AtlatestRepositorysigil-wm

sigil-wm / tree / testinput-driver.c

1/* SPDX-License-Identifier: BSD-3-Clause */
2/* Keep input devices alive while a shell supervisor advances the test. */
3#include <stdbool.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <time.h>
9#include <unistd.h>
10#include <wayland-client.h>
11#include <xkbcommon/xkbcommon.h>
12#include "virtual-keyboard-unstable-v1-client-protocol.h"
13#include "wlr-virtual-pointer-unstable-v1-client-protocol.h"
15struct input {
16 struct wl_display *display;
17 struct wl_seat *seat;
18 struct wl_output *output;
19 struct zwp_virtual_keyboard_manager_v1 *keyboards;
20 struct zwlr_virtual_pointer_manager_v1 *pointers;
21 int width, height;
22};
24static void geometry(void *data, struct wl_output *output, int32_t x, int32_t y,
25 int32_t physical_width, int32_t physical_height, int32_t subpixel,
26 const char *make, const char *model, int32_t transform) {
27 (void)data; (void)output; (void)x; (void)y; (void)physical_width;
28 (void)physical_height; (void)subpixel; (void)make; (void)model; (void)transform;
31static void mode(void *data, struct wl_output *output, uint32_t flags,
32 int32_t width, int32_t height, int32_t refresh) {
33 struct input *input = data;
34 if (flags & WL_OUTPUT_MODE_CURRENT) {
35 input->width = width;
36 input->height = height;
37 }
38 (void)output; (void)refresh;
41static const struct wl_output_listener output_listener = {
42 .geometry = geometry, .mode = mode,
43};
45static void capabilities(void *data, struct wl_seat *seat, uint32_t caps) {
46 (void)data; (void)seat; (void)caps;
49static const struct wl_seat_listener seat_listener = {.capabilities = capabilities};
51static void global(void *data, struct wl_registry *registry, uint32_t name,
52 const char *interface, uint32_t version) {
53 struct input *input = data;
54 if (!strcmp(interface, "wl_seat")) {
55 input->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
56 wl_seat_add_listener(input->seat, &seat_listener, input);
57 } else if (!strcmp(interface, "wl_output") && !input->output) {
58 input->output = wl_registry_bind(registry, name, &wl_output_interface, 1);
59 wl_output_add_listener(input->output, &output_listener, input);
60 } else if (!strcmp(interface, "zwp_virtual_keyboard_manager_v1")) {
61 input->keyboards = wl_registry_bind(registry, name,
62 &zwp_virtual_keyboard_manager_v1_interface, 1);
63 } else if (!strcmp(interface, "zwlr_virtual_pointer_manager_v1")) {
64 input->pointers = wl_registry_bind(registry, name,
65 &zwlr_virtual_pointer_manager_v1_interface, 1);
66 }
67 (void)version;
70static void global_remove(void *data, struct wl_registry *registry, uint32_t name) {
71 (void)data; (void)registry; (void)name;
74static const struct wl_registry_listener registry_listener = {
75 .global = global, .global_remove = global_remove,
76};
78static uint32_t timestamp(void) {
79 struct timespec now;
80 clock_gettime(CLOCK_MONOTONIC, &now);
81 return now.tv_sec * 1000 + now.tv_nsec / 1000000;
84int main(void) {
85 struct input input = {0};
86 input.display = wl_display_connect(NULL);
87 if (!input.display) return 2;
88 struct wl_registry *registry = wl_display_get_registry(input.display);
89 wl_registry_add_listener(registry, &registry_listener, &input);
90 if (wl_display_roundtrip(input.display) < 0 ||
91 wl_display_roundtrip(input.display) < 0 || !input.seat ||
92 !input.keyboards || !input.pointers || !input.width || !input.height) return 3;
93 struct zwp_virtual_keyboard_v1 *keyboard =
94 zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(input.keyboards, input.seat);
95 struct zwlr_virtual_pointer_v1 *pointer =
96 zwlr_virtual_pointer_manager_v1_create_virtual_pointer(input.pointers, input.seat);
97 struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
98 struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, XKB_KEYMAP_COMPILE_NO_FLAGS);
99 if (!keymap) return 4;
100 char *text = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
101 xkb_mod_index_t alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
102 xkb_mod_index_t control = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
103 xkb_mod_index_t shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
104 xkb_mod_index_t logo = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO);
105 if (!text || alt >= 32 || control >= 32 || shift >= 32 || logo >= 32) return 5;
106 char filename[256];
107 snprintf(filename, sizeof(filename), "%s/keymap.XXXXXX", getenv("XDG_RUNTIME_DIR"));
108 int fd = mkstemp(filename);
109 if (fd < 0) return 6;
110 unlink(filename);
111 size_t size = strlen(text) + 1, offset = 0;
112 while (offset < size) {
113 ssize_t written = write(fd, text + offset, size - offset);
114 if (written <= 0) return 7;
115 offset += written;
116 }
117 zwp_virtual_keyboard_v1_keymap(keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fd, size);
118 close(fd);
119 free(text);
120 xkb_keymap_unref(keymap);
121 xkb_context_unref(context);
122 if (wl_display_roundtrip(input.display) < 0) return 8;
123 printf("INPUT_DEVICE_READY output=%dx%d\n", input.width, input.height);
124 fflush(stdout);
125 char line[128], operation[32];
126 int a, b;
127 unsigned sequence = 0;
128 while (fgets(line, sizeof(line), stdin)) {
129 a = b = 0;
130 if (sscanf(line, "%31s %d %d", operation, &a, &b) < 1) return 9;
131 uint32_t time = timestamp();
132 if(getenv("SIGIL_WM_INPUT_TIMESTAMPS")) {
133 struct timespec now;
134 clock_gettime(CLOCK_MONOTONIC,&now);
135 printf("INPUT_TIME=%u %lld command=%s",sequence+1,
136 (long long)now.tv_sec*1000000000+now.tv_nsec,line);
137 }
138 if (!strcmp(operation, "absolute") && a >= 0 && b >= 0) {
139 zwlr_virtual_pointer_v1_motion_absolute(pointer, time, a, b, input.width, input.height);
140 zwlr_virtual_pointer_v1_frame(pointer);
141 } else if (!strcmp(operation, "flood") && a>0 && a<=10000) {
142 for(int index=0;index<a;index++) {
143 zwp_virtual_keyboard_v1_modifiers(keyboard,index&1 ? 1u<<shift : 0,0,0,0);
144 zwp_virtual_keyboard_v1_key(keyboard,time,30,WL_KEYBOARD_KEY_STATE_PRESSED);
145 zwlr_virtual_pointer_v1_motion(pointer,time,wl_fixed_from_int(index&1 ? -1 : 1),0);
146 zwlr_virtual_pointer_v1_frame(pointer);
147 zwp_virtual_keyboard_v1_key(keyboard,time,30,WL_KEYBOARD_KEY_STATE_RELEASED);
148 }
149 zwp_virtual_keyboard_v1_modifiers(keyboard,0,0,0,0);
150 } else if (!strcmp(operation, "motion")) {
151 zwlr_virtual_pointer_v1_motion(pointer, time, wl_fixed_from_int(a), wl_fixed_from_int(b));
152 zwlr_virtual_pointer_v1_frame(pointer);
153 } else if (!strcmp(operation, "relative")) {
154 /* Deterministic time (ms) and raw 24.8 fixed-point deltas. */
155 uint32_t given_time;
156 if (sscanf(line, "%*s %d %d %u", &a, &b, &given_time) != 3) return 12;
157 zwlr_virtual_pointer_v1_motion(pointer, given_time, a, b);
158 zwlr_virtual_pointer_v1_frame(pointer);
159 } else if (!strcmp(operation, "button") && a >= 272 && a < 288 && (b == 0 || b == 1)) {
160 zwlr_virtual_pointer_v1_button(pointer, time, a, b);
161 zwlr_virtual_pointer_v1_frame(pointer);
162 } else if (!strcmp(operation, "alt") && (a == 0 || a == 1)) {
163 zwp_virtual_keyboard_v1_modifiers(keyboard, a ? 1u << alt : 0, 0, 0, 0);
164 } else if (!strcmp(operation, "group") && a >= 0 && a < 4) {
165 zwp_virtual_keyboard_v1_modifiers(keyboard, 0, 0, 0, a);
166 } else if (!strcmp(operation, "mods") && a >= 0 && a < 256) {
167 /* wlroots modifier bits: 1 Shift, 4 Control, 8 Alt, 64 Super. */
168 uint32_t depressed = ((a & 1) ? 1u << shift : 0) | ((a & 4) ? 1u << control : 0) |
169 ((a & 8) ? 1u << alt : 0) | ((a & 64) ? 1u << logo : 0);
170 zwp_virtual_keyboard_v1_modifiers(keyboard, depressed, 0, 0, 0);
171 } else if (!strcmp(operation, "press") && a > 0 && a < 256) {
172 zwp_virtual_keyboard_v1_key(keyboard, time, a, WL_KEYBOARD_KEY_STATE_PRESSED);
173 } else if (!strcmp(operation, "release") && a > 0 && a < 256) {
174 zwp_virtual_keyboard_v1_key(keyboard, time, a, WL_KEYBOARD_KEY_STATE_RELEASED);
175 } else if (!strcmp(operation, "key") && a > 0 && a < 256) {
176 zwp_virtual_keyboard_v1_key(keyboard, time, a, WL_KEYBOARD_KEY_STATE_PRESSED);
177 zwp_virtual_keyboard_v1_key(keyboard, time, a, WL_KEYBOARD_KEY_STATE_RELEASED);
178 } else if (!strcmp(operation, "paste")) {
179 zwp_virtual_keyboard_v1_modifiers(keyboard,
180 (1u << control) | (1u << shift), 0, 0, 0);
181 zwp_virtual_keyboard_v1_key(keyboard, time, 47, WL_KEYBOARD_KEY_STATE_PRESSED);
182 zwp_virtual_keyboard_v1_key(keyboard, time, 47, WL_KEYBOARD_KEY_STATE_RELEASED);
183 zwp_virtual_keyboard_v1_modifiers(keyboard, 0, 0, 0, 0);
184 } else if (!strcmp(operation, "quit")) {
185 zwp_virtual_keyboard_v1_key(keyboard, time, 1, WL_KEYBOARD_KEY_STATE_PRESSED);
186 wl_display_flush(input.display);
187 while (wl_display_dispatch(input.display) >= 0) {}
188 puts("INPUT_QUIT_SENT");
189 wl_display_disconnect(input.display);
190 return 0;
191 } else {
192 fprintf(stderr, "unknown input command: %s", line);
193 return 10;
194 }
195 if (wl_display_roundtrip(input.display) < 0) return 11;
196 printf("INPUT_SENT=%s", line);
197 printf("INPUT_ACK=%u\n", ++sequence);
198 if(getenv("SIGIL_WM_INPUT_TIMESTAMPS")) {
199 struct timespec now;
200 clock_gettime(CLOCK_MONOTONIC,&now);
201 printf("INPUT_ACK_TIME=%u %lld\n",sequence,
202 (long long)now.tv_sec*1000000000+now.tv_nsec);
203 }
204 fflush(stdout);
205 }
206 return 12;