|
@@ -54,36 +54,59 @@ static void IME_SetTextInputArea(SDL_VideoData *videodata, HWND hwnd, const SDL_
|
|
#define MAPVK_VSC_TO_VK 1
|
|
#define MAPVK_VSC_TO_VK 1
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-// Alphabetic scancodes for PC keyboards
|
|
|
|
-void WIN_InitKeyboard(SDL_VideoDevice *_this)
|
|
|
|
|
|
+/* Building keymaps is expensive, so keep a reasonably-sized LRU cache to
|
|
|
|
+ * enable fast switching between commonly used ones.
|
|
|
|
+ */
|
|
|
|
+static struct WIN_KeymapCache
|
|
{
|
|
{
|
|
-#ifndef SDL_DISABLE_WINDOWS_IME
|
|
|
|
- SDL_VideoData *data = _this->internal;
|
|
|
|
|
|
+ HKL keyboard_layout;
|
|
|
|
+ SDL_Keymap *keymap;
|
|
|
|
+} keymap_cache[4];
|
|
|
|
|
|
- data->ime_candlistindexbase = 1;
|
|
|
|
- data->ime_composition_length = 32 * sizeof(WCHAR);
|
|
|
|
- data->ime_composition = (WCHAR *)SDL_calloc(data->ime_composition_length, sizeof(WCHAR));
|
|
|
|
-#endif // !SDL_DISABLE_WINDOWS_IME
|
|
|
|
|
|
+static int keymap_cache_size;
|
|
|
|
|
|
- WIN_UpdateKeymap(false);
|
|
|
|
|
|
+static SDL_Keymap *WIN_GetCachedKeymap(HKL layout)
|
|
|
|
+{
|
|
|
|
+ SDL_Keymap *keymap = NULL;
|
|
|
|
+ for (int i = 0; i < keymap_cache_size; ++i) {
|
|
|
|
+ if (keymap_cache[i].keyboard_layout == layout) {
|
|
|
|
+ keymap = keymap_cache[i].keymap;
|
|
|
|
+
|
|
|
|
+ // Move the map to the front of the list.
|
|
|
|
+ if (i) {
|
|
|
|
+ SDL_memmove(keymap_cache + 1, keymap_cache, sizeof(struct WIN_KeymapCache) * i);
|
|
|
|
+ keymap_cache[0].keyboard_layout = layout;
|
|
|
|
+ keymap_cache[0].keymap = keymap;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return keymap;
|
|
|
|
+}
|
|
|
|
|
|
- SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
|
|
|
- SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
|
|
|
|
- SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows");
|
|
|
|
|
|
+static void WIN_CacheKeymap(HKL layout, SDL_Keymap *keymap)
|
|
|
|
+{
|
|
|
|
+ // If the cache is full, evict the last keymap.
|
|
|
|
+ if (keymap_cache_size == SDL_arraysize(keymap_cache)) {
|
|
|
|
+ SDL_DestroyKeymap(keymap_cache[--keymap_cache_size].keymap);
|
|
|
|
+ }
|
|
|
|
|
|
- // Are system caps/num/scroll lock active? Set our state to match.
|
|
|
|
- SDL_ToggleModState(SDL_KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) ? true : false);
|
|
|
|
- SDL_ToggleModState(SDL_KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) ? true : false);
|
|
|
|
- SDL_ToggleModState(SDL_KMOD_SCROLL, (GetKeyState(VK_SCROLL) & 0x0001) ? true : false);
|
|
|
|
|
|
+ // Move all elements down by one.
|
|
|
|
+ if (keymap_cache_size) {
|
|
|
|
+ SDL_memmove(keymap_cache + 1, keymap_cache, sizeof(struct WIN_KeymapCache) * keymap_cache_size);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ keymap_cache[0].keyboard_layout = layout;
|
|
|
|
+ keymap_cache[0].keymap = keymap;
|
|
|
|
+ ++keymap_cache_size;
|
|
}
|
|
}
|
|
|
|
|
|
-void WIN_UpdateKeymap(bool send_event)
|
|
|
|
|
|
+static SDL_Keymap *WIN_BuildKeymap()
|
|
{
|
|
{
|
|
SDL_Scancode scancode;
|
|
SDL_Scancode scancode;
|
|
- SDL_Keymap *keymap;
|
|
|
|
BYTE keyboardState[256] = { 0 };
|
|
BYTE keyboardState[256] = { 0 };
|
|
WCHAR buffer[16];
|
|
WCHAR buffer[16];
|
|
- SDL_Keymod mods[] = {
|
|
|
|
|
|
+ const SDL_Keymod mods[] = {
|
|
SDL_KMOD_NONE,
|
|
SDL_KMOD_NONE,
|
|
SDL_KMOD_SHIFT,
|
|
SDL_KMOD_SHIFT,
|
|
SDL_KMOD_CAPS,
|
|
SDL_KMOD_CAPS,
|
|
@@ -96,7 +119,10 @@ void WIN_UpdateKeymap(bool send_event)
|
|
|
|
|
|
WIN_ResetDeadKeys();
|
|
WIN_ResetDeadKeys();
|
|
|
|
|
|
- keymap = SDL_CreateKeymap(true);
|
|
|
|
|
|
+ SDL_Keymap *keymap = SDL_CreateKeymap(false);
|
|
|
|
+ if (!keymap) {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
|
|
for (int m = 0; m < SDL_arraysize(mods); ++m) {
|
|
for (int m = 0; m < SDL_arraysize(mods); ++m) {
|
|
for (int i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
|
|
for (int i = 0; i < SDL_arraysize(windows_scancode_table); i++) {
|
|
@@ -160,9 +186,47 @@ void WIN_UpdateKeymap(bool send_event)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return keymap;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void WIN_UpdateKeymap(bool send_event)
|
|
|
|
+{
|
|
|
|
+ HKL layout = GetKeyboardLayout(0);
|
|
|
|
+ SDL_Keymap *keymap = WIN_GetCachedKeymap(layout);
|
|
|
|
+ if (!keymap) {
|
|
|
|
+ keymap = WIN_BuildKeymap();
|
|
|
|
+ if (keymap) {
|
|
|
|
+ WIN_CacheKeymap(layout, keymap);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
SDL_SetKeymap(keymap, send_event);
|
|
SDL_SetKeymap(keymap, send_event);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Alphabetic scancodes for PC keyboards
|
|
|
|
+void WIN_InitKeyboard(SDL_VideoDevice *_this)
|
|
|
|
+{
|
|
|
|
+#ifndef SDL_DISABLE_WINDOWS_IME
|
|
|
|
+ SDL_VideoData *data = _this->internal;
|
|
|
|
+
|
|
|
|
+ data->ime_candlistindexbase = 1;
|
|
|
|
+ data->ime_composition_length = 32 * sizeof(WCHAR);
|
|
|
|
+ data->ime_composition = (WCHAR *)SDL_calloc(data->ime_composition_length, sizeof(WCHAR));
|
|
|
|
+#endif // !SDL_DISABLE_WINDOWS_IME
|
|
|
|
+
|
|
|
|
+ // Build and bind the current keymap.
|
|
|
|
+ WIN_UpdateKeymap(false);
|
|
|
|
+
|
|
|
|
+ SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
|
|
|
+ SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
|
|
|
|
+ SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows");
|
|
|
|
+
|
|
|
|
+ // Are system caps/num/scroll lock active? Set our state to match.
|
|
|
|
+ SDL_ToggleModState(SDL_KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) ? true : false);
|
|
|
|
+ SDL_ToggleModState(SDL_KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) ? true : false);
|
|
|
|
+ SDL_ToggleModState(SDL_KMOD_SCROLL, (GetKeyState(VK_SCROLL) & 0x0001) ? true : false);
|
|
|
|
+}
|
|
|
|
+
|
|
void WIN_QuitKeyboard(SDL_VideoDevice *_this)
|
|
void WIN_QuitKeyboard(SDL_VideoDevice *_this)
|
|
{
|
|
{
|
|
#ifndef SDL_DISABLE_WINDOWS_IME
|
|
#ifndef SDL_DISABLE_WINDOWS_IME
|
|
@@ -175,6 +239,13 @@ void WIN_QuitKeyboard(SDL_VideoDevice *_this)
|
|
data->ime_composition = NULL;
|
|
data->ime_composition = NULL;
|
|
}
|
|
}
|
|
#endif // !SDL_DISABLE_WINDOWS_IME
|
|
#endif // !SDL_DISABLE_WINDOWS_IME
|
|
|
|
+
|
|
|
|
+ SDL_SetKeymap(NULL, false);
|
|
|
|
+ for (int i = 0; i < keymap_cache_size; ++i) {
|
|
|
|
+ SDL_DestroyKeymap(keymap_cache[i].keymap);
|
|
|
|
+ }
|
|
|
|
+ SDL_memset(keymap_cache, 0, sizeof(keymap_cache));
|
|
|
|
+ keymap_cache_size = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void WIN_ResetDeadKeys(void)
|
|
void WIN_ResetDeadKeys(void)
|