QLibInputKeyboard::QLibInputKeyboard() #ifndef QT_NO_XKBCOMMON_EVDEV : m_ctx(0), m_keymap(0), m_state(0) #endif { #ifndef QT_NO_XKBCOMMON_EVDEV qCDebug(qLcLibInput) << "Using xkbcommon for key mapping"; m_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!m_ctx) { qWarning("Failed to create xkb context"); return; } m_keymap = xkb_keymap_new_from_names(m_ctx, Q_NULLPTR, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!m_keymap) { qWarning("Failed to compile keymap"); return; } m_state = xkb_state_new(m_keymap); if (!m_state) { qWarning("Failed to create xkb state"); return; } m_modindex[0] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL); m_modindex[1] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT); m_modindex[2] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_SHIFT); m_modindex[3] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO); m_repeatTimer.setSingleShot(true); connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat); #else qCWarning(qLcLibInput) << "X-less xkbcommon not available, not performing key mapping"; #endif }
static void keyboardHandleKeymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int fd, uint32_t size) { struct xkb_keymap* keymap; struct xkb_state* state; char* mapStr; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (mapStr == MAP_FAILED) { close(fd); return; } keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, mapStr, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(mapStr, size); close(fd); if (!keymap) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to compile keymap"); return; } state = xkb_state_new(keymap); if (!state) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB state"); xkb_keymap_unref(keymap); return; } xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); _glfw.wl.xkb.keymap = keymap; _glfw.wl.xkb.state = state; _glfw.wl.xkb.controlMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); _glfw.wl.xkb.altMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); _glfw.wl.xkb.shiftMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); _glfw.wl.xkb.superMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); }
static void test_serialisation(struct xkb_keymap *keymap) { struct xkb_state *state = xkb_state_new(keymap); xkb_mod_mask_t base_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t effective_mods; xkb_mod_index_t caps, shift, ctrl; xkb_layout_index_t base_group = 0; xkb_layout_index_t latched_group = 0; xkb_layout_index_t locked_group = 0; assert(state); caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); assert(caps != XKB_MOD_INVALID); shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); assert(shift != XKB_MOD_INVALID); ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); assert(ctrl != XKB_MOD_INVALID); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED); assert(base_mods == 0); latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); assert(latched_mods == 0); locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); assert(locked_mods == (1U << caps)); effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); assert(effective_mods == locked_mods); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED); assert(base_mods == (1U << shift)); latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); assert(latched_mods == 0); locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); assert(locked_mods == (1U << caps)); effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); assert(effective_mods == (base_mods | locked_mods)); base_mods |= (1U << ctrl); xkb_state_update_mask(state, base_mods, latched_mods, locked_mods, base_group, latched_group, locked_group); assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0); xkb_state_unref(state); }
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { UwacSeat *input = data; struct xkb_keymap *keymap; struct xkb_state *state; char *map_str; if (!data) { close(fd); return; } if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) { close(fd); return; } keymap = xkb_keymap_new_from_string(input->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); if (!keymap) { assert(uwacErrorHandler(input->display, UWAC_ERROR_INTERNAL, "failed to compile keymap\n")); return; } state = xkb_state_new(keymap); if (!state) { assert(uwacErrorHandler(input->display, UWAC_ERROR_NOMEMORY, "failed to create XKB state\n")); xkb_keymap_unref(keymap); return; } xkb_keymap_unref(input->xkb.keymap); xkb_state_unref(input->xkb.state); input->xkb.keymap = keymap; input->xkb.state = state; input->xkb.control_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Control"); input->xkb.alt_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Mod1"); input->xkb.shift_mask = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Shift"); }
static void input_method_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { struct simple_im *keyboard = data; char *map_str; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) { close(fd); return; } keyboard->keymap = xkb_keymap_new_from_string(keyboard->xkb_context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); if (!keyboard->keymap) { fprintf(stderr, "failed to compile keymap\n"); return; } keyboard->state = xkb_state_new(keyboard->keymap); if (!keyboard->state) { fprintf(stderr, "failed to create XKB state\n"); xkb_keymap_unref(keyboard->keymap); return; } keyboard->control_mask = 1 << xkb_keymap_mod_get_index(keyboard->keymap, "Control"); keyboard->alt_mask = 1 << xkb_keymap_mod_get_index(keyboard->keymap, "Mod1"); keyboard->shift_mask = 1 << xkb_keymap_mod_get_index(keyboard->keymap, "Shift"); }
static int kbdmap_new_from_names(kbdmap **out, kbdctx *kc, const char *model, const char *layout, const char *variant, const char *options) { _cleanup_(kbdmap_unrefp) kbdmap *km = NULL; struct xkb_rule_names rmlvo = { }; unsigned int i; assert_return(out, -EINVAL); km = new0(kbdmap, 1); if (!km) return -ENOMEM; km->ref = 1; rmlvo.rules = "evdev"; rmlvo.model = model; rmlvo.layout = layout; rmlvo.variant = variant; rmlvo.options = options; errno = 0; km->xkb_keymap = xkb_keymap_new_from_names(kc->xkb_context, &rmlvo, 0); if (!km->xkb_keymap) return errno > 0 ? -errno : -EFAULT; for (i = 0; i < IDEV_KBDMOD_CNT; ++i) { const char *t = kbdmap_modmap[i]; if (t) km->modmap[i] = xkb_keymap_mod_get_index(km->xkb_keymap, t); else km->modmap[i] = XKB_MOD_INVALID; } for (i = 0; i < IDEV_KBDLED_CNT; ++i) { const char *t = kbdmap_ledmap[i]; if (t) km->ledmap[i] = xkb_keymap_led_get_index(km->xkb_keymap, t); else km->ledmap[i] = XKB_LED_INVALID; } *out = km; km = NULL; return 0; }
static unsigned int x11_find_mod_mask ( xkb_stuff *xkb, ... ) { va_list names; const char *name; xkb_mod_index_t i; unsigned int mask = 0; va_start ( names, xkb ); while ( ( name = va_arg ( names, const char * ) ) != NULL ) { i = xkb_keymap_mod_get_index ( xkb->keymap, name ); if ( i != XKB_MOD_INVALID ) { mask |= 1 << i; } } va_end ( names ); return mask; }
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { // Keyboard errors are abort-worthy because you wouldn't be able to unlock your screen otherwise. struct registry *registry = data; if (!data) { close(fd); return; } if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); sway_abort("Unknown keymap format %d, aborting", format); } char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) { close(fd); sway_abort("Unable to initialized shared keyboard memory, aborting"); } struct xkb_keymap *keymap = xkb_keymap_new_from_string(registry->input->xkb.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); if (!keymap) { sway_abort("Failed to compile keymap, aborting"); } struct xkb_state *state = xkb_state_new(keymap); if (!state) { xkb_keymap_unref(keymap); sway_abort("Failed to create xkb state, aborting"); } xkb_keymap_unref(registry->input->xkb.keymap); xkb_state_unref(registry->input->xkb.state); registry->input->xkb.keymap = keymap; registry->input->xkb.state = state; int i; for (i = 0; i < MASK_LAST; ++i) { registry->input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(registry->input->xkb.keymap, XKB_MASK_NAMES[i]); } }
static void test_ctrl_string_transformation(struct xkb_keymap *keymap) { char buf[256]; struct xkb_state *state = xkb_state_new(keymap); xkb_mod_index_t ctrl; assert(state); /* See xkb_state_key_get_utf8() for what's this all about. */ ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); assert(ctrl != XKB_MOD_INVALID); /* First without. */ TEST_KEY(KEY_A, "a", 0x61); TEST_KEY(KEY_B, "b", 0x62); TEST_KEY(KEY_C, "c", 0x63); TEST_KEY(KEY_ESC, "\x1B", 0x1B); TEST_KEY(KEY_1, "1", 0x31); /* And with. */ xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN); assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0); TEST_KEY(KEY_A, "\x01", 0x01); TEST_KEY(KEY_B, "\x02", 0x02); TEST_KEY(KEY_C, "\x03", 0x03); TEST_KEY(KEY_ESC, "\x1B", 0x1B); TEST_KEY(KEY_1, "1", 0x31); xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_UP); /* Switch to ru layout */ xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_key_get_layout(state, KEY_A + 8) == 1); /* Non ASCII. */ xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN); assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0); TEST_KEY(KEY_A, "\x01", 0x01); TEST_KEY(KEY_B, "\x02", 0x02); xkb_state_update_key(state, KEY_RIGHTCTRL + EVDEV_OFFSET, XKB_KEY_UP); xkb_state_unref(state); }
static void *udev_input_init(void) { settings_t *settings = config_get_ptr(); udev_input_t *udev = (udev_input_t*)calloc(1, sizeof(*udev)); if (!udev) return NULL; udev->udev = udev_new(); if (!udev->udev) { RARCH_ERR("Failed to create udev handle.\n"); goto error; } udev->monitor = udev_monitor_new_from_netlink(udev->udev, "udev"); if (udev->monitor) { udev_monitor_filter_add_match_subsystem_devtype(udev->monitor, "input", NULL); udev_monitor_enable_receiving(udev->monitor); } #ifdef HAVE_XKBCOMMON udev->mod_map_idx = (xkb_mod_index_t *)calloc(MOD_MAP_SIZE, sizeof(xkb_mod_index_t)); if (!udev->mod_map_idx) goto error; udev->mod_map_bit = (uint16_t*)calloc(MOD_MAP_SIZE, sizeof(uint16_t)); if (!udev->mod_map_bit) goto error; udev->xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (udev->xkb_ctx) { struct string_list *list = NULL; struct xkb_rule_names rule = {0}; rule.rules = "evdev"; if (*settings->input.keyboard_layout) { list = string_split(settings->input.keyboard_layout, ":"); if (list && list->size >= 2) rule.variant = list->elems[1].data; if (list && list->size >= 1) rule.layout = list->elems[0].data; } udev->xkb_map = xkb_keymap_new_from_names(udev->xkb_ctx, &rule, XKB_MAP_COMPILE_NO_FLAGS); if (list) string_list_free(list); } if (udev->xkb_map) { xkb_mod_index_t *map_idx = (xkb_mod_index_t*)&udev->mod_map_idx[0]; uint16_t *map_bit = (uint16_t*)&udev->mod_map_bit[0]; udev->xkb_state = xkb_state_new(udev->xkb_map); *map_idx = xkb_keymap_mod_get_index(udev->xkb_map, XKB_MOD_NAME_CAPS); map_idx++; *map_bit = RETROKMOD_CAPSLOCK; map_bit++; *map_idx = xkb_keymap_mod_get_index(udev->xkb_map, XKB_MOD_NAME_SHIFT); map_idx++; *map_bit = RETROKMOD_SHIFT; map_bit++; *map_idx = xkb_keymap_mod_get_index(udev->xkb_map, XKB_MOD_NAME_CTRL); map_idx++; *map_bit = RETROKMOD_CTRL; map_bit++; *map_idx = xkb_keymap_mod_get_index(udev->xkb_map, XKB_MOD_NAME_ALT); map_idx++; *map_bit = RETROKMOD_ALT; map_bit++; *map_idx = xkb_keymap_mod_get_index(udev->xkb_map, XKB_MOD_NAME_LOGO); *map_bit = RETROKMOD_META; } #endif udev->epfd = epoll_create(32); if (udev->epfd < 0) { RARCH_ERR("Failed to create epoll FD.\n"); goto error; } if (!open_devices(udev, "ID_INPUT_KEYBOARD", udev_handle_keyboard)) { RARCH_ERR("Failed to open keyboard.\n"); goto error; } if (!open_devices(udev, "ID_INPUT_MOUSE", udev_handle_mouse)) { RARCH_ERR("Failed to open mouse.\n"); goto error; } if (!open_devices(udev, "ID_INPUT_TOUCHPAD", udev_handle_touchpad)) { RARCH_ERR("Failed to open touchpads.\n"); goto error; } /* If using KMS and we forgot this, * we could lock ourselves out completely. */ if (!udev->num_devices) RARCH_WARN("[udev]: Couldn't open any keyboard, mouse or touchpad. Are permissions set correctly for /dev/input/event*?\n"); udev->joypad = input_joypad_init_driver(settings->input.joypad_driver, udev); input_keymaps_init_keyboard_lut(rarch_key_map_linux); disable_terminal_input(); return udev; error: udev_input_free(udev); return NULL; }
static void keyboardHandleKeymap(void* data, struct wl_keyboard* keyboard, uint32_t format, int fd, uint32_t size) { struct xkb_keymap* keymap; struct xkb_state* state; #ifdef HAVE_XKBCOMMON_COMPOSE_H struct xkb_compose_table* composeTable; struct xkb_compose_state* composeState; #endif char* mapStr; const char* locale; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (mapStr == MAP_FAILED) { close(fd); return; } keymap = xkb_keymap_new_from_string(_glfw.wl.xkb.context, mapStr, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(mapStr, size); close(fd); if (!keymap) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to compile keymap"); return; } state = xkb_state_new(keymap); if (!state) { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB state"); xkb_keymap_unref(keymap); return; } // Look up the preferred locale, falling back to "C" as default. locale = getenv("LC_ALL"); if (!locale) locale = getenv("LC_CTYPE"); if (!locale) locale = getenv("LANG"); if (!locale) locale = "C"; #ifdef HAVE_XKBCOMMON_COMPOSE_H composeTable = xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); if (composeTable) { composeState = xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS); xkb_compose_table_unref(composeTable); if (composeState) _glfw.wl.xkb.composeState = composeState; else _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB compose state"); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Failed to create XKB compose table"); } #endif xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_state_unref(_glfw.wl.xkb.state); _glfw.wl.xkb.keymap = keymap; _glfw.wl.xkb.state = state; _glfw.wl.xkb.controlMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Control"); _glfw.wl.xkb.altMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); _glfw.wl.xkb.shiftMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); _glfw.wl.xkb.superMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); _glfw.wl.xkb.capsLockMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); _glfw.wl.xkb.numLockMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); }
namespace ViewBackend { class EventSource { public: static GSourceFuncs sourceFuncs; GSource source; GPollFD pfd; struct wl_display* display; }; GSourceFuncs EventSource::sourceFuncs = { // prepare [](GSource* base, gint* timeout) -> gboolean { auto* source = reinterpret_cast<EventSource*>(base); struct wl_display* display = source->display; *timeout = -1; wl_display_flush(display); wl_display_dispatch_pending(display); return FALSE; }, // check [](GSource* base) -> gboolean { auto* source = reinterpret_cast<EventSource*>(base); return !!source->pfd.revents; }, // dispatch [](GSource* base, GSourceFunc, gpointer) -> gboolean { auto* source = reinterpret_cast<EventSource*>(base); struct wl_display* display = source->display; if (source->pfd.revents & G_IO_IN) wl_display_dispatch(display); if (source->pfd.revents & (G_IO_ERR | G_IO_HUP)) return FALSE; source->pfd.revents = 0; return TRUE; }, nullptr, // finalize nullptr, // closure_callback nullptr, // closure_marshall }; const struct wl_registry_listener g_registryListener = { // global [](void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t) { auto& interfaces = *static_cast<WaylandDisplay::Interfaces*>(data); if (!std::strcmp(interface, "wl_compositor")) interfaces.compositor = static_cast<struct wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, 1)); if (!std::strcmp(interface, "wl_data_device_manager")) interfaces.data_device_manager = static_cast<struct wl_data_device_manager*>(wl_registry_bind(registry, name, &wl_data_device_manager_interface, 2)); if (!std::strcmp(interface, "wl_drm")) interfaces.drm = static_cast<struct wl_drm*>(wl_registry_bind(registry, name, &wl_drm_interface, 2)); if (!std::strcmp(interface, "wl_seat")) interfaces.seat = static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, 4)); if (!std::strcmp(interface, "xdg_shell")) interfaces.xdg = static_cast<struct xdg_shell*>(wl_registry_bind(registry, name, &xdg_shell_interface, 1)); if (!std::strcmp(interface, "ivi_application")) interfaces.ivi_application = static_cast<struct ivi_application*>(wl_registry_bind(registry, name, &ivi_application_interface, 1)); }, // global_remove [](void*, struct wl_registry*, uint32_t) { }, }; static const struct xdg_shell_listener g_xdgShellListener = { // ping [](void*, struct xdg_shell* shell, uint32_t serial) { xdg_shell_pong(shell, serial); }, }; static const struct wl_pointer_listener g_pointerListener = { // enter [](void* data, struct wl_pointer*, uint32_t serial, struct wl_surface* surface, wl_fixed_t, wl_fixed_t) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; auto it = seatData.inputClients.find(surface); if (it != seatData.inputClients.end()) seatData.pointer.target = *it; }, // leave [](void* data, struct wl_pointer*, uint32_t serial, struct wl_surface* surface) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; auto it = seatData.inputClients.find(surface); if (it != seatData.inputClients.end() && seatData.pointer.target.first == it->first) seatData.pointer.target = { }; }, // motion [](void* data, struct wl_pointer*, uint32_t time, wl_fixed_t fixedX, wl_fixed_t fixedY) { auto x = wl_fixed_to_int(fixedX); auto y = wl_fixed_to_int(fixedY); auto& pointer = static_cast<WaylandDisplay::SeatData*>(data)->pointer; pointer.coords = { x, y }; if (pointer.target.first) pointer.target.second->handlePointerEvent({ Input::PointerEvent::Motion, time, x, y, 0, 0 }); }, // button [](void* data, struct wl_pointer*, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { static_cast<WaylandDisplay::SeatData*>(data)->serial = serial; if (button >= BTN_MOUSE) button = button - BTN_MOUSE + 1; else button = 0; auto& pointer = static_cast<WaylandDisplay::SeatData*>(data)->pointer; auto& coords = pointer.coords; if (pointer.target.first) pointer.target.second->handlePointerEvent( { Input::PointerEvent::Button, time, coords.first, coords.second, button, state }); }, // axis [](void* data, struct wl_pointer*, uint32_t time, uint32_t axis, wl_fixed_t value) { auto& pointer = static_cast<WaylandDisplay::SeatData*>(data)->pointer; auto& coords = pointer.coords; if (pointer.target.first) pointer.target.second->handleAxisEvent( { Input::AxisEvent::Motion, time, coords.first, coords.second, axis, -wl_fixed_to_int(value) }); }, }; static void handleKeyEvent(WaylandDisplay::SeatData& seatData, uint32_t key, uint32_t state, uint32_t time) { auto& xkb = seatData.xkb; uint32_t keysym = xkb_state_key_get_one_sym(xkb.state, key); uint32_t unicode = xkb_state_key_get_utf32(xkb.state, key); if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_compose_state_feed(xkb.composeState, keysym) == XKB_COMPOSE_FEED_ACCEPTED && xkb_compose_state_get_status(xkb.composeState) == XKB_COMPOSE_COMPOSED) { keysym = xkb_compose_state_get_one_sym(xkb.composeState); unicode = xkb_keysym_to_utf32(keysym); } if (seatData.keyboard.target.first) seatData.keyboard.target.second->handleKeyboardEvent({ time, keysym, unicode, !!state, xkb.modifiers }); } static gboolean repeatRateTimeout(void* data) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); handleKeyEvent(seatData, seatData.repeatData.key, seatData.repeatData.state, seatData.repeatData.time); return G_SOURCE_CONTINUE; } static gboolean repeatDelayTimeout(void* data) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); handleKeyEvent(seatData, seatData.repeatData.key, seatData.repeatData.state, seatData.repeatData.time); seatData.repeatData.eventSource = g_timeout_add(seatData.repeatInfo.rate, static_cast<GSourceFunc>(repeatRateTimeout), data); return G_SOURCE_REMOVE; } static const struct wl_keyboard_listener g_keyboardListener = { // keymap [](void* data, struct wl_keyboard*, uint32_t format, int fd, uint32_t size) { if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } void* mapping = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); if (mapping == MAP_FAILED) { close(fd); return; } auto& xkb = static_cast<WaylandDisplay::SeatData*>(data)->xkb; xkb.keymap = xkb_keymap_new_from_string(xkb.context, static_cast<char*>(mapping), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(mapping, size); close(fd); if (!xkb.keymap) return; xkb.state = xkb_state_new(xkb.keymap); if (!xkb.state) return; xkb.indexes.control = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_CTRL); xkb.indexes.alt = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_ALT); xkb.indexes.shift = xkb_keymap_mod_get_index(xkb.keymap, XKB_MOD_NAME_SHIFT); }, // enter [](void* data, struct wl_keyboard*, uint32_t serial, struct wl_surface* surface, struct wl_array*) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; auto it = seatData.inputClients.find(surface); if (it != seatData.inputClients.end()) seatData.keyboard.target = *it; }, // leave [](void* data, struct wl_keyboard*, uint32_t serial, struct wl_surface* surface) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; auto it = seatData.inputClients.find(surface); if (it != seatData.inputClients.end() && seatData.keyboard.target.first == it->first) seatData.keyboard.target = { }; }, // key [](void* data, struct wl_keyboard*, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { // IDK. key += 8; auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; handleKeyEvent(seatData, key, state, time); if (!seatData.repeatInfo.rate) return; if (state == WL_KEYBOARD_KEY_STATE_RELEASED && seatData.repeatData.key == key) { if (seatData.repeatData.eventSource) g_source_remove(seatData.repeatData.eventSource); seatData.repeatData = { 0, 0, 0, 0 }; } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(seatData.xkb.keymap, key)) { if (seatData.repeatData.eventSource) g_source_remove(seatData.repeatData.eventSource); seatData.repeatData = { key, time, state, g_timeout_add(seatData.repeatInfo.delay, static_cast<GSourceFunc>(repeatDelayTimeout), data) }; } }, // modifiers [](void* data, struct wl_keyboard*, uint32_t serial, uint32_t depressedMods, uint32_t latchedMods, uint32_t lockedMods, uint32_t group) { static_cast<WaylandDisplay::SeatData*>(data)->serial = serial; auto& xkb = static_cast<WaylandDisplay::SeatData*>(data)->xkb; xkb_state_update_mask(xkb.state, depressedMods, latchedMods, lockedMods, 0, 0, group); auto& modifiers = xkb.modifiers; modifiers = 0; auto component = static_cast<xkb_state_component>(XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.control, component)) modifiers |= Input::KeyboardEvent::Control; if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.alt, component)) modifiers |= Input::KeyboardEvent::Alt; if (xkb_state_mod_index_is_active(xkb.state, xkb.indexes.shift, component)) modifiers |= Input::KeyboardEvent::Shift; }, // repeat_info [](void* data, struct wl_keyboard*, int32_t rate, int32_t delay) { auto& repeatInfo = static_cast<WaylandDisplay::SeatData*>(data)->repeatInfo; repeatInfo = { rate, delay }; // A rate of zero disables any repeating. if (!rate) { auto& repeatData = static_cast<WaylandDisplay::SeatData*>(data)->repeatData; if (repeatData.eventSource) { g_source_remove(repeatData.eventSource); repeatData = { 0, 0, 0, 0 }; } } }, }; static const struct wl_touch_listener g_touchListener = { // down [](void* data, struct wl_touch*, uint32_t serial, uint32_t time, struct wl_surface* surface, int32_t id, wl_fixed_t x, wl_fixed_t y) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; int32_t arraySize = std::tuple_size<decltype(seatData.touch.targets)>::value; if (id < 0 || id >= arraySize) return; auto& target = seatData.touch.targets[id]; assert(!target.first && !target.second); auto it = seatData.inputClients.find(surface); if (it == seatData.inputClients.end()) return; target = { surface, it->second }; auto& touchPoints = seatData.touch.touchPoints; touchPoints[id] = { Input::TouchEvent::Down, time, id, wl_fixed_to_int(x), wl_fixed_to_int(y) }; target.second->handleTouchEvent({ touchPoints, Input::TouchEvent::Down, id, time }); }, // up [](void* data, struct wl_touch*, uint32_t serial, uint32_t time, int32_t id) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); seatData.serial = serial; int32_t arraySize = std::tuple_size<decltype(seatData.touch.targets)>::value; if (id < 0 || id >= arraySize) return; auto& target = seatData.touch.targets[id]; assert(target.first && target.second); auto& touchPoints = seatData.touch.touchPoints; auto& point = touchPoints[id]; point = { Input::TouchEvent::Up, time, id, point.x, point.y }; target.second->handleTouchEvent({ touchPoints, Input::TouchEvent::Up, id, time }); point = { Input::TouchEvent::Null, 0, 0, 0, 0 }; target = { nullptr, nullptr }; }, // motion [](void* data, struct wl_touch*, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); int32_t arraySize = std::tuple_size<decltype(seatData.touch.targets)>::value; if (id < 0 || id >= arraySize) return; auto& target = seatData.touch.targets[id]; assert(target.first && target.second); auto& touchPoints = seatData.touch.touchPoints; touchPoints[id] = { Input::TouchEvent::Motion, time, id, wl_fixed_to_int(x), wl_fixed_to_int(y) }; target.second->handleTouchEvent({ touchPoints, Input::TouchEvent::Motion, id, time }); }, // frame [](void*, struct wl_touch*) { // FIXME: Dispatching events via frame() would avoid dispatching events // for every single event that's encapsulated in a frame with multiple // other events. }, // cancel [](void*, struct wl_touch*) { }, }; static const struct wl_seat_listener g_seatListener = { // capabilities [](void* data, struct wl_seat* seat, uint32_t capabilities) { auto& seatData = *static_cast<WaylandDisplay::SeatData*>(data); // WL_SEAT_CAPABILITY_POINTER const bool hasPointerCap = capabilities & WL_SEAT_CAPABILITY_POINTER; if (hasPointerCap && !seatData.pointer.object) { seatData.pointer.object = wl_seat_get_pointer(seat); wl_pointer_add_listener(seatData.pointer.object, &g_pointerListener, &seatData); } if (!hasPointerCap && seatData.pointer.object) { wl_pointer_destroy(seatData.pointer.object); seatData.pointer.object = nullptr; } // WL_SEAT_CAPABILITY_KEYBOARD const bool hasKeyboardCap = capabilities & WL_SEAT_CAPABILITY_KEYBOARD; if (hasKeyboardCap && !seatData.keyboard.object) { seatData.keyboard.object = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(seatData.keyboard.object, &g_keyboardListener, &seatData); } if (!hasKeyboardCap && seatData.keyboard.object) { wl_keyboard_destroy(seatData.keyboard.object); seatData.keyboard.object = nullptr; } // WL_SEAT_CAPABILITY_TOUCH const bool hasTouchCap = capabilities & WL_SEAT_CAPABILITY_TOUCH; if (hasTouchCap && !seatData.touch.object) { seatData.touch.object = wl_seat_get_touch(seat); wl_touch_add_listener(seatData.touch.object, &g_touchListener, &seatData); } if (!hasTouchCap && seatData.touch.object) { wl_touch_destroy(seatData.touch.object); seatData.touch.object = nullptr; } }, // name [](void*, struct wl_seat*, const char*) { } }; WaylandDisplay& WaylandDisplay::singleton() { static WaylandDisplay display; return display; } WaylandDisplay::WaylandDisplay() { m_display = wl_display_connect(nullptr); m_registry = wl_display_get_registry(m_display); wl_registry_add_listener(m_registry, &g_registryListener, &m_interfaces); wl_display_roundtrip(m_display); m_eventSource = g_source_new(&EventSource::sourceFuncs, sizeof(EventSource)); auto* source = reinterpret_cast<EventSource*>(m_eventSource); source->display = m_display; source->pfd.fd = wl_display_get_fd(m_display); source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP; source->pfd.revents = 0; g_source_add_poll(m_eventSource, &source->pfd); g_source_set_name(m_eventSource, "[WPE] WaylandDisplay"); g_source_set_priority(m_eventSource, G_PRIORITY_HIGH + 30); g_source_set_can_recurse(m_eventSource, TRUE); g_source_attach(m_eventSource, g_main_context_get_thread_default()); if (m_interfaces.xdg) { xdg_shell_add_listener(m_interfaces.xdg, &g_xdgShellListener, nullptr); xdg_shell_use_unstable_version(m_interfaces.xdg, 5); } wl_seat_add_listener(m_interfaces.seat, &g_seatListener, &m_seatData); m_seatData.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); m_seatData.xkb.composeTable = xkb_compose_table_new_from_locale(m_seatData.xkb.context, setlocale(LC_CTYPE, nullptr), XKB_COMPOSE_COMPILE_NO_FLAGS); if (m_seatData.xkb.composeTable) m_seatData.xkb.composeState = xkb_compose_state_new(m_seatData.xkb.composeTable, XKB_COMPOSE_STATE_NO_FLAGS); } WaylandDisplay::~WaylandDisplay() { if (m_eventSource) g_source_unref(m_eventSource); m_eventSource = nullptr; if (m_interfaces.compositor) wl_compositor_destroy(m_interfaces.compositor); if (m_interfaces.data_device_manager) wl_data_device_manager_destroy(m_interfaces.data_device_manager); if (m_interfaces.drm) wl_drm_destroy(m_interfaces.drm); if (m_interfaces.seat) wl_seat_destroy(m_interfaces.seat); if (m_interfaces.xdg) xdg_shell_destroy(m_interfaces.xdg); if (m_interfaces.ivi_application) ivi_application_destroy(m_interfaces.ivi_application); m_interfaces = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; if (m_registry) wl_registry_destroy(m_registry); m_registry = nullptr; if (m_display) wl_display_disconnect(m_display); m_display = nullptr; if (m_seatData.pointer.object) wl_pointer_destroy(m_seatData.pointer.object); if (m_seatData.keyboard.object) wl_keyboard_destroy(m_seatData.keyboard.object); if (m_seatData.touch.object) wl_touch_destroy(m_seatData.touch.object); if (m_seatData.xkb.context) xkb_context_unref(m_seatData.xkb.context); if (m_seatData.xkb.keymap) xkb_keymap_unref(m_seatData.xkb.keymap); if (m_seatData.xkb.state) xkb_state_unref(m_seatData.xkb.state); if (m_seatData.xkb.composeTable) xkb_compose_table_unref(m_seatData.xkb.composeTable); if (m_seatData.xkb.composeState) xkb_compose_state_unref(m_seatData.xkb.composeState); if (m_seatData.repeatData.eventSource) g_source_remove(m_seatData.repeatData.eventSource); m_seatData = SeatData{ }; } void WaylandDisplay::registerInputClient(struct wl_surface* surface, Input::Client* client) { #ifndef NDEBUG auto result = #endif m_seatData.inputClients.insert({ surface, client }); assert(result.second); } void WaylandDisplay::unregisterInputClient(struct wl_surface* surface) { auto it = m_seatData.inputClients.find(surface); assert(it != m_seatData.inputClients.end()); if (m_seatData.pointer.target.first == it->first) m_seatData.pointer.target = { }; if (m_seatData.keyboard.target.first == it->first) m_seatData.keyboard.target = { }; m_seatData.inputClients.erase(it); } } // namespace ViewBackend
static void test_caps_keysym_transformation(struct xkb_keymap *keymap) { struct xkb_state *state = xkb_state_new(keymap); xkb_mod_index_t caps, shift; int nsyms; xkb_keysym_t sym; const xkb_keysym_t *syms; assert(state); /* See xkb_state_key_get_one_sym() for what's this all about. */ caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); assert(caps != XKB_MOD_INVALID && shift != XKB_MOD_INVALID); assert(xkb_state_key_get_layout(state, KEY_A + 8) == 0); assert(xkb_state_key_get_layout(state, KEY_SEMICOLON + 8) == 0); /* Without caps, no transformation. */ assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 0); sym = xkb_state_key_get_one_sym(state, KEY_A + 8); assert(sym == XKB_KEY_a); assert(xkb_state_key_get_level(state, KEY_SEMICOLON + 8, 0) == 0); sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8); assert(sym == XKB_KEY_eacute); nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms); assert(nsyms == 1 && syms[0] == XKB_KEY_eacute); /* With shift, no transformation (only different level). */ xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_DOWN); assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) > 0); assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 1); sym = xkb_state_key_get_one_sym(state, KEY_A + 8); assert(sym == XKB_KEY_A); sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8); assert(sym == XKB_KEY_odiaeresis); nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms); assert(nsyms == 1 && syms[0] == XKB_KEY_odiaeresis); xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_UP); assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0); /* With caps, transform in same level, only with _get_one_sym(). */ xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_UP); assert(xkb_state_mod_index_is_active(state, caps, XKB_STATE_MODS_EFFECTIVE) > 0); assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_key_get_level(state, KEY_A + 8, 0) == 1); sym = xkb_state_key_get_one_sym(state, KEY_A + 8); assert(sym == XKB_KEY_A); assert(xkb_state_key_get_level(state, KEY_SEMICOLON + 8, 0) == 0); sym = xkb_state_key_get_one_sym(state, KEY_SEMICOLON + 8); assert(sym == XKB_KEY_Eacute); nsyms = xkb_state_key_get_syms(state, KEY_SEMICOLON + 8, &syms); assert(nsyms == 1 && syms[0] == XKB_KEY_eacute); xkb_state_update_key(state, KEY_LEFTSHIFT + 8, XKB_KEY_UP); assert(xkb_state_mod_index_is_active(state, shift, XKB_STATE_MODS_EFFECTIVE) == 0); xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + 8, XKB_KEY_UP); xkb_state_unref(state); }
static void test_consume(struct xkb_keymap *keymap) { struct xkb_state *state; xkb_mod_index_t alt, shift, caps, ctrl, mod5; xkb_mod_mask_t mask; state = xkb_state_new(keymap); assert(state); alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); assert(alt != XKB_MOD_INVALID); shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); assert(shift != XKB_MOD_INVALID); caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); assert(caps != XKB_MOD_INVALID); ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); assert(ctrl != XKB_MOD_INVALID); mod5 = xkb_keymap_mod_get_index(keymap, "Mod5"); assert(mod5 != XKB_MOD_INVALID); /* Test remove_consumed() */ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_EQUAL + EVDEV_OFFSET, XKB_KEY_DOWN); fprintf(stderr, "dumping state for Alt-Shift-+\n"); print_state(state); mask = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); assert(mask == ((1U << alt) | (1U << shift))); mask = xkb_state_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET, mask); assert(mask == (1U << alt)); /* Test get_consumed_mods() */ mask = xkb_state_key_get_consumed_mods(state, KEY_EQUAL + EVDEV_OFFSET); assert(mask == (1U << shift)); mask = xkb_state_key_get_consumed_mods(state, KEY_ESC + EVDEV_OFFSET); assert(mask == 0); xkb_state_unref(state); /* Test is_consumed() - simple ALPHABETIC type. */ state = xkb_state_new(keymap); assert(state); mask = xkb_state_key_get_consumed_mods(state, KEY_A + EVDEV_OFFSET); assert(mask == ((1U << shift) | (1U << caps))); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, caps) > 0); assert(xkb_state_mod_index_is_consumed(state, KEY_A + EVDEV_OFFSET, shift) > 0); xkb_state_unref(state); /* More complicated - CTRL+ALT */ state = xkb_state_new(keymap); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5))); /* Shift is preserved. */ xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); assert(mask == ((1U << alt) | (1U << ctrl) | (1U << mod5))); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP); mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET); assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5))); assert(state); xkb_state_unref(state); }
int init_xkb(int fd, size_t size) { char *map_str = NULL; mod_map_idx = (xkb_mod_index_t *)calloc( MOD_MAP_SIZE, sizeof(xkb_mod_index_t)); if (!mod_map_idx) goto error; mod_map_bit = (uint16_t*) calloc(MOD_MAP_SIZE, sizeof(uint16_t)); if (!mod_map_bit) goto error; xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (xkb_ctx) { if (fd >= 0) { map_str = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map_str == MAP_FAILED) goto error; xkb_map = xkb_keymap_new_from_string(xkb_ctx, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_str, size); } else { struct string_list *list = NULL; struct xkb_rule_names rule = {0}; settings_t *settings = config_get_ptr(); rule.rules = "evdev"; if (*settings->arrays.input_keyboard_layout) { list = string_split(settings->arrays.input_keyboard_layout, ":"); if (list && list->size >= 2) rule.variant = list->elems[1].data; if (list && list->size >= 1) rule.layout = list->elems[0].data; } xkb_map = xkb_keymap_new_from_names(xkb_ctx, &rule, XKB_MAP_COMPILE_NO_FLAGS); if (list) string_list_free(list); } } if (xkb_map) { xkb_mod_index_t *map_idx = (xkb_mod_index_t*)&mod_map_idx[0]; uint16_t *map_bit = (uint16_t*)&mod_map_bit[0]; xkb_state = xkb_state_new(xkb_map); *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_CAPS); map_idx++; *map_bit = RETROKMOD_CAPSLOCK; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_SHIFT); map_idx++; *map_bit = RETROKMOD_SHIFT; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_CTRL); map_idx++; *map_bit = RETROKMOD_CTRL; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_ALT); map_idx++; *map_bit = RETROKMOD_ALT; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_LOGO); *map_bit = RETROKMOD_META; } return 0; error: free_xkb(); return -1; }
int init_xkb(void) { settings_t *settings = config_get_ptr(); mod_map_idx = (xkb_mod_index_t *)calloc(MOD_MAP_SIZE, sizeof(xkb_mod_index_t)); if (!mod_map_idx) goto error; mod_map_bit = (uint16_t*)calloc(MOD_MAP_SIZE, sizeof(uint16_t)); if (!mod_map_bit) goto error; xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (xkb_ctx) { struct string_list *list = NULL; struct xkb_rule_names rule = {0}; rule.rules = "evdev"; if (*settings->input.keyboard_layout) { list = string_split(settings->input.keyboard_layout, ":"); if (list && list->size >= 2) rule.variant = list->elems[1].data; if (list && list->size >= 1) rule.layout = list->elems[0].data; } xkb_map = xkb_keymap_new_from_names(xkb_ctx, &rule, XKB_MAP_COMPILE_NO_FLAGS); if (list) string_list_free(list); } if (xkb_map) { xkb_mod_index_t *map_idx = (xkb_mod_index_t*)&mod_map_idx[0]; uint16_t *map_bit = (uint16_t*)&mod_map_bit[0]; xkb_state = xkb_state_new(xkb_map); *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_CAPS); map_idx++; *map_bit = RETROKMOD_CAPSLOCK; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_SHIFT); map_idx++; *map_bit = RETROKMOD_SHIFT; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_CTRL); map_idx++; *map_bit = RETROKMOD_CTRL; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_ALT); map_idx++; *map_bit = RETROKMOD_ALT; map_bit++; *map_idx = xkb_keymap_mod_get_index(xkb_map, XKB_MOD_NAME_LOGO); *map_bit = RETROKMOD_META; } return 0; error: free_xkb(); return -1; }
static void test_update_key(struct xkb_keymap *keymap) { struct xkb_state *state = xkb_state_new(keymap); const xkb_keysym_t *syms; xkb_keysym_t one_sym; int num_syms; assert(state); /* LCtrl down */ xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN); fprintf(stderr, "dumping state for LCtrl down:\n"); print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED) > 0); /* LCtrl + RAlt down */ xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_DOWN); fprintf(stderr, "dumping state for LCtrl + RAlt down:\n"); print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, NULL) > 0); assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL, xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL), xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT), XKB_MOD_INVALID) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL, XKB_MOD_NAME_ALT, NULL) == 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, XKB_MOD_NAME_ALT, NULL) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, (XKB_STATE_MATCH_ANY | XKB_STATE_MATCH_NON_EXCLUSIVE), XKB_MOD_NAME_ALT, NULL) > 0); /* RAlt down */ xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP); fprintf(stderr, "dumping state for RAlt down:\n"); print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ANY, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, NULL) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_LATCHED, XKB_STATE_MATCH_ANY, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, NULL) == 0); /* none down */ xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_EFFECTIVE) == 0); /* Caps locked */ xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_DEPRESSED) > 0); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); fprintf(stderr, "dumping state for Caps Lock:\n"); print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_DEPRESSED) == 0); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED) > 0); assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_CAPS) > 0); num_syms = xkb_state_key_get_syms(state, KEY_Q + EVDEV_OFFSET, &syms); assert(num_syms == 1 && syms[0] == XKB_KEY_Q); /* Num Lock locked */ xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_UP); fprintf(stderr, "dumping state for Caps Lock + Num Lock:\n"); print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED) > 0); assert(xkb_state_mod_name_is_active(state, "Mod2", XKB_STATE_MODS_LOCKED) > 0); num_syms = xkb_state_key_get_syms(state, KEY_KP1 + EVDEV_OFFSET, &syms); assert(num_syms == 1 && syms[0] == XKB_KEY_KP_1); assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0); /* Num Lock unlocked */ xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_NUMLOCK + EVDEV_OFFSET, XKB_KEY_UP); /* Switch to group 2 */ xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_led_name_is_active(state, "Group 2") > 0); assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) == 0); /* Switch back to group 1. */ xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_COMPOSE + EVDEV_OFFSET, XKB_KEY_UP); /* Caps unlocked */ xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_EFFECTIVE) == 0); assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_CAPS) == 0); num_syms = xkb_state_key_get_syms(state, KEY_Q + EVDEV_OFFSET, &syms); assert(num_syms == 1 && syms[0] == XKB_KEY_q); /* Multiple symbols */ num_syms = xkb_state_key_get_syms(state, KEY_6 + EVDEV_OFFSET, &syms); assert(num_syms == 5 && syms[0] == XKB_KEY_H && syms[1] == XKB_KEY_E && syms[2] == XKB_KEY_L && syms[3] == XKB_KEY_L && syms[4] == XKB_KEY_O); one_sym = xkb_state_key_get_one_sym(state, KEY_6 + EVDEV_OFFSET); assert(one_sym == XKB_KEY_NoSymbol); xkb_state_update_key(state, KEY_6 + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_6 + EVDEV_OFFSET, XKB_KEY_UP); one_sym = xkb_state_key_get_one_sym(state, KEY_5 + EVDEV_OFFSET); assert(one_sym == XKB_KEY_5); xkb_state_unref(state); }