diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 454de5c..a3b5ad0 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -44,6 +44,8 @@ struct _MwLLWaylandTopLevel { struct xdg_surface_listener xdg_surface_listener; struct xkb_context* xkb_context; + struct xkb_keymap* xkb_keymap; + struct xkb_state* xkb_state; MwBool compositor_created; MwBool xdg_wm_base_created; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 14cd116..ee2770f 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -16,13 +16,12 @@ #else #include #endif + /* - callback todo: - void (*key)(MwLL handle, void* data); - void (*key_released)(MwLL handle, void* data); - void (*focus_in)(MwLL handle, void* data); - void (*focus_out)(MwLL handle, void* data); -*/ + * GENERAL TODO: + * comment the file lmao + * make sure MwLLDestroy is finished (+ handle dropdown bug that results from it) + */ static void timed_redraw(MwLL handle, MwU32 time, int cooldown, MwU64* cooldown_timer); @@ -50,9 +49,11 @@ static void protocol_removed(void* data, static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y) {}; + wl_fixed_t surface_y) { +}; static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface) {}; + struct wl_surface* surface) { +}; static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { MwLL self = data; @@ -103,6 +104,102 @@ struct wl_pointer_listener pointer_listener = { .axis = pointer_axis, }; +static void keyboard_keymap(void* data, + struct wl_keyboard* wl_keyboard, + uint32_t format, + int32_t fd, + uint32_t size) { + MwLL self = data; + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + + char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + assert(map_shm != MAP_FAILED); + + struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string( + wayland->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm, size); + close(fd); + + struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); + xkb_keymap_unref(wayland->xkb_keymap); + xkb_state_unref(wayland->xkb_state); + + wayland->xkb_keymap = xkb_keymap; + wayland->xkb_state = xkb_state; + } +}; +static void keyboard_enter(void* data, + struct wl_keyboard* wl_keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) { + MwLL self = data; + MwLLDispatch(self, focus_in, NULL); +}; +static void keyboard_leave(void* data, + struct wl_keyboard* wl_keyboard, + uint32_t serial, + struct wl_surface* surface) { + MwLL self = data; + MwLLDispatch(self, focus_out, NULL); +}; +static void keyboard_key(void* data, + struct wl_keyboard* wl_keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) { + MwLL self = data; + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; + xkb_layout_index_t layout; + xkb_level_index_t level; + const xkb_keysym_t* syms_out; + MwU32 keycode = key + 8; + MwU64 syms_num; + int i; + + if(!wayland->xkb_keymap) { + return; + } + + layout = xkb_state_key_get_layout(wayland->xkb_state, keycode); + level = + xkb_keymap_num_levels_for_key(wayland->xkb_keymap, keycode, layout) - 1; + syms_num = xkb_keymap_key_get_syms_by_level(wayland->xkb_keymap, keycode, layout, level, &syms_out); + if(syms_out == NULL) { + return; + } + + for(i = 0; i < syms_num; i++) { + int sym = syms_out[i]; + if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { + MwLLDispatch(self, key, &sym); + } else { + MwLLDispatch(self, key_released, &sym); + } + } + } +}; +static void keyboard_modifiers(void* data, + struct wl_keyboard* wl_keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) {}; + +struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, +}; + static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, @@ -110,7 +207,7 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwLL self = data; if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { struct wl_keyboard* keyboard = wl_seat_get_keyboard(wl_seat); - // wl_keyboard_add_listener(keyboard, const struct wl_keyboard_listener* listener, data); + wl_keyboard_add_listener(keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER && !self->wayland.pointer) { self->wayland.pointer = wl_seat_get_pointer(wl_seat); @@ -490,16 +587,6 @@ static void setup_toplevel(MwLL r, int x, int y) { return; } - // Check that all globals we require are available - if( - r->wayland.compositor == NULL || - WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context == NULL) { - - printf("no xdg_wm_base support\n"); - raise(SIGTRAP); - return; - } - r->wayland.toplevel->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); // Create a wl_surface, a xdg_surface and a xdg_toplevel