Hook up mouse callbacks
This commit is contained in:
parent
d053e7daff
commit
a3f8043afa
2 changed files with 128 additions and 10 deletions
2
Makefile
2
Makefile
|
|
@ -1,6 +1,6 @@
|
||||||
INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
INTERFACEDIR:=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
||||||
CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter
|
CFLAGS=-Wall -Wextra -Og -ggdb3 -Wno-unused-but-set-variable -Wno-unused-parameter
|
||||||
LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL
|
LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL -lxkbcommon
|
||||||
wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h
|
wayland: wayland.c xdg-shell-protocol.c xdg-shell-client-protocol.h
|
||||||
gcc $(CFLAGS) $(LIBS) wayland.c xdg-shell-protocol.c -o wayland
|
gcc $(CFLAGS) $(LIBS) wayland.c xdg-shell-protocol.c -o wayland
|
||||||
xdg-shell-protocol.c:
|
xdg-shell-protocol.c:
|
||||||
|
|
|
||||||
128
wayland.c
128
wayland.c
|
|
@ -3,9 +3,12 @@
|
||||||
#include <wayland-egl.h>
|
#include <wayland-egl.h>
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
// Generated header using wayland-scanner
|
// Generated header using wayland-scanner
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
|
|
||||||
|
|
@ -16,13 +19,19 @@ struct xdg_wm_base *wm_base = NULL;
|
||||||
struct xdg_surface *xdg_surface = NULL;
|
struct xdg_surface *xdg_surface = NULL;
|
||||||
struct xdg_toplevel *xdg_toplevel = NULL;
|
struct xdg_toplevel *xdg_toplevel = NULL;
|
||||||
struct wl_egl_window *window = NULL;
|
struct wl_egl_window *window = NULL;
|
||||||
|
|
||||||
/* Input API */
|
/* Input API */
|
||||||
struct wl_seat *wl_seat = NULL;
|
struct wl_seat *wl_seat = NULL;
|
||||||
struct wl_keyboard *wl_keyboard = NULL;
|
struct wl_keyboard *wl_keyboard = NULL;
|
||||||
struct wl_pointer *wl_pointer = NULL;
|
struct wl_pointer *wl_pointer = NULL;
|
||||||
EGLBoolean errcode = 0;
|
|
||||||
|
/* XKB library */
|
||||||
|
struct xkb_context *xkb_context = NULL;
|
||||||
|
struct xkb_state *xkb_state = NULL;
|
||||||
|
struct xkb_keymap *xkb_keymap = NULL;
|
||||||
|
|
||||||
/* Misc. global state */
|
/* Misc. global state */
|
||||||
|
EGLBoolean errcode = 0;
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
char *egl_s(int code)
|
char *egl_s(int code)
|
||||||
|
|
@ -60,14 +69,15 @@ void registry_handle_global( void *data, struct wl_registry *registry,
|
||||||
fprintf(stdout, "Registering XDG WM base interface...\n");
|
fprintf(stdout, "Registering XDG WM base interface...\n");
|
||||||
wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
|
wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
|
||||||
}
|
}
|
||||||
|
/* NOTE: Since wl_seat v5, pointer events are grouped into "frames", which do not appear to be useful for non-touch applications and
|
||||||
|
also create more events which are more complicated to dispatch. */
|
||||||
if (!strcmp(interface, wl_seat_interface.name))
|
if (!strcmp(interface, wl_seat_interface.name))
|
||||||
{
|
{
|
||||||
fprintf(stdout, "Registering WL seat interface...\n");
|
fprintf(stdout, "Registering WL seat interface...\n");
|
||||||
wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
|
wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void registry_handle_global_remove(void *data, struct wl_registry *registry,
|
void registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||||
uint32_t name)
|
uint32_t name)
|
||||||
{
|
{
|
||||||
|
|
@ -103,10 +113,24 @@ void wayland_ping(void *data, struct xdg_wm_base *base, uint32_t serial)
|
||||||
xdg_wm_base_pong(base, serial);
|
xdg_wm_base_pong(base, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wl_seat_capabilities_callback(void *data, struct wl_seat *wl_seat, uint capabilities)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Capabilities changed for WL seat\n");
|
||||||
|
}
|
||||||
|
|
||||||
void keymap_callback(void *data, struct wl_keyboard *kb, uint format, int fd, uint size)
|
void keymap_callback(void *data, struct wl_keyboard *kb, uint format, int fd, uint size)
|
||||||
{
|
{
|
||||||
// TODO: Check for XKB compatibility and use xkbcommon to extract
|
// TODO: Check for XKB compatibility and use xkbcommon to extract
|
||||||
fprintf(stdout, "KBMAP of size %d detected\n", size);
|
fprintf(stdout, "KBMAP of size %d detected\n", size);
|
||||||
|
|
||||||
|
char *mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
fprintf(stdout, "XKBMAP desc:\n\t%s\n", mem);
|
||||||
|
xkb_keymap = xkb_keymap_new_from_string(xkb_context, mem, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
|
munmap(mem, size);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (!(xkb_state = xkb_state_new(xkb_keymap)))
|
||||||
|
fprintf(stderr, "Could not initialize XKB state machine\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void enter_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_surface* surface, struct wl_array *keys)
|
void enter_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_surface* surface, struct wl_array *keys)
|
||||||
|
|
@ -121,12 +145,27 @@ void leave_callback(void *data, struct wl_keyboard* kb, uint serial, struct wl_s
|
||||||
|
|
||||||
void key_callback(void *data, struct wl_keyboard *kb, uint serial, uint time, uint key, uint state)
|
void key_callback(void *data, struct wl_keyboard *kb, uint serial, uint time, uint key, uint state)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "Pressed key %d\n", key);
|
/* TODO: This does *not* respect the system's language defaults. At least not in KDE.
|
||||||
|
* Wayland's own (terrible) documentation does not go into detail about languages:
|
||||||
|
* https://wayland-book.com/seat/xkb.html
|
||||||
|
*/
|
||||||
|
key += 8;
|
||||||
|
uint32_t layout = xkb_state_key_get_layout(xkb_state, key);
|
||||||
|
if (layout >= xkb_keymap_num_layouts_for_key(xkb_keymap, key))
|
||||||
|
fprintf(stderr, "Layout %d exceeds number of available key layouts\n", layout);
|
||||||
|
|
||||||
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, key);
|
||||||
|
char keyname[128];
|
||||||
|
xkb_keysym_get_name(sym, keyname, sizeof(keyname));
|
||||||
|
char keyutf8[128];
|
||||||
|
xkb_state_key_get_utf8(xkb_state, key, keyutf8, sizeof(keyutf8));
|
||||||
|
fprintf(stdout, "%s key %d layout %d (KEYSYM %s) (UTF8 %s)\n", (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "Pressed" : "Released"), key, layout, keyname, keyutf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void modifier_callback(void *data, struct wl_keyboard *kb, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group)
|
void modifier_callback(void *data, struct wl_keyboard *kb, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "Keyboard modifier keys changed\n");
|
fprintf(stdout, "Keyboard modifier keys changed\n");
|
||||||
|
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int delay)
|
void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int delay)
|
||||||
|
|
@ -134,6 +173,56 @@ void repeat_info_callback(void *data, struct wl_keyboard *kb, int rate, int dela
|
||||||
fprintf(stdout, "Keyboard repeat/delay rate changed\n");
|
fprintf(stdout, "Keyboard repeat/delay rate changed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pointer_enter_callback(void *data, struct wl_pointer *pointer, uint serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer entered WL surface on coordinates %d %d\n", x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pointer_leave_callback(void *data, struct wl_pointer *pointer, uint serial, struct wl_surface *surface)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer left WL surface\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pointer_motion_callback(void *data, struct wl_pointer *pointer, uint time, wl_fixed_t x, wl_fixed_t y)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer moved to %d %d\n", x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pointer_button_callback(void *data, struct wl_pointer *pointer, uint serial, uint time, uint button, uint state)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer button %d changed state\n", button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pointer_axis_callback(void *data, struct wl_pointer *pointer, uint time, uint axis, wl_fixed_t value)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer scroll on axis %d value %d\n", axis, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: *some* events are logically grouped together. The frame event marks the boundary between groups of them. More info: https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_pointer */
|
||||||
|
|
||||||
|
void pointer_frame_callback(void *data, struct wl_pointer *frame)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer frame ended\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: This event is also used to group pointer events together. It specifies info about all events in its frame */
|
||||||
|
void pointer_axis_source_callback(void *data, struct wl_pointer *pointer, uint axis_source)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer axis source: %d\n", axis_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional event to implement kinetic scrolling */
|
||||||
|
void pointer_axis_stop_callback(void *data, struct wl_pointer *pointer, uint time, uint axis)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer axis stopped: %d\n", axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional event. Carries discrete scroll info after an 'axis' event */
|
||||||
|
void pointer_axis_discrete_callback(void *data, struct wl_pointer *pointer, uint axis, int discrete)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Pointer axis discrete step: %d\n", discrete);
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
fprintf(stdout, "Starting platform layer...\n");
|
fprintf(stdout, "Starting platform layer...\n");
|
||||||
|
|
@ -165,13 +254,19 @@ int main()
|
||||||
xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
|
xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
|
||||||
xdg_toplevel_set_title(xdg_toplevel, "Hi");
|
xdg_toplevel_set_title(xdg_toplevel, "Hi");
|
||||||
|
|
||||||
|
/* XKB library initialization */
|
||||||
|
xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
|
||||||
|
|
||||||
const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||||
.configure = xdg_toplevel_configure,
|
.configure = xdg_toplevel_configure,
|
||||||
.close = xdg_toplevel_close
|
.close = xdg_toplevel_close
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||||
.ping = wayland_ping
|
.ping = wayland_ping
|
||||||
};
|
};
|
||||||
|
|
||||||
if (xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL))
|
if (xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL))
|
||||||
fprintf(stderr, "Could not set XDG toplevel listener\n");
|
fprintf(stderr, "Could not set XDG toplevel listener\n");
|
||||||
if (xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL))
|
if (xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL))
|
||||||
|
|
@ -181,6 +276,13 @@ int main()
|
||||||
if (!(wl_pointer = wl_seat_get_pointer(wl_seat)))
|
if (!(wl_pointer = wl_seat_get_pointer(wl_seat)))
|
||||||
fprintf(stderr, "Could not get WL pointer\n");
|
fprintf(stderr, "Could not get WL pointer\n");
|
||||||
|
|
||||||
|
const struct wl_seat_listener wl_seat_listener = {
|
||||||
|
.capabilities = wl_seat_capabilities_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
if (wl_seat_add_listener(wl_seat, &wl_seat_listener, NULL))
|
||||||
|
fprintf(stderr, "Could not set WL seat listener\n");
|
||||||
|
|
||||||
/* NOTE: We have to define all available callbacks for the keyboard listener even if we are not interested in them:
|
/* NOTE: We have to define all available callbacks for the keyboard listener even if we are not interested in them:
|
||||||
https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 */
|
https://gitlab.freedesktop.org/wayland/wayland/-/issues/160 */
|
||||||
const struct wl_keyboard_listener wl_keyboard_listener = {
|
const struct wl_keyboard_listener wl_keyboard_listener = {
|
||||||
|
|
@ -191,8 +293,24 @@ int main()
|
||||||
.modifiers = modifier_callback,
|
.modifiers = modifier_callback,
|
||||||
.repeat_info = repeat_info_callback,
|
.repeat_info = repeat_info_callback,
|
||||||
};
|
};
|
||||||
wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL);
|
if (wl_keyboard_add_listener(wl_keyboard, &wl_keyboard_listener, NULL))
|
||||||
|
fprintf(stderr, "Could not set XKB keyboard listener\n");
|
||||||
|
|
||||||
|
// TODO: Apparently we are not setting opcode 10's callback?
|
||||||
|
const struct wl_pointer_listener wl_pointer_listener = {
|
||||||
|
.enter = pointer_enter_callback,
|
||||||
|
.leave = pointer_leave_callback,
|
||||||
|
.motion = pointer_motion_callback,
|
||||||
|
.button = pointer_button_callback,
|
||||||
|
.axis = pointer_axis_callback,
|
||||||
|
.frame = pointer_frame_callback,
|
||||||
|
.axis_source = pointer_axis_source_callback,
|
||||||
|
.axis_stop = pointer_axis_stop_callback,
|
||||||
|
.axis_discrete = pointer_axis_discrete_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
if (wl_pointer_add_listener(wl_pointer, &wl_pointer_listener, NULL))
|
||||||
|
fprintf(stderr, "Could not set WL pointer listener\n");
|
||||||
|
|
||||||
/* WL EGL initialization */
|
/* WL EGL initialization */
|
||||||
window = wl_egl_window_create(surface, 480, 460);
|
window = wl_egl_window_create(surface, 480, 460);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue