static void update_internal_xkb_state (ClutterInputDeviceEvdev *device, xkb_mod_mask_t new_latched_mask, xkb_mod_mask_t new_locked_mask) { ClutterSeatEvdev *seat = device->seat; xkb_mod_mask_t depressed_mods; xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t group_mods; depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED); latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED); locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED); latched_mods &= ~device->stickykeys_latched_mask; locked_mods &= ~device->stickykeys_locked_mask; device->stickykeys_latched_mask = new_latched_mask; device->stickykeys_locked_mask = new_locked_mask; latched_mods |= device->stickykeys_latched_mask; locked_mods |= device->stickykeys_locked_mask; group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE); xkb_state_update_mask (seat->xkb, depressed_mods, latched_mods, locked_mods, 0, 0, group_mods); notify_stickykeys_mask (device); }
static void keyboardHandleModifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group) { xkb_mod_mask_t mask; unsigned int modifiers = 0; if (!_glfw.wl.xkb.keymap) return; xkb_state_update_mask(_glfw.wl.xkb.state, modsDepressed, modsLatched, modsLocked, 0, 0, group); mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, XKB_STATE_DEPRESSED | XKB_STATE_LATCHED); if (mask & _glfw.wl.xkb.control_mask) modifiers |= GLFW_MOD_CONTROL; if (mask & _glfw.wl.xkb.alt_mask) modifiers |= GLFW_MOD_ALT; if (mask & _glfw.wl.xkb.shift_mask) modifiers |= GLFW_MOD_SHIFT; if (mask & _glfw.wl.xkb.super_mask) modifiers |= GLFW_MOD_SUPER; _glfw.wl.xkb.modifiers = modifiers; }
void handle_xkb_state_mask(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { if (!xkb_state) return; xkb_state_update_mask(xkb_state, depressed, latched, locked, 0, 0, group); }
static void ss_seat_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial_in, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct ss_seat *seat = data; struct weston_compositor *c = seat->base.compositor; struct weston_keyboard *keyboard; uint32_t serial_out; /* If we get a key event followed by a modifier event with the * same serial number, then we try to preserve those semantics by * reusing the same serial number on the way out too. */ if (serial_in == seat->key_serial) serial_out = wl_display_get_serial(c->wl_display); else serial_out = wl_display_next_serial(c->wl_display); keyboard = weston_seat_get_keyboard(&seat->base); xkb_state_update_mask(keyboard->xkb_state.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); notify_modifiers(&seat->base, serial_out); }
static void input_method_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct simple_im *keyboard = data; struct input_method_context *context = keyboard->context; xkb_mod_mask_t mask; xkb_state_update_mask(keyboard->state, mods_depressed, mods_latched, mods_locked, 0, 0, group); mask = xkb_state_serialize_mods(keyboard->state, XKB_STATE_DEPRESSED | XKB_STATE_LATCHED); keyboard->modifiers = 0; if (mask & keyboard->control_mask) keyboard->modifiers |= MOD_CONTROL_MASK; if (mask & keyboard->alt_mask) keyboard->modifiers |= MOD_ALT_MASK; if (mask & keyboard->shift_mask) keyboard->modifiers |= MOD_SHIFT_MASK; input_method_context_modifiers(context, serial, mods_depressed, mods_depressed, mods_latched, group); }
void EglFSWaylandInput::keyboardModifiersChanged(quint32 depressed, quint32 latched, quint32 locked, quint32 group) { if (m_xkbState) xkb_state_update_mask(m_xkbState, depressed, latched, locked, 0, 0, group); m_modifiers = EglFSXkb::modifiers(m_xkbState); m_nativeModifiers = depressed | latched | locked; }
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); }
/** * Process X11 events in the main-loop (gui-thread) of the application. */ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer data ) { if ( ev == NULL ) { int status = xcb_connection_has_error ( xcb->connection ); fprintf ( stderr, "The XCB connection to X server had a fatal error: %d\n", status ); g_main_loop_quit ( main_loop ); return G_SOURCE_REMOVE; } uint8_t type = ev->response_type & ~0x80; if ( type == xkb.first_event ) { switch ( ev->pad0 ) { case XCB_XKB_MAP_NOTIFY: xkb_state_unref ( xkb.state ); xkb_keymap_unref ( xkb.keymap ); xkb.keymap = xkb_x11_keymap_new_from_device ( xkb.context, xcb->connection, xkb.device_id, 0 ); xkb.state = xkb_x11_state_new_from_device ( xkb.keymap, xcb->connection, xkb.device_id ); break; case XCB_XKB_STATE_NOTIFY: { xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev; xkb_state_update_mask ( xkb.state, ksne->baseMods, ksne->latchedMods, ksne->lockedMods, ksne->baseGroup, ksne->latchedGroup, ksne->lockedGroup ); break; } } return G_SOURCE_CONTINUE; } RofiViewState *state = rofi_view_get_active (); if ( xcb->sndisplay != NULL ) { sn_xcb_display_process_event ( xcb->sndisplay, ev ); } if ( state != NULL ) { rofi_view_itterrate ( state, ev, &xkb ); if ( rofi_view_get_completed ( state ) ) { // This menu is done. rofi_view_finalize ( state ); // cleanup if ( rofi_view_get_active () == NULL ) { teardown ( pfd ); g_main_loop_quit ( main_loop ); } } } return G_SOURCE_CONTINUE; }
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct vo_wayland_state *wl = data; xkb_state_update_mask(wl->input.xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); }
/* * Called when the keyboard mapping changes. We update our symbols. * * We ignore errors — if the new keymap cannot be loaded it’s better if the * screen stays locked and the user intervenes by using killall i3lock. * */ static void process_xkb_event(xcb_generic_event_t *gevent) { union xkb_event { struct { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; } any; xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; xcb_xkb_map_notify_event_t map_notify; xcb_xkb_state_notify_event_t state_notify; } *event = (union xkb_event *)gevent; DEBUG("process_xkb_event for device %d\n", event->any.deviceID); if (event->any.deviceID != xkb_x11_get_core_keyboard_device_id(conn)) return; /* * XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap * updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent * recompilations. */ switch (event->any.xkbType) { case XCB_XKB_NEW_KEYBOARD_NOTIFY: if (event->new_keyboard_notify.changed & XCB_XKB_NKN_DETAIL_KEYCODES) (void)load_keymap(); break; case XCB_XKB_MAP_NOTIFY: (void)load_keymap(); break; case XCB_XKB_STATE_NOTIFY: xkb_state_update_mask(xkb_state, event->state_notify.baseMods, event->state_notify.latchedMods, event->state_notify.lockedMods, event->state_notify.baseGroup, event->state_notify.latchedGroup, event->state_notify.lockedGroup); break; } }
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct registry *registry = data; if (!registry->input->xkb.keymap) { return; } xkb_state_update_mask(registry->input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); xkb_mod_mask_t mask = xkb_state_serialize_mods(registry->input->xkb.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); registry->input->modifiers = 0; for (uint32_t i = 0; i < MASK_LAST; ++i) { if (mask & registry->input->xkb.masks[i]) { registry->input->modifiers |= XKB_MODS[i]; } } }
static void clutter_wayland_handle_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { ClutterInputDeviceWayland *device = data; if (!device->xkb) return; xkb_state_update_mask (device->xkb, mods_depressed, mods_latched, mods_locked, 0, 0, group); }
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { xkb_mod_mask_t mask; xkb_state_update_mask(GLWin.keyboard.xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); mask = xkb_state_serialize_mods(GLWin.keyboard.xkb.state, (xkb_state_component) (XKB_STATE_DEPRESSED | XKB_STATE_LATCHED)); GLWin.keyboard.modifiers = 0; if (mask & GLWin.keyboard.xkb.control_mask) GLWin.keyboard.modifiers |= MOD_CONTROL_MASK; if (mask & GLWin.keyboard.xkb.alt_mask) GLWin.keyboard.modifiers |= MOD_ALT_MASK; if (mask & GLWin.keyboard.xkb.shift_mask) GLWin.keyboard.modifiers |= MOD_SHIFT_MASK; }
static void process_keyboard_event(Keyboard *keyboard, xcb_generic_event_t *event) { union xkb_event { struct { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; } any; xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; xcb_xkb_map_notify_event_t map_notify; xcb_xkb_state_notify_event_t state_notify; } *e = (union xkb_event *)event; if (e->any.deviceID != keyboard->device_id) { return; } switch (e->any.xkbType) { case XCB_XKB_NEW_KEYBOARD_NOTIFY: if (e->new_keyboard_notify.changed & XCB_XKB_NKN_DETAIL_KEYCODES) { update_keymap(keyboard); } break; case XCB_XKB_MAP_NOTIFY: update_keymap(keyboard); break; case XCB_XKB_STATE_NOTIFY: xkb_state_update_mask(keyboard->state, e->state_notify.baseMods, e->state_notify.latchedMods, e->state_notify.lockedMods, e->state_notify.baseGroup, e->state_notify.latchedGroup, e->state_notify.lockedGroup); break; default: break; } }
static void input_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial_in, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct wayland_input *input = data; struct wayland_compositor *c = input->compositor; uint32_t serial_out; /* If we get a key event followed by a modifier event with the * same serial number, then we try to preserve those semantics by * reusing the same serial number on the way out too. */ if (serial_in == input->key_serial) serial_out = wl_display_get_serial(c->base.wl_display); else serial_out = wl_display_next_serial(c->base.wl_display); xkb_state_update_mask(input->base.xkb_state.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); notify_modifiers(&input->base, serial_out); }
int X11Backend::eventLoop() { xcb_generic_event_t* event; int count = 0; while((event = xcb_poll_for_event(xConnection_))) { switch(event->response_type & ~0x80) { case XCB_EXPOSE: { xcb_expose_event_t* ev = (xcb_expose_event_t*) event; auto* outp = outputForWindow(ev->window); if(!outp) { ny::sendWarning("xcb_expose: invalid xcb window"); break; } outp->scheduleRepaint(); break; } case XCB_CLIENT_MESSAGE: { xcb_client_message_event_t* ev = (xcb_client_message_event_t*) event; if(ev->data.data32[0] == atoms::deleteWindow) { auto* outp = outputForWindow(ev->window); if(!outp) { ny::sendWarning("xcb_client_message: invalid xcb window"); break; } destroyOutput(*outp); if(outputs_.empty()) { compositor().exit(); return count + 1; } } break; } case XCB_BUTTON_PRESS: { if(!seat().pointer()) break; xcb_button_press_event_t* ev = (xcb_button_press_event_t*) event; unsigned int code = (ev->detail == 2 ? BTN_MIDDLE : (ev->detail == 3 ? BTN_RIGHT : ev->detail + BTN_LEFT - 1)); seat().pointer()->sendButton(code, 1); break; } case XCB_BUTTON_RELEASE: { if(!seat().pointer()) break; xcb_button_release_event_t* ev = (xcb_button_release_event_t*) event; unsigned int code = (ev->detail == 2 ? BTN_MIDDLE : (ev->detail == 3 ? BTN_RIGHT : ev->detail + BTN_LEFT - 1)); seat().pointer()->sendButton(code, 0); break; } case XCB_MOTION_NOTIFY: { if(!seat().pointer()) break; xcb_motion_notify_event_t* ev = (xcb_motion_notify_event_t*) event; seat().pointer()->sendMove({ev->event_x, ev->event_y}); break; } case XCB_KEY_PRESS: { if(!seat().keyboard()) break; xcb_key_press_event_t* ev = (xcb_key_press_event_t*) event; seat().keyboard()->sendKey(ev->detail - 8, true); break; } case XCB_KEY_RELEASE: { if(!seat().keyboard()) break; xcb_key_press_event_t* ev = (xcb_key_press_event_t*) event; seat().keyboard()->sendKey(ev->detail - 8, false); break; } case XCB_FOCUS_IN: { break; } case XCB_FOCUS_OUT: { break; } case XCB_ENTER_NOTIFY: { break; } case XCB_LEAVE_NOTIFY: { break; } default: break; } if(event->response_type == xkbEventBase_) { xcb_xkb_state_notify_event_t *ev = (xcb_xkb_state_notify_event_t*)event; if(ev->xkbType == XCB_XKB_STATE_NOTIFY) { if(seat().keyboard()) { auto& kb = *seat().keyboard(); xkb_state_update_mask(&kb.xkbState(), kb.modMask(ev->baseMods), kb.modMask(ev->latchedMods), kb.modMask(ev->lockedMods), 0, 0, ev->group); seat().keyboard()->updateModifiers(); } } } free(event); ++count; } return count; }
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