AtlatestRepositorysigil-wm
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"15
struct 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
};24
static 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;29
}31
static 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;39
}41
static const struct wl_output_listener output_listener = {42
.geometry = geometry, .mode = mode,43
};45
static void capabilities(void *data, struct wl_seat *seat, uint32_t caps) {46
(void)data; (void)seat; (void)caps;47
}49
static const struct wl_seat_listener seat_listener = {.capabilities = capabilities};51
static 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;68
}70
static void global_remove(void *data, struct wl_registry *registry, uint32_t name) {71
(void)data; (void)registry; (void)name;72
}74
static const struct wl_registry_listener registry_listener = {75
.global = global, .global_remove = global_remove,76
};78
static uint32_t timestamp(void) {79
struct timespec now;80
clock_gettime(CLOCK_MONOTONIC, &now);81
return now.tv_sec * 1000 + now.tv_nsec / 1000000;82
}84
int 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, ®istry_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;207
}