static void test_repeat(struct xkb_keymap *keymap) { assert(!xkb_keymap_key_repeats(keymap, KEY_LEFTSHIFT + 8)); assert(xkb_keymap_key_repeats(keymap, KEY_A + 8)); assert(xkb_keymap_key_repeats(keymap, KEY_8 + 8)); assert(xkb_keymap_key_repeats(keymap, KEY_DOWN + 8)); assert(xkb_keymap_key_repeats(keymap, KEY_KBDILLUMDOWN + 8)); }
static void uxkb_dev_repeat(struct uterm_input_dev *dev, unsigned int state) { struct xkb_keymap *keymap = xkb_state_get_keymap(dev->state); unsigned int i; int num_keysyms, ret; const uint32_t *keysyms; struct itimerspec spec; if (dev->repeating && dev->repeat_event.keycode == dev->event.keycode) { if (state == KEY_RELEASED) { dev->repeating = false; ev_timer_update(dev->repeat_timer, NULL); } return; } if (state == KEY_PRESSED && xkb_keymap_key_repeats(keymap, dev->event.keycode)) { dev->repeat_event.keycode = dev->event.keycode; dev->repeat_event.ascii = dev->event.ascii; dev->repeat_event.mods = dev->event.mods; dev->repeat_event.num_syms = dev->event.num_syms; for (i = 0; i < dev->event.num_syms; ++i) { dev->repeat_event.keysyms[i] = dev->event.keysyms[i]; dev->repeat_event.codepoints[i] = dev->event.codepoints[i]; } } else if (dev->repeating && !xkb_keymap_key_repeats(keymap, dev->event.keycode)) { num_keysyms = xkb_state_key_get_syms(dev->state, dev->repeat_event.keycode, &keysyms); if (num_keysyms <= 0) return; ret = uxkb_dev_fill_event(dev, &dev->repeat_event, dev->repeat_event.keycode, num_keysyms, keysyms); if (ret) return; return; } else { return; } dev->repeating = true; spec.it_interval.tv_sec = 0; spec.it_interval.tv_nsec = dev->input->repeat_rate * 1000000; spec.it_value.tv_sec = 0; spec.it_value.tv_nsec = dev->input->repeat_delay * 1000000; ev_timer_update(dev->repeat_timer, &spec); }
static void process_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value) { xkb_keycode_t keycode; struct xkb_keymap *keymap; enum xkb_state_component changed; if (type != EV_KEY) return; keycode = evdev_offset + code; keymap = xkb_state_get_keymap(kbd->state); if (value == KEY_STATE_REPEAT && !xkb_keymap_key_repeats(keymap, keycode)) return; if (value != KEY_STATE_RELEASE) test_print_keycode_state(kbd->state, keycode); if (value == KEY_STATE_RELEASE) changed = xkb_state_update_key(kbd->state, keycode, XKB_KEY_UP); else changed = xkb_state_update_key(kbd->state, keycode, XKB_KEY_DOWN); if (report_state_changes) test_print_state_changes(changed); }
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 }
void EglFSWaylandInput::processKeyEvent(QEvent::Type type, quint32 time, quint32 key) { EglFSWaylandWindow *window = EglFSWaylandWindow::fromSurface( m_seat->keyboard()->focusSurface()); if (!createDefaultKeymap()) return; quint32 code = key + 8; QString text; const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_xkbState, code); quint32 utf32 = xkb_keysym_to_utf32(sym); if (utf32) text = QString::fromUcs4(&utf32, 1); int qtKey = EglFSXkb::keysymToQtKey(sym, m_modifiers, text); QWindowSystemInterface::handleExtendedKeyEvent(window ? window->window() : Q_NULLPTR, time, type, qtKey, m_modifiers, code, sym, m_nativeModifiers, text); if (type == QEvent::KeyPress && xkb_keymap_key_repeats(m_xkbKeymap, code)) { m_repeatKey = qtKey; m_repeatCode = code; m_repeatTime = time; m_repeatText = text; m_repeatSym = sym; m_repeatTimer.setInterval(m_seat->keyboard()->repeatRate()); m_repeatTimer.start(); } else if (m_repeatCode == code) { m_repeatTimer.stop(); } }
static GLFWbool inputChar(_GLFWwindow* window, uint32_t key) { uint32_t code, numSyms; long cp; const xkb_keysym_t *syms; xkb_keysym_t sym; code = key + 8; numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); if (numSyms == 1) { #ifdef HAVE_XKBCOMMON_COMPOSE_H sym = composeSymbol(syms[0]); #else sym = syms[0]; #endif cp = _glfwKeySym2Unicode(sym); if (cp != -1) { const int mods = _glfw.wl.xkb.modifiers; const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); _glfwInputChar(window, cp, mods, plain); } } return xkb_keymap_key_repeats(_glfw.wl.xkb.keymap, syms[0]); }
static void keyboard_repeat(idev_keyboard *k) { idev_data *evdata = &k->evdata; idev_data *repdata = &k->repdata; idev_data_keyboard *evkbd = &evdata->keyboard; idev_data_keyboard *repkbd = &repdata->keyboard; const xkb_keysym_t *keysyms; idev_device *d = &k->device; bool repeats; int r, num; if (evdata->resync) { /* * We received a re-sync event. During re-sync, any number of * key-events may have been lost and sync-events may be * re-ordered. Always disable key-repeat for those events. Any * following event will trigger it again. */ k->repeating = false; keyboard_arm(k, 0); return; } repeats = xkb_keymap_key_repeats(k->kbdmap->xkb_keymap, evkbd->keycode + KBDXKB_SHIFT); if (k->repeating && repkbd->keycode == evkbd->keycode) { /* * We received an event for the key we currently repeat. If it * was released, stop key-repeat. Otherwise, ignore the event. */ if (evkbd->value == KBDKEY_UP) { k->repeating = false; keyboard_arm(k, 0); } } else if (evkbd->value == KBDKEY_DOWN && repeats) { /* * We received a key-down event for a key that repeats. The * previous condition caught keys we already repeat, so we know * this is a different key or no key-repeat is running. Start * new key-repeat. */ errno = 0; num = xkb_state_key_get_syms(k->xkb_state, evkbd->keycode + KBDXKB_SHIFT, &keysyms); if (num < 0) r = errno > 0 ? errno : -EFAULT; else r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms); if (r < 0) { log_debug_errno(r, "idev-keyboard: %s/%s: cannot set key-repeat: %m", d->session->name, d->name); k->repeating = false; keyboard_arm(k, 0); } else { k->repeating = true; keyboard_arm(k, k->repeat_delay); } } else if (k->repeating && !repeats) { /* * We received an event for a key that does not repeat, but we * currently repeat a previously received key. The new key is * usually a modifier, but might be any kind of key. In this * case, we continue repeating the old key, but update the * symbols according to the new state. */ errno = 0; num = xkb_state_key_get_syms(k->xkb_state, repkbd->keycode + KBDXKB_SHIFT, &keysyms); if (num < 0) r = errno > 0 ? errno : -EFAULT; else r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms); if (r < 0) { log_debug_errno(r, "idev-keyboard: %s/%s: cannot update key-repeat: %m", d->session->name, d->name); k->repeating = false; keyboard_arm(k, 0); } } }
void clutter_seat_evdev_notify_key (ClutterSeatEvdev *seat, ClutterInputDevice *device, uint64_t time_us, uint32_t key, uint32_t state, gboolean update_keys) { ClutterStage *stage; ClutterEvent *event = NULL; enum xkb_state_component changed_state; if (state != AUTOREPEAT_VALUE) { /* Drop any repeated button press (for example from virtual devices. */ int count = update_button_count (seat, key, state); if (state && count > 1) return; if (!state && count != 0) return; } /* We can drop the event on the floor if no stage has been * associated with the device yet. */ stage = _clutter_input_device_get_stage (device); if (stage == NULL) { clutter_seat_evdev_clear_repeat_timer (seat); return; } event = _clutter_key_event_new_from_evdev (device, seat->core_keyboard, stage, seat->xkb, seat->button_state, us2ms (time_us), key, state); _clutter_evdev_event_set_event_code (event, key); /* We must be careful and not pass multiple releases to xkb, otherwise it gets confused and locks the modifiers */ if (state != AUTOREPEAT_VALUE) { changed_state = xkb_state_update_key (seat->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP); } else { changed_state = 0; clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_REPEATED); } queue_event (event); if (update_keys && (changed_state & XKB_STATE_LEDS)) { ClutterBackend *backend; backend = clutter_get_default_backend (); g_signal_emit_by_name (clutter_backend_get_keymap (backend), "state-changed"); clutter_seat_evdev_sync_leds (seat); } if (state == 0 || /* key release */ !seat->repeat || !xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb), event->key.hardware_keycode)) { clutter_seat_evdev_clear_repeat_timer (seat); return; } if (state == 1) /* key press */ seat->repeat_count = 0; seat->repeat_count += 1; seat->repeat_key = key; switch (seat->repeat_count) { case 1: case 2: { guint32 interval; clutter_seat_evdev_clear_repeat_timer (seat); seat->repeat_device = g_object_ref (device); if (seat->repeat_count == 1) interval = seat->repeat_delay; else interval = seat->repeat_interval; seat->repeat_timer = clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS, interval, keyboard_repeat, seat, NULL); return; } default: return; } }
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