static void print_keycode(struct keyboard *kbd, xkb_keycode_t keycode) { unsigned int i; struct xkb_keymap *keymap; struct xkb_state *state; const xkb_keysym_t *syms; unsigned int nsyms; char s[16]; uint32_t unicode; xkb_layout_index_t layout; xkb_mod_index_t mod; xkb_led_index_t led; state = kbd->state; keymap = xkb_state_get_keymap(state); nsyms = xkb_state_key_get_syms(state, keycode, &syms); if (nsyms <= 0) return; printf("keysyms [ "); for (i = 0; i < nsyms; i++) { xkb_keysym_get_name(syms[i], s, sizeof(s)); printf("%-*s ", (int)sizeof(s), s); } printf("] "); /* * Only do this if wchar_t is UCS-4, so we can be lazy and print * with %lc. */ #ifdef __STDC_ISO_10646__ printf("unicode [ "); for (i = 0; i < nsyms; i++) { unicode = xkb_keysym_to_utf32(syms[i]); printf("%lc ", (int)(unicode ? unicode : L' ')); } printf("] "); #endif layout = xkb_state_key_get_layout(state, keycode); printf("layout [ %s (%d) ] ", xkb_keymap_layout_get_name(keymap, layout), layout); printf("level [ %d ] ", xkb_state_key_get_level(state, keycode, layout)); printf("mods [ "); for (mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) { if (xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_EFFECTIVE) <= 0) continue; if (xkb_state_mod_index_is_consumed(state, keycode, mod)) printf("-%s ", xkb_keymap_mod_get_name(keymap, mod)); else printf("%s ", xkb_keymap_mod_get_name(keymap, mod)); } printf("] "); printf("leds [ "); for (led = 0; led < xkb_keymap_num_leds(keymap); led++) { if (xkb_state_led_index_is_active(state, led) <= 0) continue; printf("%s ", xkb_keymap_led_get_name(keymap, led)); } printf("] "); printf("\n"); }
void QLibInputKeyboard::processKey(libinput_event_keyboard *e) { #ifndef QT_NO_XKBCOMMON_EVDEV if (!m_ctx || !m_keymap || !m_state) return; const uint32_t k = libinput_event_keyboard_get_key(e) + 8; const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED; QVarLengthArray<char, 32> chars(32); const int size = xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL chars.resize(size + 1); xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size()); } const QString text = QString::fromUtf8(chars.constData(), size); const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k); // mods here is the modifier state before the event, i.e. not // including the current key in case it is a modifier. Qt::KeyboardModifiers mods = Qt::NoModifier; const int qtkey = keysymToQtKey(sym, &mods, text); xkb_state_component modtype = xkb_state_component(XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); if (xkb_state_mod_index_is_active(m_state, m_modindex[0], modtype) && (qtkey != Qt::Key_Control || !pressed)) mods |= Qt::ControlModifier; if (xkb_state_mod_index_is_active(m_state, m_modindex[1], modtype) && (qtkey != Qt::Key_Alt || !pressed)) mods |= Qt::AltModifier; if (xkb_state_mod_index_is_active(m_state, m_modindex[2], modtype) && (qtkey != Qt::Key_Shift || !pressed)) mods |= Qt::ShiftModifier; if (xkb_state_mod_index_is_active(m_state, m_modindex[3], modtype) && (qtkey != Qt::Key_Meta || !pressed)) mods |= Qt::MetaModifier; xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(mods, qtkey); QWindowSystemInterface::handleExtendedKeyEvent(Q_NULLPTR, pressed ? QEvent::KeyPress : QEvent::KeyRelease, qtkey, mods, k, sym, mods, text); if (pressed && xkb_keymap_key_repeats(m_keymap, k)) { m_repeatData.qtkey = qtkey; m_repeatData.mods = mods; m_repeatData.nativeScanCode = k; m_repeatData.virtualKey = sym; m_repeatData.nativeMods = mods; m_repeatData.unicodeText = text; m_repeatData.repeatCount = 1; m_repeatTimer.setInterval(REPEAT_DELAY); m_repeatTimer.start(); } else if (m_repeatTimer.isActive()) { m_repeatTimer.stop(); } #else Q_UNUSED(e); #endif }
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 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 int keyboard_fill(idev_keyboard *k, idev_data *dst, bool resync, uint16_t code, uint32_t value, uint32_t n_syms, const uint32_t *keysyms) { idev_data_keyboard *kev; uint32_t i; int r; assert(dst == &k->evdata || dst == &k->repdata); r = keyboard_resize_bufs(k, n_syms); if (r < 0) return r; dst->type = IDEV_DATA_KEYBOARD; dst->resync = resync; kev = &dst->keyboard; kev->ascii = guess_ascii(k->xkb_state, code, n_syms, keysyms); kev->value = value; kev->keycode = code; kev->mods = 0; kev->consumed_mods = 0; kev->n_syms = n_syms; memcpy(kev->keysyms, keysyms, sizeof(*keysyms) * n_syms); for (i = 0; i < n_syms; ++i) { kev->codepoints[i] = xkb_keysym_to_utf32(keysyms[i]); if (!kev->codepoints[i]) kev->codepoints[i] = 0xffffffffUL; } for (i = 0; i < IDEV_KBDMOD_CNT; ++i) { if (k->kbdmap->modmap[i] == XKB_MOD_INVALID) continue; r = xkb_state_mod_index_is_active(k->xkb_state, k->kbdmap->modmap[i], XKB_STATE_MODS_EFFECTIVE); if (r > 0) kev->mods |= 1 << i; r = xkb_state_mod_index_is_consumed(k->xkb_state, code + KBDXKB_SHIFT, k->kbdmap->modmap[i]); if (r > 0) kev->consumed_mods |= 1 << i; } return 0; }
/* FIXME: Don't handle composed and dead-keys properly. * Waiting for support in libxkbcommon ... */ int handle_xkb(int code, int value) { unsigned i; const xkb_keysym_t *syms = NULL; unsigned num_syms = 0; uint16_t mod = 0; /* Convert Linux evdev to X11 (xkbcommon docs say so at least ...) */ int xk_code = code + 8; if (!xkb_state) return -1; if (value == 2) /* Repeat, release first explicitly. */ xkb_state_update_key(xkb_state, xk_code, XKB_KEY_UP); if (value) num_syms = xkb_state_key_get_syms(xkb_state, xk_code, &syms); if (value > 0) xkb_state_update_key(xkb_state, xk_code, XKB_KEY_DOWN); else xkb_state_update_key(xkb_state, xk_code, XKB_KEY_UP); if (!syms) return -1; /* Build mod state. */ for (i = 0; i < MOD_MAP_SIZE; i++) { xkb_mod_index_t *map_idx = (xkb_mod_index_t*)&mod_map_idx[i]; uint16_t *map_bit = (uint16_t *)&mod_map_bit[i]; if (*map_idx != XKB_MOD_INVALID) mod |= xkb_state_mod_index_is_active( xkb_state, *map_idx, (enum xkb_state_component) ((XKB_STATE_MODS_EFFECTIVE) > 0)) ? *map_bit : 0; } input_keyboard_event(value, input_keymaps_translate_keysym_to_rk(code), num_syms ? xkb_keysym_to_utf32(syms[0]) : 0, mod, RETRO_DEVICE_KEYBOARD); for (i = 1; i < num_syms; i++) input_keyboard_event(value, RETROK_UNKNOWN, xkb_keysym_to_utf32(syms[i]), mod, RETRO_DEVICE_KEYBOARD); return 0; }
static void input_done(void) { STOP_TIMER(clear_pam_wrong_timeout); pam_state = STATE_PAM_VERIFY; redraw_screen(); if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) { DEBUG("successfully authenticated\n"); clear_password_memory(); /* PAM credentials should be refreshed, this will for example update any kerberos tickets. * Related to credentials pam_end() needs to be called to cleanup any temporary * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the * refresh of the credentials failed. */ pam_setcred(pam_handle, PAM_REFRESH_CRED); pam_end(pam_handle, PAM_SUCCESS); exit(0); } if (debug_mode) fprintf(stderr, "Authentication failure\n"); /* Get state of Caps and Num lock modifiers, to be displayed in * STATE_PAM_WRONG state */ xkb_mod_index_t idx, num_mods; const char *mod_name; num_mods = xkb_keymap_num_mods(xkb_keymap); for (idx = 0; idx < num_mods; idx++) { if (!xkb_state_mod_index_is_active(xkb_state, idx, XKB_STATE_MODS_EFFECTIVE)) continue; mod_name = xkb_keymap_mod_get_name(xkb_keymap, idx); if (mod_name == NULL) continue; /* Replace certain xkb names with nicer, human-readable ones. */ if (strcmp(mod_name, XKB_MOD_NAME_CAPS) == 0) mod_name = "Caps Lock"; else if (strcmp(mod_name, XKB_MOD_NAME_ALT) == 0) mod_name = "Alt"; else if (strcmp(mod_name, XKB_MOD_NAME_NUM) == 0) mod_name = "Num Lock"; else if (strcmp(mod_name, XKB_MOD_NAME_LOGO) == 0) mod_name = "Win"; char *tmp; if (modifier_string == NULL) { if (asprintf(&tmp, "%s", mod_name) != -1) modifier_string = tmp; } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) { free(modifier_string); modifier_string = tmp; } } pam_state = STATE_PAM_WRONG; failed_attempts += 1; clear_input(); if (unlock_indicator) redraw_screen(); /* Skip all the events during the pam verification to avoid bad people * spamming keys and locking pam in an endless validation loop */ xcb_generic_event_t *ev = xcb_poll_for_event(conn); free(ev); while (ev != NULL) { ev = xcb_poll_for_queued_event(conn); free(ev); } /* Clear this state after 2 seconds (unless the user enters another * password during that time). */ ev_now_update(main_loop); START_TIMER(clear_pam_wrong_timeout, TSTAMP_N_SECS(2), clear_pam_wrong); /* Cancel the clear_indicator_timeout, it would hide the unlock indicator * too early. */ STOP_TIMER(clear_indicator_timeout); /* beep on authentication failure, if enabled */ if (beep) { xcb_bell(conn, 100); xcb_flush(conn); } }
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 print_state(struct xkb_state *state) { struct xkb_keymap *keymap; xkb_layout_index_t group; xkb_mod_index_t mod; xkb_led_index_t led; group = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE); mod = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); /* led = xkb_state_serialize_leds(state, XKB_STATE_LEDS); */ if (!group && !mod /* && !led */) { fprintf(stderr, "\tno state\n"); return; } keymap = xkb_state_get_keymap(state); for (group = 0; group < xkb_keymap_num_layouts(keymap); group++) { if (xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_EFFECTIVE | XKB_STATE_LAYOUT_DEPRESSED | XKB_STATE_LAYOUT_LATCHED | XKB_STATE_LAYOUT_LOCKED) <= 0) continue; fprintf(stderr, "\tgroup %s (%d): %s%s%s%s\n", xkb_keymap_layout_get_name(keymap, group), group, xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_EFFECTIVE) > 0 ? "effective " : "", xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_DEPRESSED) > 0 ? "depressed " : "", xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_LATCHED) > 0 ? "latched " : "", xkb_state_layout_index_is_active(state, group, XKB_STATE_LAYOUT_LOCKED) > 0 ? "locked " : ""); } for (mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) { if (xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_EFFECTIVE | XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED) <= 0) continue; fprintf(stderr, "\tmod %s (%d): %s%s%s%s\n", xkb_keymap_mod_get_name(keymap, mod), mod, xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_EFFECTIVE) > 0 ? "effective " : "", xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_DEPRESSED) > 0 ? "depressed " : "", xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_LATCHED) > 0 ? "latched " : "", xkb_state_mod_index_is_active(state, mod, XKB_STATE_MODS_LOCKED) > 0 ? "locked " : ""); } for (led = 0; led < xkb_keymap_num_leds(keymap); led++) { if (xkb_state_led_index_is_active(state, led) <= 0) continue; fprintf(stderr, "\tled %s (%d): active\n", xkb_keymap_led_get_name(keymap, led), led); } }