@@ -54,36 +54,59 @@ static void IME_SetTextInputArea(SDL_VideoData *videodata, HWND hwnd, const SDL_
54
54
#define MAPVK_VSC_TO_VK 1
55
55
#endif
56
56
57
- // Alphabetic scancodes for PC keyboards
58
- void WIN_InitKeyboard (SDL_VideoDevice * _this )
57
+ /* Building keymaps is expensive, so keep a reasonably-sized LRU cache to
58
+ * enable fast switching between commonly used ones.
59
+ */
60
+ static struct WIN_KeymapCache
59
61
{
60
- #ifndef SDL_DISABLE_WINDOWS_IME
61
- SDL_VideoData * data = _this -> internal ;
62
+ HKL keyboard_layout ;
63
+ SDL_Keymap * keymap ;
64
+ } keymap_cache [4 ];
62
65
63
- data -> ime_candlistindexbase = 1 ;
64
- data -> ime_composition_length = 32 * sizeof (WCHAR );
65
- data -> ime_composition = (WCHAR * )SDL_calloc (data -> ime_composition_length , sizeof (WCHAR ));
66
- #endif // !SDL_DISABLE_WINDOWS_IME
66
+ static int keymap_cache_size ;
67
67
68
- WIN_UpdateKeymap (false);
68
+ static SDL_Keymap * WIN_GetCachedKeymap (HKL layout )
69
+ {
70
+ SDL_Keymap * keymap = NULL ;
71
+ for (int i = 0 ; i < keymap_cache_size ; ++ i ) {
72
+ if (keymap_cache [i ].keyboard_layout == layout ) {
73
+ keymap = keymap_cache [i ].keymap ;
74
+
75
+ // Move the map to the front of the list.
76
+ if (i ) {
77
+ SDL_memmove (keymap_cache + 1 , keymap_cache , sizeof (struct WIN_KeymapCache ) * i );
78
+ keymap_cache [0 ].keyboard_layout = layout ;
79
+ keymap_cache [0 ].keymap = keymap ;
80
+ }
81
+ break ;
82
+ }
83
+ }
84
+ return keymap ;
85
+ }
69
86
70
- SDL_SetScancodeName (SDL_SCANCODE_APPLICATION , "Menu" );
71
- SDL_SetScancodeName (SDL_SCANCODE_LGUI , "Left Windows" );
72
- SDL_SetScancodeName (SDL_SCANCODE_RGUI , "Right Windows" );
87
+ static void WIN_CacheKeymap (HKL layout , SDL_Keymap * keymap )
88
+ {
89
+ // If the cache is full, evict the last keymap.
90
+ if (keymap_cache_size == SDL_arraysize (keymap_cache )) {
91
+ SDL_DestroyKeymap (keymap_cache [-- keymap_cache_size ].keymap );
92
+ }
73
93
74
- // Are system caps/num/scroll lock active? Set our state to match.
75
- SDL_ToggleModState (SDL_KMOD_CAPS , (GetKeyState (VK_CAPITAL ) & 0x0001 ) ? true : false);
76
- SDL_ToggleModState (SDL_KMOD_NUM , (GetKeyState (VK_NUMLOCK ) & 0x0001 ) ? true : false);
77
- SDL_ToggleModState (SDL_KMOD_SCROLL , (GetKeyState (VK_SCROLL ) & 0x0001 ) ? true : false);
94
+ // Move all elements down by one.
95
+ if (keymap_cache_size ) {
96
+ SDL_memmove (keymap_cache + 1 , keymap_cache , sizeof (struct WIN_KeymapCache ) * keymap_cache_size );
97
+ }
98
+
99
+ keymap_cache [0 ].keyboard_layout = layout ;
100
+ keymap_cache [0 ].keymap = keymap ;
101
+ ++ keymap_cache_size ;
78
102
}
79
103
80
- void WIN_UpdateKeymap ( bool send_event )
104
+ static SDL_Keymap * WIN_BuildKeymap ( )
81
105
{
82
106
SDL_Scancode scancode ;
83
- SDL_Keymap * keymap ;
84
107
BYTE keyboardState [256 ] = { 0 };
85
108
WCHAR buffer [16 ];
86
- SDL_Keymod mods [] = {
109
+ const SDL_Keymod mods [] = {
87
110
SDL_KMOD_NONE ,
88
111
SDL_KMOD_SHIFT ,
89
112
SDL_KMOD_CAPS ,
@@ -96,7 +119,10 @@ void WIN_UpdateKeymap(bool send_event)
96
119
97
120
WIN_ResetDeadKeys ();
98
121
99
- keymap = SDL_CreateKeymap (true);
122
+ SDL_Keymap * keymap = SDL_CreateKeymap (false);
123
+ if (!keymap ) {
124
+ return NULL ;
125
+ }
100
126
101
127
for (int m = 0 ; m < SDL_arraysize (mods ); ++ m ) {
102
128
for (int i = 0 ; i < SDL_arraysize (windows_scancode_table ); i ++ ) {
@@ -160,9 +186,47 @@ void WIN_UpdateKeymap(bool send_event)
160
186
}
161
187
}
162
188
189
+ return keymap ;
190
+ }
191
+
192
+ void WIN_UpdateKeymap (bool send_event )
193
+ {
194
+ HKL layout = GetKeyboardLayout (0 );
195
+ SDL_Keymap * keymap = WIN_GetCachedKeymap (layout );
196
+ if (!keymap ) {
197
+ keymap = WIN_BuildKeymap ();
198
+ if (keymap ) {
199
+ WIN_CacheKeymap (layout , keymap );
200
+ }
201
+ }
202
+
163
203
SDL_SetKeymap (keymap , send_event );
164
204
}
165
205
206
+ // Alphabetic scancodes for PC keyboards
207
+ void WIN_InitKeyboard (SDL_VideoDevice * _this )
208
+ {
209
+ #ifndef SDL_DISABLE_WINDOWS_IME
210
+ SDL_VideoData * data = _this -> internal ;
211
+
212
+ data -> ime_candlistindexbase = 1 ;
213
+ data -> ime_composition_length = 32 * sizeof (WCHAR );
214
+ data -> ime_composition = (WCHAR * )SDL_calloc (data -> ime_composition_length , sizeof (WCHAR ));
215
+ #endif // !SDL_DISABLE_WINDOWS_IME
216
+
217
+ // Build and bind the current keymap.
218
+ WIN_UpdateKeymap (false);
219
+
220
+ SDL_SetScancodeName (SDL_SCANCODE_APPLICATION , "Menu" );
221
+ SDL_SetScancodeName (SDL_SCANCODE_LGUI , "Left Windows" );
222
+ SDL_SetScancodeName (SDL_SCANCODE_RGUI , "Right Windows" );
223
+
224
+ // Are system caps/num/scroll lock active? Set our state to match.
225
+ SDL_ToggleModState (SDL_KMOD_CAPS , (GetKeyState (VK_CAPITAL ) & 0x0001 ) ? true : false);
226
+ SDL_ToggleModState (SDL_KMOD_NUM , (GetKeyState (VK_NUMLOCK ) & 0x0001 ) ? true : false);
227
+ SDL_ToggleModState (SDL_KMOD_SCROLL , (GetKeyState (VK_SCROLL ) & 0x0001 ) ? true : false);
228
+ }
229
+
166
230
void WIN_QuitKeyboard (SDL_VideoDevice * _this )
167
231
{
168
232
#ifndef SDL_DISABLE_WINDOWS_IME
@@ -175,6 +239,13 @@ void WIN_QuitKeyboard(SDL_VideoDevice *_this)
175
239
data -> ime_composition = NULL ;
176
240
}
177
241
#endif // !SDL_DISABLE_WINDOWS_IME
242
+
243
+ SDL_SetKeymap (NULL , false);
244
+ for (int i = 0 ; i < keymap_cache_size ; ++ i ) {
245
+ SDL_DestroyKeymap (keymap_cache [i ].keymap );
246
+ }
247
+ SDL_memset (keymap_cache , 0 , sizeof (keymap_cache ));
248
+ keymap_cache_size = 0 ;
178
249
}
179
250
180
251
void WIN_ResetDeadKeys (void )
0 commit comments