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 }
END_TEST START_TEST(device_disable_release_keys) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; struct libinput_device *device; struct libinput_event *event; struct libinput_event_keyboard *kbdevent; enum libinput_config_status status; device = dev->libinput_device; litest_button_click(dev, KEY_A, true); litest_drain_events(li); litest_assert_empty_queue(li); status = libinput_device_config_send_events_set_mode(device, LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); litest_wait_for_event(li); event = libinput_get_event(li); ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_KEYBOARD_KEY); kbdevent = libinput_event_get_keyboard_event(event); ck_assert_int_eq(libinput_event_keyboard_get_key(kbdevent), KEY_A); ck_assert_int_eq(libinput_event_keyboard_get_key_state(kbdevent), LIBINPUT_KEY_STATE_RELEASED); libinput_event_destroy(event); litest_assert_empty_queue(li); }
END_TEST START_TEST(keyboard_ignore_no_pressed_release) { struct litest_device *dev; struct libinput *unused_libinput; struct libinput *libinput; struct libinput_event *event; struct libinput_event_keyboard *kevent; int events[] = { EV_KEY, KEY_A, -1, -1, }; enum libinput_key_state *state; enum libinput_key_state expected_states[] = { LIBINPUT_KEY_STATE_PRESSED, LIBINPUT_KEY_STATE_RELEASED, }; /* We can't send pressed -> released -> pressed events using uinput * as such non-symmetric events are dropped. Work-around this by first * adding the test device to the tested context after having sent an * initial pressed event. */ unused_libinput = litest_create_context(); dev = litest_add_device_with_overrides(unused_libinput, LITEST_KEYBOARD, "Generic keyboard", NULL, NULL, events); litest_keyboard_key(dev, KEY_A, true); litest_drain_events(unused_libinput); libinput = litest_create_context(); libinput_path_add_device(libinput, libevdev_uinput_get_devnode(dev->uinput)); litest_drain_events(libinput); litest_keyboard_key(dev, KEY_A, false); litest_keyboard_key(dev, KEY_A, true); litest_keyboard_key(dev, KEY_A, false); libinput_dispatch(libinput); ARRAY_FOR_EACH(expected_states, state) { event = libinput_get_event(libinput); ck_assert_notnull(event); ck_assert_int_eq(libinput_event_get_type(event), LIBINPUT_EVENT_KEYBOARD_KEY); kevent = libinput_event_get_keyboard_event(event); ck_assert_int_eq(libinput_event_keyboard_get_key(kevent), KEY_A); ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent), *state); libinput_event_destroy(event); libinput_dispatch(libinput); }
static void handle_keyboard_key(struct libinput_device *libinput_device, struct libinput_event_keyboard *keyboard_event) { struct evdev_device *device = libinput_device_get_user_data(libinput_device); notify_key(device->seat, libinput_event_keyboard_get_time(keyboard_event), libinput_event_keyboard_get_key(keyboard_event), libinput_event_keyboard_get_key_state(keyboard_event), STATE_UPDATE_AUTOMATIC); }
static void handle_keyboard_key(struct libinput_device *libinput_device, struct libinput_event_keyboard *keyboard_event) { struct evdev_device *device = libinput_device_get_user_data(libinput_device); int key_state = libinput_event_keyboard_get_key_state(keyboard_event); int seat_key_count = libinput_event_keyboard_get_seat_key_count(keyboard_event); /* Ignore key events that are not seat wide state changes. */ if ((key_state == LIBINPUT_KEY_STATE_PRESSED && seat_key_count != 1) || (key_state == LIBINPUT_KEY_STATE_RELEASED && seat_key_count != 0)) return; notify_key(device->seat, libinput_event_keyboard_get_time(keyboard_event), libinput_event_keyboard_get_key(keyboard_event), libinput_event_keyboard_get_key_state(keyboard_event), STATE_UPDATE_AUTOMATIC); }
static int input_event(int fd, uint32_t mask, void *data) { (void)fd, (void)mask; struct input *input = data; if (libinput_dispatch(input->handle) != 0) wlc_log(WLC_LOG_WARN, "Failed to dispatch libinput"); struct libinput_event *event; while ((event = libinput_get_event(input->handle))) { struct libinput *handle = libinput_event_get_context(event); struct libinput_device *device = libinput_event_get_device(event); (void)handle; switch (libinput_event_get_type(event)) { case LIBINPUT_EVENT_DEVICE_ADDED: WLC_INTERFACE_EMIT(input.created, device); break; case LIBINPUT_EVENT_DEVICE_REMOVED: WLC_INTERFACE_EMIT(input.destroyed, device); break; case LIBINPUT_EVENT_POINTER_MOTION: { struct libinput_event_pointer *pev = libinput_event_get_pointer_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_MOTION; ev.time = libinput_event_pointer_get_time(pev); ev.motion.dx = libinput_event_pointer_get_dx(pev); ev.motion.dy = libinput_event_pointer_get_dy(pev); wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { struct libinput_event_pointer *pev = libinput_event_get_pointer_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_MOTION_ABSOLUTE; ev.time = libinput_event_pointer_get_time(pev); ev.motion_abs.x = pointer_abs_x; ev.motion_abs.y = pointer_abs_y; ev.motion_abs.internal = pev; wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_POINTER_BUTTON: { struct libinput_event_pointer *pev = libinput_event_get_pointer_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_BUTTON; ev.time = libinput_event_pointer_get_time(pev); ev.button.code = libinput_event_pointer_get_button(pev); ev.button.state = (enum wl_pointer_button_state)libinput_event_pointer_get_button_state(pev); wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_POINTER_AXIS: { struct libinput_event_pointer *pev = libinput_event_get_pointer_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_SCROLL; ev.time = libinput_event_pointer_get_time(pev); #if LIBINPUT_VERSION_MAJOR == 0 && LIBINPUT_VERSION_MINOR < 8 /* < libinput 0.8.x (at least to 0.6.x) */ const enum wl_pointer_axis axis = libinput_event_pointer_get_axis(pev); ev.scroll.amount[(axis == LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)] = libinput_event_pointer_get_axis_value(pev); ev.scroll.axis_bits |= (axis == LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL ? WLC_SCROLL_AXIS_HORIZONTAL : WLC_SCROLL_AXIS_VERTICAL); #else /* > libinput 0.8.0 */ if (libinput_event_pointer_has_axis(pev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { ev.scroll.amount[0] = libinput_event_pointer_get_axis_value(pev, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); ev.scroll.axis_bits |= WLC_SCROLL_AXIS_VERTICAL; } if (libinput_event_pointer_has_axis(pev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { ev.scroll.amount[1] = libinput_event_pointer_get_axis_value(pev, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); ev.scroll.axis_bits |= WLC_SCROLL_AXIS_HORIZONTAL; } #endif // We should get other axis information from libinput as well, like source (finger, wheel) (v0.8) wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_KEYBOARD_KEY: { struct libinput_event_keyboard *kev = libinput_event_get_keyboard_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_KEY; ev.time = libinput_event_keyboard_get_time(kev); ev.key.code = libinput_event_keyboard_get_key(kev); ev.key.state = (enum wl_keyboard_key_state)libinput_event_keyboard_get_key_state(kev); ev.device = device; wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_TOUCH_UP: { struct libinput_event_touch *tev = libinput_event_get_touch_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_TOUCH; ev.time = libinput_event_touch_get_time(tev); ev.touch.type = wlc_touch_type_for_libinput_type(libinput_event_get_type(event)); ev.touch.slot = libinput_event_touch_get_seat_slot(tev); wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_TOUCH_DOWN: case LIBINPUT_EVENT_TOUCH_MOTION: { struct libinput_event_touch *tev = libinput_event_get_touch_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_TOUCH; ev.time = libinput_event_touch_get_time(tev); ev.touch.type = wlc_touch_type_for_libinput_type(libinput_event_get_type(event)); ev.touch.x = touch_abs_x; ev.touch.y = touch_abs_y; ev.touch.internal = tev; ev.touch.slot = libinput_event_touch_get_seat_slot(tev); wl_signal_emit(&wlc_system_signals()->input, &ev); } break; case LIBINPUT_EVENT_TOUCH_FRAME: case LIBINPUT_EVENT_TOUCH_CANCEL: { struct libinput_event_touch *tev = libinput_event_get_touch_event(event); struct wlc_input_event ev = {0}; ev.type = WLC_INPUT_EVENT_TOUCH; ev.time = libinput_event_touch_get_time(tev); ev.touch.type = wlc_touch_type_for_libinput_type(libinput_event_get_type(event)); wl_signal_emit(&wlc_system_signals()->input, &ev); } break; default: break; } libinput_event_destroy(event); } return 0; }
inline void LibInputHandler::HandleEvent(struct libinput_event *li_event) { int type = libinput_event_get_type(li_event); switch (type) { case LIBINPUT_EVENT_KEYBOARD_KEY: { /* Discard all data on stdin to avoid that keyboard input data is read * on the executing shell. */ tcflush(STDIN_FILENO, TCIFLUSH); libinput_event_keyboard *kb_li_event = libinput_event_get_keyboard_event(li_event); uint32_t key_code = libinput_event_keyboard_get_key(kb_li_event); libinput_key_state key_state = libinput_event_keyboard_get_key_state(kb_li_event); queue.Push(Event(key_state == LIBINPUT_KEY_STATE_PRESSED ? Event::KEY_DOWN : Event::KEY_UP, key_code)); } break; case LIBINPUT_EVENT_POINTER_MOTION: { libinput_event_pointer *ptr_li_event = libinput_event_get_pointer_event(li_event); if (-1.0 == x) x = 0.0; if (-1.0 == y) y = 0.0; x += libinput_event_pointer_get_dx(ptr_li_event); x = Clamp<double>(x, 0, width); y += libinput_event_pointer_get_dy(ptr_li_event); y = Clamp<double>(y, 0, height); queue.Push(Event(Event::MOUSE_MOTION, (unsigned) x, (unsigned) y)); } break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: { libinput_event_pointer *ptr_li_event = libinput_event_get_pointer_event(li_event); x = libinput_event_pointer_get_absolute_x_transformed(ptr_li_event, width); y = libinput_event_pointer_get_absolute_y_transformed(ptr_li_event, height); queue.Push(Event(Event::MOUSE_MOTION, (unsigned) x, (unsigned) y)); } break; case LIBINPUT_EVENT_POINTER_BUTTON: { libinput_event_pointer *ptr_li_event = libinput_event_get_pointer_event(li_event); libinput_button_state btn_state = libinput_event_pointer_get_button_state(ptr_li_event); queue.Push(Event(btn_state == LIBINPUT_BUTTON_STATE_PRESSED ? Event::MOUSE_DOWN : Event::MOUSE_UP, (unsigned) x, (unsigned) y)); } break; case LIBINPUT_EVENT_POINTER_AXIS: { libinput_event_pointer *ptr_li_event = libinput_event_get_pointer_event(li_event); double axis_value = libinput_event_pointer_get_axis_value(ptr_li_event); Event event(Event::MOUSE_WHEEL, (unsigned) x, (unsigned) y); event.param = unsigned((int) axis_value); queue.Push(event); } break; case LIBINPUT_EVENT_TOUCH_DOWN: { libinput_event_touch *touch_li_event = libinput_event_get_touch_event(li_event); x = libinput_event_touch_get_x_transformed(touch_li_event, width); y = libinput_event_touch_get_y_transformed(touch_li_event, height); queue.Push(Event(Event::MOUSE_DOWN, (unsigned) x, (unsigned) y)); } break; case LIBINPUT_EVENT_TOUCH_UP: { queue.Push(Event(Event::MOUSE_UP, (unsigned) x, (unsigned) y)); } break; case LIBINPUT_EVENT_TOUCH_MOTION: { libinput_event_touch *touch_li_event = libinput_event_get_touch_event(li_event); x = libinput_event_touch_get_x_transformed(touch_li_event, width); y = libinput_event_touch_get_y_transformed(touch_li_event, height); queue.Push(Event(Event::MOUSE_MOTION, (unsigned) x, (unsigned) y)); } break; } }
void LibinputServer::processEvents() { libinput_dispatch(m_libinput); while (auto* event = libinput_get_event(m_libinput)) { switch (libinput_event_get_type(event)) { case LIBINPUT_EVENT_TOUCH_DOWN: if (m_handleTouchEvents) handleTouchEvent(event, Input::TouchEvent::Type::Down); break; case LIBINPUT_EVENT_TOUCH_UP: if (m_handleTouchEvents) handleTouchEvent(event, Input::TouchEvent::Type::Up); break; case LIBINPUT_EVENT_TOUCH_MOTION: if (m_handleTouchEvents) handleTouchEvent(event, Input::TouchEvent::Type::Motion); break; case LIBINPUT_EVENT_KEYBOARD_KEY: { auto* keyEvent = libinput_event_get_keyboard_event(event); Input::KeyboardEvent::Raw rawEvent{ libinput_event_keyboard_get_time(keyEvent), libinput_event_keyboard_get_key(keyEvent), libinput_event_keyboard_get_key_state(keyEvent) }; Input::KeyboardEventHandler::Result result = m_keyboardEventHandler->handleKeyboardEvent(rawEvent); m_client->handleKeyboardEvent({ rawEvent.time, std::get<0>(result), std::get<1>(result), !!rawEvent.state, std::get<2>(result) }); if (!!rawEvent.state) m_keyboardEventRepeating->schedule(rawEvent); else m_keyboardEventRepeating->cancel(); break; } case LIBINPUT_EVENT_POINTER_MOTION: { if (!m_handlePointerEvents) break; auto* pointerEvent = libinput_event_get_pointer_event(event); double dx = libinput_event_pointer_get_dx(pointerEvent); double dy = libinput_event_pointer_get_dy(pointerEvent); m_pointerCoords.first = std::min<int32_t>(std::max<uint32_t>(0, m_pointerCoords.first + dx), m_pointerBounds.first - 1); m_pointerCoords.second = std::min<int32_t>(std::max<uint32_t>(0, m_pointerCoords.second + dy), m_pointerBounds.second - 1); m_client->handlePointerEvent({ Input::PointerEvent::Motion, libinput_event_pointer_get_time(pointerEvent), m_pointerCoords.first, m_pointerCoords.second, 0, 0 }); break; } case LIBINPUT_EVENT_POINTER_BUTTON: { if (!m_handlePointerEvents) break; auto* pointerEvent = libinput_event_get_pointer_event(event); m_client->handlePointerEvent({ Input::PointerEvent::Button, libinput_event_pointer_get_time(pointerEvent), m_pointerCoords.first, m_pointerCoords.second, libinput_event_pointer_get_button(pointerEvent), libinput_event_pointer_get_button_state(pointerEvent) }); break; } case LIBINPUT_EVENT_POINTER_AXIS: { if (!m_handlePointerEvents) break; auto* pointerEvent = libinput_event_get_pointer_event(event); // Support only wheel events for now. if (libinput_event_pointer_get_axis_source(pointerEvent) != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL) break; if (libinput_event_pointer_has_axis(pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { auto axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL; int32_t axisValue = libinput_event_pointer_get_axis_value(pointerEvent, axis); m_client->handleAxisEvent({ Input::AxisEvent::Motion, libinput_event_pointer_get_time(pointerEvent), m_pointerCoords.first, m_pointerCoords.second, axis, -axisValue }); } if (libinput_event_pointer_has_axis(pointerEvent, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { auto axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL; int32_t axisValue = libinput_event_pointer_get_axis_value(pointerEvent, axis); m_client->handleAxisEvent({ Input::AxisEvent::Motion, libinput_event_pointer_get_time(pointerEvent), m_pointerCoords.first, m_pointerCoords.second, axis, axisValue }); } break; } default: break; } libinput_event_destroy(event); } }