summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Burakov <mburakov@mailbox.org>2023-04-07 12:31:59 +0200
committerMikhail Burakov <mburakov@mailbox.org>2023-04-07 13:48:45 +0200
commitd25bb30da26eefbe92cd1e59f7ee4b936c1afcec (patch)
tree8cf18f86deb8a1231b182929414128074f511742
parent779b65bc22e0463f42161f0e03fee2cef9b2d790 (diff)
Implement support for mouse events
-rw-r--r--.gitignore1
-rw-r--r--input.c68
-rw-r--r--input.h4
-rw-r--r--main.c24
-rw-r--r--makefile1
-rw-r--r--window.c73
-rw-r--r--window.h3
7 files changed, 165 insertions, 9 deletions
diff --git a/.gitignore b/.gitignore
index 2ca1a3c..d239d70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ compile_commands.json
compile_flags.txt
linux-dmabuf-unstable-v1.h
receiver
+relative-pointer-unstable-v1.h
xdg-shell.h
diff --git a/input.c b/input.c
index 9733236..3644ef0 100644
--- a/input.c
+++ b/input.c
@@ -18,6 +18,7 @@
#include "input.h"
#include <errno.h>
+#include <linux/input-event-codes.h>
#include <linux/uhid.h>
#include <stddef.h>
#include <stdint.h>
@@ -87,6 +88,7 @@ static const struct uhid_event uhid_event_create2 = {
struct InputStream {
int fd;
+ unsigned button_state;
uint64_t key_state[4];
};
@@ -172,7 +174,7 @@ bool InputStreamKeyPress(struct InputStream* input_stream, unsigned evdev_code,
uint64_t key_state_shift = evdev_code & 0x3f;
uint64_t key_state =
(input_stream->key_state[key_state_row] & ~(1ull << key_state_shift)) |
- ((uint64_t)(!!pressed) << key_state_shift);
+ (((uint64_t) !!pressed) << key_state_shift);
if (key_state == input_stream->key_state[key_state_row]) return true;
input_stream->key_state[key_state_row] = key_state;
@@ -183,6 +185,70 @@ bool InputStreamKeyPress(struct InputStream* input_stream, unsigned evdev_code,
return result;
}
+static size_t InputStreamFormatMouse(const struct InputStream* input_stream,
+ struct uhid_event* uhid_event, int dx,
+ int dy, int wheel) {
+ uhid_event->type = UHID_INPUT2;
+ uhid_event->u.input2.data[0] = 2;
+ uhid_event->u.input2.data[1] = input_stream->button_state & 0xff;
+ uhid_event->u.input2.data[2] = dx & 0xff;
+ uhid_event->u.input2.data[3] = dx >> 8 & 0xff;
+ uhid_event->u.input2.data[4] = dy & 0xff;
+ uhid_event->u.input2.data[5] = dy >> 8 & 0xff;
+ uhid_event->u.input2.data[6] = wheel & 0xff;
+ uhid_event->u.input2.size = 7;
+ return offsetof(struct uhid_event, u.input2.data) + uhid_event->u.input2.size;
+}
+
+bool InputStreamMouseMove(struct InputStream* input_stream, int dx, int dy) {
+ struct uhid_event uhid_event_input2;
+ size_t size =
+ InputStreamFormatMouse(input_stream, &uhid_event_input2, dx, dy, 0);
+ bool result = Drain(input_stream->fd, &uhid_event_input2, size);
+ if (!result) LOG("Failed to drain mousemove");
+ return result;
+}
+
+bool InputStreamMouseButton(struct InputStream* input_stream, unsigned button,
+ bool pressed) {
+ unsigned button_shift;
+ switch (button) {
+ case BTN_LEFT:
+ button_shift = 0;
+ break;
+ case BTN_RIGHT:
+ button_shift = 1;
+ break;
+ case BTN_MIDDLE:
+ button_shift = 2;
+ break;
+ default:
+ // mburakov: Ignore unknown buttons...
+ return true;
+ }
+
+ unsigned button_state = (input_stream->button_state & ~(1u << button_shift)) |
+ (((unsigned)!!pressed) << button_shift);
+ if (button_state == input_stream->button_state) return true;
+ input_stream->button_state = button_state;
+
+ struct uhid_event uhid_event_input2;
+ size_t size =
+ InputStreamFormatMouse(input_stream, &uhid_event_input2, 0, 0, 0);
+ bool result = Drain(input_stream->fd, &uhid_event_input2, size);
+ if (!result) LOG("Failed to drain mousebutton");
+ return result;
+}
+
+bool InputStreamMouseWheel(struct InputStream* input_stream, int delta) {
+ struct uhid_event uhid_event_input2;
+ size_t size =
+ InputStreamFormatMouse(input_stream, &uhid_event_input2, 0, 0, delta);
+ bool result = Drain(input_stream->fd, &uhid_event_input2, size);
+ if (!result) LOG("Failed to drain mousewheel");
+ return result;
+}
+
bool InputStreamHandsoff(struct InputStream* input_stream) {
memset(input_stream->key_state, 0, sizeof(input_stream->key_state));
static const struct uhid_event uhid_event_input2 = {
diff --git a/input.h b/input.h
index 1487b35..8bea32b 100644
--- a/input.h
+++ b/input.h
@@ -25,6 +25,10 @@ struct InputStream;
struct InputStream* InputStreamCreate(int fd);
bool InputStreamKeyPress(struct InputStream* input_stream, unsigned evdev_code,
bool pressed);
+bool InputStreamMouseMove(struct InputStream* input_stream, int dx, int dy);
+bool InputStreamMouseButton(struct InputStream* input_stream, unsigned button,
+ bool pressed);
+bool InputStreamMouseWheel(struct InputStream* input_stream, int delta);
bool InputStreamHandsoff(struct InputStream* input_stream);
void InputStreamDestroy(struct InputStream* input_stream);
diff --git a/main.c b/main.c
index cce66ae..b686980 100644
--- a/main.c
+++ b/main.c
@@ -98,6 +98,27 @@ static void OnWindowKey(void* user, unsigned key, bool pressed) {
}
}
+static void OnWindowMove(void* user, int dx, int dy) {
+ if (!InputStreamMouseMove(user, dx, dy)) {
+ LOG("Failed to handle mouse move");
+ g_signal = SIGABRT;
+ }
+}
+
+static void OnWindowButton(void* user, unsigned button, bool pressed) {
+ if (!InputStreamMouseButton(user, button, pressed)) {
+ LOG("Failed to handle mouse button");
+ g_signal = SIGABRT;
+ }
+}
+
+static void OnWindowWheel(void* user, int delta) {
+ if (!InputStreamMouseWheel(user, delta)) {
+ LOG("Failed to handle mouse wheel");
+ g_signal = SIGABRT;
+ }
+}
+
static void InputStreamDtor(struct InputStream** input_stream) {
if (!*input_stream) return;
InputStreamDestroy(*input_stream);
@@ -139,6 +160,9 @@ int main(int argc, char* argv[]) {
.OnClose = OnWindowClose,
.OnFocus = OnWindowFocus,
.OnKey = OnWindowKey,
+ .OnMove = OnWindowMove,
+ .OnButton = OnWindowButton,
+ .OnWheel = OnWindowWheel,
};
struct Window __attribute__((cleanup(WindowDtor)))* window =
WindowCreate(&window_event_handlers, input_stream);
diff --git a/makefile b/makefile
index 79a7e61..3ab97d7 100644
--- a/makefile
+++ b/makefile
@@ -16,6 +16,7 @@ protocols_dir:=\
protocols:=\
linux-dmabuf-unstable-v1 \
+ relative-pointer-unstable-v1 \
xdg-shell
obj:=$(patsubst %,%.o,$(protocols)) $(obj)
diff --git a/window.c b/window.c
index b7ae0ec..eb56dc4 100644
--- a/window.c
+++ b/window.c
@@ -26,6 +26,7 @@
#include "frame.h"
#include "linux-dmabuf-unstable-v1.h"
+#include "relative-pointer-unstable-v1.h"
#include "toolbox/utils.h"
#include "xdg-shell.h"
@@ -42,7 +43,9 @@ struct Window {
struct wl_keyboard* wl_keyboard;
struct xdg_wm_base* xdg_wm_base;
struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1;
+ struct zwp_relative_pointer_manager_v1* zwp_relative_pointer_manager_v1;
+ struct zwp_relative_pointer_v1* zwp_relative_pointer_v1;
struct xdg_surface* xdg_surface;
struct xdg_toplevel* xdg_toplevel;
struct wl_buffer** wl_buffers;
@@ -90,6 +93,15 @@ static void OnWlRegistryGlobal(void* data, struct wl_registry* wl_registry,
wl_registry, name, &zwp_linux_dmabuf_v1_interface, version);
if (!window->zwp_linux_dmabuf_v1)
LOG("Failed to bind zwp_linux_dmabuf_v1 (%s)", strerror(errno));
+
+ } else if (!strcmp(interface,
+ zwp_relative_pointer_manager_v1_interface.name)) {
+ window->zwp_relative_pointer_manager_v1 = wl_registry_bind(
+ wl_registry, name, &zwp_relative_pointer_manager_v1_interface, version);
+ if (!window->zwp_relative_pointer_manager_v1) {
+ LOG("Failed to bind zwp_relative_pointer_manager_v1 (%s)",
+ strerror(errno));
+ }
}
}
@@ -132,12 +144,11 @@ static void OnWlPointerMotion(void* data, struct wl_pointer* wl_pointer,
static void OnWlPointerButton(void* data, struct wl_pointer* wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t state) {
- (void)data;
(void)wl_pointer;
(void)serial;
(void)time;
- (void)button;
- (void)state;
+ struct Window* window = data;
+ window->event_handlers->OnButton(window->user, button, !!state);
}
static void OnWlPointerAxis(void* data, struct wl_pointer* wl_pointer,
@@ -179,10 +190,14 @@ static void OnWlPointerAxisDiscrete(void* data, struct wl_pointer* wl_pointer,
static void OnWlPointerAxisValue120(void* data, struct wl_pointer* wl_pointer,
uint32_t axis, int32_t value120) {
- (void)data;
(void)wl_pointer;
- (void)axis;
- (void)value120;
+ if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ // mburakov: Current code models regular one-wheeled mouse.
+ return;
+ }
+ struct Window* window = data;
+ // TODO(mburakov): Why minus is needed here?
+ window->event_handlers->OnWheel(window->user, -value120 / 120);
}
static void OnWlKeyboardKeymap(void* data, struct wl_keyboard* wl_keyboard,
@@ -252,6 +267,20 @@ static void OnXdgWmBasePing(void* data, struct xdg_wm_base* xdg_wm_base,
xdg_wm_base_pong(xdg_wm_base, serial);
}
+static void OnZwpRelativePointerMotion(
+ void* data, struct zwp_relative_pointer_v1* zwp_relative_pointer_v1,
+ uint32_t utime_hi, uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy,
+ wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) {
+ (void)zwp_relative_pointer_v1;
+ (void)utime_hi;
+ (void)utime_lo;
+ (void)dx;
+ (void)dy;
+ struct Window* window = data;
+ window->event_handlers->OnMove(window->user, wl_fixed_to_int(dx_unaccel),
+ wl_fixed_to_int(dy_unaccel));
+}
+
static void OnXdgSurfaceConfigure(void* data, struct xdg_surface* xdg_surface,
uint32_t serial) {
(void)data;
@@ -291,6 +320,7 @@ static void OnXdgToplevelWmCapabilities(void* data,
(void)xdg_toplevel;
(void)capabilities;
}
+
struct Window* WindowCreate(const struct WindowEventHandlers* event_handlers,
void* user) {
struct Window* window = malloc(sizeof(struct Window));
@@ -327,7 +357,8 @@ struct Window* WindowCreate(const struct WindowEventHandlers* event_handlers,
goto rollback_wl_registry;
}
if (!window->wl_surface || !window->wl_pointer || !window->wl_keyboard ||
- !window->xdg_wm_base || !window->zwp_linux_dmabuf_v1) {
+ !window->xdg_wm_base || !window->zwp_linux_dmabuf_v1 ||
+ !window->zwp_relative_pointer_manager_v1) {
LOG("Some wayland objects are missing");
goto rollback_globals;
}
@@ -371,11 +402,29 @@ struct Window* WindowCreate(const struct WindowEventHandlers* event_handlers,
goto rollback_globals;
}
+ window->zwp_relative_pointer_v1 =
+ zwp_relative_pointer_manager_v1_get_relative_pointer(
+ window->zwp_relative_pointer_manager_v1, window->wl_pointer);
+ if (!window->zwp_relative_pointer_v1) {
+ LOG("Failed to get zwp_relative_pointer_v1 (%s)", strerror(errno));
+ goto rollback_globals;
+ }
+ static const struct zwp_relative_pointer_v1_listener
+ zwp_relative_pointer_v1_listener = {
+ .relative_motion = OnZwpRelativePointerMotion,
+ };
+ if (zwp_relative_pointer_v1_add_listener(window->zwp_relative_pointer_v1,
+ &zwp_relative_pointer_v1_listener,
+ window)) {
+ LOG("Failed to add zwp_relative_pointer_v1 listener (%s)", strerror(errno));
+ goto rollback_zwp_relative_pointer_v1;
+ }
+
window->xdg_surface =
xdg_wm_base_get_xdg_surface(window->xdg_wm_base, window->wl_surface);
if (!window->xdg_surface) {
LOG("Failed to get xdg_surface (%s)", strerror(errno));
- goto rollback_globals;
+ goto rollback_zwp_relative_pointer_v1;
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = OnXdgSurfaceConfigure,
@@ -415,7 +464,13 @@ rollback_xdg_toplevel:
xdg_toplevel_destroy(window->xdg_toplevel);
rollback_xdg_surface:
xdg_surface_destroy(window->xdg_surface);
+rollback_zwp_relative_pointer_v1:
+ zwp_relative_pointer_v1_destroy(window->zwp_relative_pointer_v1);
rollback_globals:
+ if (window->zwp_relative_pointer_manager_v1) {
+ zwp_relative_pointer_manager_v1_destroy(
+ window->zwp_relative_pointer_manager_v1);
+ }
if (window->zwp_linux_dmabuf_v1)
zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1);
if (window->xdg_wm_base) xdg_wm_base_destroy(window->xdg_wm_base);
@@ -506,6 +561,8 @@ void WindowDestroy(struct Window* window) {
DestroyBuffers(window);
xdg_toplevel_destroy(window->xdg_toplevel);
xdg_surface_destroy(window->xdg_surface);
+ zwp_relative_pointer_manager_v1_destroy(
+ window->zwp_relative_pointer_manager_v1);
zwp_linux_dmabuf_v1_destroy(window->zwp_linux_dmabuf_v1);
xdg_wm_base_destroy(window->xdg_wm_base);
wl_keyboard_release(window->wl_keyboard);
diff --git a/window.h b/window.h
index 93c0ed0..cd6def7 100644
--- a/window.h
+++ b/window.h
@@ -28,6 +28,9 @@ struct WindowEventHandlers {
void (*OnClose)(void* user);
void (*OnFocus)(void* user, bool focused);
void (*OnKey)(void* user, unsigned key, bool pressed);
+ void (*OnMove)(void* user, int dx, int dy);
+ void (*OnButton)(void* user, unsigned button, bool pressed);
+ void (*OnWheel)(void* user, int delta);
};
struct Window* WindowCreate(