mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-04 07:15:59 -04:00
backend, virtual_keyboard: set the time_nsec field of relevant events
Backends modified: libinput (with microsecond precision), X11 (with millisecond precision), RDP (with millisecond precision), and Wayland (with nanosecond precision if the host server supports the input-timestamps protocol, otherwise millisecond precision); and virtual-keyboard protocol (with millisecond precision).
This commit is contained in:
parent
79ed410be4
commit
e617da0378
9 changed files with 172 additions and 38 deletions
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "backend/wayland.h"
|
||||
#include "util/signal.h"
|
||||
#include "input-timestamps-unstable-v1-client-protocol.h"
|
||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
|
@ -81,6 +82,9 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(iface, zwp_pointer_gestures_v1_interface.name) == 0) {
|
||||
wl->zwp_pointer_gestures_v1 = wl_registry_bind(registry, name,
|
||||
&zwp_pointer_gestures_v1_interface, 1);
|
||||
} else if (strcmp(iface, zwp_input_timestamps_manager_v1_interface.name) == 0) {
|
||||
wl->input_timestamps.manager = wl_registry_bind(registry, name,
|
||||
&zwp_input_timestamps_manager_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,6 +231,11 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
|
|||
goto error_registry;
|
||||
}
|
||||
|
||||
if (!wl->input_timestamps.manager) {
|
||||
wlr_log(WLR_INFO,
|
||||
"Remote Wayland compositor does not support input-timestamps");
|
||||
}
|
||||
|
||||
struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display);
|
||||
int fd = wl_display_get_fd(wl->remote_display);
|
||||
int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||
#include "backend/wayland.h"
|
||||
#include "util/signal.h"
|
||||
#include "input-timestamps-unstable-v1-client-protocol.h"
|
||||
|
||||
static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) {
|
||||
struct wlr_input_device *wlr_dev;
|
||||
|
|
@ -34,6 +36,15 @@ static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline uint32_t timespec_to_msec(const struct timespec *a) {
|
||||
assert((unsigned long)a->tv_sec < UINT32_MAX / 1000 &&
|
||||
"struct timespec value too big");
|
||||
return (uint32_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
|
||||
}
|
||||
static inline uint64_t timespec_to_nsec(const struct timespec *a) {
|
||||
return (uint64_t)a->tv_sec * 1000000000 + a->tv_nsec;
|
||||
}
|
||||
|
||||
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
|
||||
wl_fixed_t sy) {
|
||||
|
|
@ -78,10 +89,19 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t time_nsec;
|
||||
if (backend->input_timestamps.manager &&
|
||||
backend->input_timestamps.pointer.tv_sec == time / 1000) {
|
||||
time_nsec = timespec_to_nsec(&backend->input_timestamps.pointer);
|
||||
} else {
|
||||
time_nsec = (time % 1000) * 1000000;
|
||||
}
|
||||
|
||||
struct wlr_output *wlr_output = &pointer->output->wlr_output;
|
||||
struct wlr_event_pointer_motion_absolute event = {
|
||||
.device = &pointer->input_device->wlr_input_device,
|
||||
.time_msec = time,
|
||||
.time_nsec = time_nsec,
|
||||
.x = wl_fixed_to_double(sx) / wlr_output->width,
|
||||
.y = wl_fixed_to_double(sy) / wlr_output->height,
|
||||
};
|
||||
|
|
@ -96,11 +116,20 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t time_nsec;
|
||||
if (backend->input_timestamps.manager &&
|
||||
backend->input_timestamps.pointer.tv_sec == time / 1000) {
|
||||
time_nsec = timespec_to_nsec(&backend->input_timestamps.pointer);
|
||||
} else {
|
||||
time_nsec = (time % 1000) * 1000000;
|
||||
}
|
||||
|
||||
struct wlr_event_pointer_button event = {
|
||||
.device = &pointer->input_device->wlr_input_device,
|
||||
.button = button,
|
||||
.state = state,
|
||||
.time_msec = time,
|
||||
.time_nsec = time_nsec,
|
||||
};
|
||||
wlr_signal_emit_safe(&pointer->wlr_pointer.events.button, &event);
|
||||
}
|
||||
|
|
@ -113,12 +142,21 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t time_nsec;
|
||||
if (backend->input_timestamps.manager &&
|
||||
backend->input_timestamps.pointer.tv_sec == time / 1000) {
|
||||
time_nsec = timespec_to_nsec(&backend->input_timestamps.pointer);
|
||||
} else {
|
||||
time_nsec = (time % 1000) * 1000000;
|
||||
}
|
||||
|
||||
struct wlr_event_pointer_axis event = {
|
||||
.device = &pointer->input_device->wlr_input_device,
|
||||
.delta = wl_fixed_to_double(value),
|
||||
.delta_discrete = pointer->axis_discrete,
|
||||
.orientation = axis,
|
||||
.time_msec = time,
|
||||
.time_nsec = time_nsec,
|
||||
.source = pointer->axis_source,
|
||||
};
|
||||
wlr_signal_emit_safe(&pointer->wlr_pointer.events.axis, &event);
|
||||
|
|
@ -156,12 +194,21 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t time_nsec;
|
||||
if (backend->input_timestamps.manager &&
|
||||
backend->input_timestamps.pointer.tv_sec == time / 1000) {
|
||||
time_nsec = timespec_to_nsec(&backend->input_timestamps.pointer);
|
||||
} else {
|
||||
time_nsec = (time % 1000) * 1000000;
|
||||
}
|
||||
|
||||
struct wlr_event_pointer_axis event = {
|
||||
.device = &pointer->input_device->wlr_input_device,
|
||||
.delta = 0,
|
||||
.delta_discrete = 0,
|
||||
.orientation = axis,
|
||||
.time_msec = time,
|
||||
.time_nsec = time_nsec,
|
||||
.source = pointer->axis_source,
|
||||
};
|
||||
wlr_signal_emit_safe(&pointer->wlr_pointer.events.axis, &event);
|
||||
|
|
@ -195,24 +242,23 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|||
// TODO: set keymap
|
||||
}
|
||||
|
||||
static uint32_t get_current_time_msec(void) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
return now.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
|
||||
struct wlr_input_device *dev = data;
|
||||
struct wlr_wl_input_device *wl_dev = data;
|
||||
struct wlr_input_device *dev = &wl_dev->wlr_input_device;
|
||||
|
||||
uint32_t time = get_current_time_msec();
|
||||
assert(dev && dev->keyboard);
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
uint32_t *keycode_ptr;
|
||||
wl_array_for_each(keycode_ptr, keys) {
|
||||
struct wlr_event_keyboard_key event = {
|
||||
.keycode = *keycode_ptr,
|
||||
.state = WLR_KEY_PRESSED,
|
||||
.time_msec = time,
|
||||
.time_msec = timespec_to_msec(&now),
|
||||
.time_nsec = timespec_to_nsec(&now),
|
||||
.update_state = false,
|
||||
};
|
||||
wlr_keyboard_notify_key(dev->keyboard, &event);
|
||||
|
|
@ -221,9 +267,13 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
|
|||
|
||||
static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface) {
|
||||
struct wlr_input_device *dev = data;
|
||||
struct wlr_wl_input_device *wl_dev = data;
|
||||
struct wlr_input_device *dev = &wl_dev->wlr_input_device;
|
||||
|
||||
uint32_t time = get_current_time_msec();
|
||||
assert(dev && dev->keyboard);
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
uint32_t pressed[dev->keyboard->num_keycodes + 1];
|
||||
memcpy(pressed, dev->keyboard->keycodes,
|
||||
|
|
@ -235,7 +285,8 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
|||
struct wlr_event_keyboard_key event = {
|
||||
.keycode = keycode,
|
||||
.state = WLR_KEY_RELEASED,
|
||||
.time_msec = time,
|
||||
.time_msec = timespec_to_msec(&now),
|
||||
.time_nsec = timespec_to_nsec(&now),
|
||||
.update_state = false,
|
||||
};
|
||||
wlr_keyboard_notify_key(dev->keyboard, &event);
|
||||
|
|
@ -244,13 +295,25 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
|||
|
||||
static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
|
||||
struct wlr_input_device *dev = data;
|
||||
struct wlr_wl_input_device *wl_dev = data;
|
||||
struct wlr_input_device *dev = &wl_dev->wlr_input_device;
|
||||
|
||||
assert(dev && dev->keyboard);
|
||||
|
||||
uint64_t time_nsec;
|
||||
if (wl_dev->backend->input_timestamps.manager &&
|
||||
wl_dev->backend->input_timestamps.keyboard.tv_sec == time / 1000) {
|
||||
time_nsec =
|
||||
timespec_to_nsec(&wl_dev->backend->input_timestamps.keyboard);
|
||||
} else {
|
||||
time_nsec = (time % 1000) * 1000000;
|
||||
}
|
||||
|
||||
struct wlr_event_keyboard_key wlr_event = {
|
||||
.keycode = key,
|
||||
.state = state,
|
||||
.time_msec = time,
|
||||
.time_nsec = time_nsec,
|
||||
.update_state = false,
|
||||
};
|
||||
wlr_keyboard_notify_key(dev->keyboard, &wlr_event);
|
||||
|
|
@ -259,15 +322,18 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
|
|||
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 wlr_input_device *dev = data;
|
||||
struct wlr_wl_input_device *wl_dev = data;
|
||||
struct wlr_input_device *dev = &wl_dev->wlr_input_device;
|
||||
|
||||
assert(dev && dev->keyboard);
|
||||
wlr_keyboard_notify_modifiers(dev->keyboard, mods_depressed, mods_latched,
|
||||
mods_locked, group);
|
||||
|
||||
wlr_keyboard_notify_modifiers(dev->keyboard, mods_depressed,
|
||||
mods_latched, mods_locked, group);
|
||||
}
|
||||
|
||||
static void keyboard_handle_repeat_info(void *data,
|
||||
struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) {
|
||||
// This space is intentionally left blank
|
||||
/* This space is intentionally left blank */
|
||||
}
|
||||
|
||||
static struct wl_keyboard_listener keyboard_listener = {
|
||||
|
|
@ -521,11 +587,27 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *
|
|||
}
|
||||
wlr_keyboard_init(wlr_dev->keyboard, NULL);
|
||||
|
||||
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev);
|
||||
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, dev);
|
||||
dev->resource = wl_keyboard;
|
||||
wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev);
|
||||
}
|
||||
|
||||
static void input_timestamps_handle_timestamp(void *data,
|
||||
struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
|
||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||
struct timespec *timestamp = data;
|
||||
|
||||
uint64_t tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
|
||||
assert(tv_sec < (uint64_t)LONG_MAX && "input-timestamps value is too big");
|
||||
|
||||
timestamp->tv_sec = tv_sec;
|
||||
timestamp->tv_nsec = tv_nsec;
|
||||
}
|
||||
|
||||
static const struct zwp_input_timestamps_v1_listener input_timestamps_listener = {
|
||||
.timestamp = input_timestamps_handle_timestamp,
|
||||
};
|
||||
|
||||
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||
enum wl_seat_capability caps) {
|
||||
struct wlr_wl_backend *backend = data;
|
||||
|
|
@ -543,6 +625,14 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
}
|
||||
|
||||
wl_pointer_add_listener(wl_pointer, &pointer_listener, backend);
|
||||
|
||||
if (backend->input_timestamps.manager) {
|
||||
struct zwp_input_timestamps_v1 *pointer_input_timestamps =
|
||||
zwp_input_timestamps_manager_v1_get_pointer_timestamps(
|
||||
backend->input_timestamps.manager, wl_pointer);
|
||||
zwp_input_timestamps_v1_add_listener(pointer_input_timestamps,
|
||||
&input_timestamps_listener, &backend->input_timestamps.pointer);
|
||||
}
|
||||
}
|
||||
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
||||
wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void*) wl_seat);
|
||||
|
|
@ -553,6 +643,14 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|||
if (backend->started) {
|
||||
create_wl_keyboard(wl_keyboard, backend);
|
||||
}
|
||||
|
||||
if (backend->input_timestamps.manager) {
|
||||
struct zwp_input_timestamps_v1 *keyboard_input_timestamps =
|
||||
zwp_input_timestamps_manager_v1_get_keyboard_timestamps(
|
||||
backend->input_timestamps.manager, wl_keyboard);
|
||||
zwp_input_timestamps_v1_add_listener(keyboard_input_timestamps,
|
||||
&input_timestamps_listener, &backend->input_timestamps.keyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue