소스 검색

wayland: Optimize keymap creation

Iterate over the list of keys only once while assembling all related state for key levels and modifiers.
Frank Praznik 2 주 전
부모
커밋
9b00f3a728
2개의 변경된 파일60개의 추가작업 그리고 78개의 파일을 삭제
  1. 52 77
      src/video/wayland/SDL_waylandevents.c
  2. 8 1
      src/video/wayland/SDL_waylandsym.h

+ 52 - 77
src/video/wayland/SDL_waylandevents.c

@@ -1410,103 +1410,78 @@ static const struct wl_touch_listener touch_listener = {
     touch_handler_orientation // Version 6
 };
 
-typedef struct Wayland_KeymapBuilderState
-{
-    SDL_Keymap *keymap;
-    struct xkb_state *state;
-    SDL_Keymod modstate;
-} Wayland_KeymapBuilderState;
-
 static void Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
 {
-    Wayland_KeymapBuilderState *sdlKeymap = (Wayland_KeymapBuilderState *)data;
+    SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
     const xkb_keysym_t *syms;
+    const xkb_mod_mask_t xkb_valid_mod_mask = seat->keyboard.xkb.shift_mask |
+                                              seat->keyboard.xkb.alt_mask |
+                                              seat->keyboard.xkb.gui_mask |
+                                              seat->keyboard.xkb.level3_mask |
+                                              seat->keyboard.xkb.level5_mask |
+                                              seat->keyboard.xkb.caps_mask;
     const SDL_Scancode scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_XFREE86_2, (key - 8));
     if (scancode == SDL_SCANCODE_UNKNOWN) {
         return;
     }
 
-    if (WAYLAND_xkb_state_key_get_syms(sdlKeymap->state, key, &syms) > 0) {
-        SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(syms[0], key, sdlKeymap->modstate);
+    const xkb_level_index_t num_levels = WAYLAND_xkb_keymap_num_levels_for_key(seat->keyboard.xkb.keymap, key, seat->keyboard.xkb.current_layout);
+    for (xkb_level_index_t level = 0; level < num_levels; ++level) {
+        if (WAYLAND_xkb_keymap_key_get_syms_by_level(seat->keyboard.xkb.keymap, key, seat->keyboard.xkb.current_layout, level, &syms) > 0) {
+            xkb_mod_mask_t xkb_mod_masks[16];
+            const size_t num_masks = WAYLAND_xkb_keymap_key_get_mods_for_level(seat->keyboard.xkb.keymap, key, seat->keyboard.xkb.current_layout, level, xkb_mod_masks, SDL_arraysize(xkb_mod_masks));
+            for (size_t mask = 0; mask < num_masks; ++mask) {
+                // Ignore this modifier set if it uses unsupported modifier types.
+                if ((xkb_mod_masks[mask] | xkb_valid_mod_mask) != xkb_valid_mod_mask) {
+                    continue;
+                }
 
-        if (!keycode) {
-            switch (scancode) {
-            case SDL_SCANCODE_RETURN:
-                keycode = SDLK_RETURN;
-                break;
-            case SDL_SCANCODE_ESCAPE:
-                keycode = SDLK_ESCAPE;
-                break;
-            case SDL_SCANCODE_BACKSPACE:
-                keycode = SDLK_BACKSPACE;
-                break;
-            case SDL_SCANCODE_DELETE:
-                keycode = SDLK_DELETE;
-                break;
-            default:
-                keycode = SDL_SCANCODE_TO_KEYCODE(scancode);
-                break;
+                const SDL_Keymod sdl_mod = (xkb_mod_masks[mask] & seat->keyboard.xkb.shift_mask ? SDL_KMOD_SHIFT : 0) |
+                                           (xkb_mod_masks[mask] & seat->keyboard.xkb.alt_mask ? SDL_KMOD_ALT : 0) |
+                                           (xkb_mod_masks[mask] & seat->keyboard.xkb.gui_mask ? SDL_KMOD_GUI : 0) |
+                                           (xkb_mod_masks[mask] & seat->keyboard.xkb.level3_mask ? SDL_KMOD_MODE : 0) |
+                                           (xkb_mod_masks[mask] & seat->keyboard.xkb.level5_mask ? SDL_KMOD_LEVEL5 : 0) |
+                                           (xkb_mod_masks[mask] & seat->keyboard.xkb.caps_mask ? SDL_KMOD_CAPS : 0);
+
+                SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(syms[0], key, sdl_mod);
+
+                if (!keycode) {
+                    switch (scancode) {
+                    case SDL_SCANCODE_RETURN:
+                        keycode = SDLK_RETURN;
+                        break;
+                    case SDL_SCANCODE_ESCAPE:
+                        keycode = SDLK_ESCAPE;
+                        break;
+                    case SDL_SCANCODE_BACKSPACE:
+                        keycode = SDLK_BACKSPACE;
+                        break;
+                    case SDL_SCANCODE_DELETE:
+                        keycode = SDLK_DELETE;
+                        break;
+                    default:
+                        keycode = SDL_SCANCODE_TO_KEYCODE(scancode);
+                        break;
+                    }
+                }
+
+                SDL_SetKeymapEntry(seat->keyboard.sdl_keymap, scancode, sdl_mod, keycode);
             }
         }
-
-        SDL_SetKeymapEntry(sdlKeymap->keymap, scancode, sdlKeymap->modstate, keycode);
     }
 }
 
 static void Wayland_UpdateKeymap(SDL_WaylandSeat *seat)
 {
-    struct Keymod_masks
-    {
-        SDL_Keymod sdl_mask;
-        xkb_mod_mask_t xkb_mask;
-    } const keymod_masks[] = {
-        { SDL_KMOD_NONE, 0 },
-        { SDL_KMOD_SHIFT, seat->keyboard.xkb.shift_mask },
-        { SDL_KMOD_CAPS, seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.shift_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_MODE, seat->keyboard.xkb.level3_mask },
-        { SDL_KMOD_MODE | SDL_KMOD_SHIFT, seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.shift_mask },
-        { SDL_KMOD_MODE | SDL_KMOD_CAPS, seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.shift_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_LEVEL5, seat->keyboard.xkb.level5_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.shift_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.shift_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.level3_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.shift_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.caps_mask },
-        { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.level5_mask | seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.shift_mask | seat->keyboard.xkb.caps_mask },
-    };
-
     if (!seat->keyboard.is_virtual) {
-        Wayland_KeymapBuilderState keymap;
-
-        keymap.keymap = SDL_CreateKeymap(false);
-        if (!keymap.keymap) {
-            return;
-        }
-
-        keymap.state = WAYLAND_xkb_state_new(seat->keyboard.xkb.keymap);
-        if (!keymap.state) {
-            SDL_SetError("failed to create XKB state");
-            SDL_DestroyKeymap(keymap.keymap);
+        SDL_DestroyKeymap(seat->keyboard.sdl_keymap);
+        seat->keyboard.sdl_keymap = SDL_CreateKeymap(false);
+        if (!seat->keyboard.sdl_keymap) {
             return;
         }
 
-        for (int i = 0; i < SDL_arraysize(keymod_masks); ++i) {
-            keymap.modstate = keymod_masks[i].sdl_mask;
-            WAYLAND_xkb_state_update_mask(keymap.state,
-                                          keymod_masks[i].xkb_mask & (seat->keyboard.xkb.shift_mask | seat->keyboard.xkb.level3_mask | seat->keyboard.xkb.level5_mask), 0, keymod_masks[i].xkb_mask & seat->keyboard.xkb.caps_mask,
-                                          0, 0, seat->keyboard.xkb.current_layout);
-            WAYLAND_xkb_keymap_key_for_each(seat->keyboard.xkb.keymap,
-                                            Wayland_keymap_iter,
-                                            &keymap);
-        }
-
-        WAYLAND_xkb_state_unref(keymap.state);
-        SDL_SetKeymap(keymap.keymap, true);
-        SDL_DestroyKeymap(seat->keyboard.sdl_keymap);
-        seat->keyboard.sdl_keymap = keymap.keymap;
+        WAYLAND_xkb_keymap_key_for_each(seat->keyboard.xkb.keymap, Wayland_keymap_iter, seat);
+        SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
     } else {
         // Virtual keyboards use the default keymap.
         SDL_SetKeymap(NULL, true);

+ 8 - 1
src/video/wayland/SDL_waylandsym.h

@@ -153,8 +153,15 @@ SDL_WAYLAND_SYM(void, xkb_keymap_key_for_each, (struct xkb_keymap *, xkb_keymap_
 SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
                                                         xkb_keycode_t,
                                                         xkb_layout_index_t,
-                                                        xkb_layout_index_t,
+                                                        xkb_level_index_t,
                                                         const xkb_keysym_t **) )
+SDL_WAYLAND_SYM(xkb_level_index_t, xkb_keymap_num_levels_for_key, (struct xkb_keymap *, xkb_keycode_t, xkb_layout_index_t) )
+SDL_WAYLAND_SYM(size_t, xkb_keymap_key_get_mods_for_level, (struct xkb_keymap *,
+                                                            xkb_keycode_t,
+                                                            xkb_layout_index_t,
+                                                            xkb_level_index_t,
+                                                            xkb_mod_mask_t *,
+                                                            size_t masks_size) )
 SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
 SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *,
                                                       const char *) )