wip update
[nyanlinux.git] / files / x11keyautorepeat.c
blob39a6041eef21264ea8e08e31871a3c5d45cb90d7
1 /*
2 * code protected with a GNU affero GPLv3 license
3 * copyright (C) 2020 Sylvain BERTRAND
4 */
5 /*
6 * usage:
7 * "x11keyautorepeat" alone will turn off x11 global key repeat
8 * "x11keyautorepeat WHATEVER" will turn on x11 global key repeat
9 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <stdint.h>
13 #include <errno.h>
14 #include <string.h>
16 #include <unistd.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
20 * ABBREVIATIONS:
21 * addr : ADDRess
22 * auth : AUTHentication
23 * fd : File Descriptor
24 * fmt(s) : ForMaT(S)
25 * img(s) : IMaGe(S)
26 * max : MAXimum
27 * min : MINimum
28 * n : couNt
29 * num(S) : NUMber(S)
30 * recv : RECeiVe
31 * req(s) : REQuest(S)
32 * scr(s) : SCReen(S)
33 * so : SOcket
34 * sz : SiZe (usually a count of bytes)
35 * w(s) : Word(S) (32 bits)
37 #define u8 uint8_t
38 #define u16 uint16_t
39 #define u32 uint32_t
40 #define loop for(;;)
41 #define FATAL(fmt, ...) ({fprintf(stderr, fmt, ##__VA_ARGS__); exit(EXIT_FAILURE);})
42 #define POUT(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
43 #define PERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
45 static u8 *so_pathname = "/tmp/.X11-unix/X0";
46 static int so_fd;
48 #ifdef __GNUC__
49 #define PACKED __attribute__((packed))
50 #else
51 #error "missing C extension for packed structure declaration"
52 #endif
53 struct x11_setup {
54 u8 endian;
55 u8 unused0;
56 u16 major;
57 u16 minor;
58 u16 auth_name_sz;
59 u16 auth_data_sz;
60 u16 unused1;
61 } PACKED;
63 struct x11_setup_status_common {
64 u8 code;
65 u8 unused_or_reason_sz;
66 u16 major;
67 u16 minor;
68 u16 additional_data_ws_n;
69 } PACKED;
71 struct x11_change_keyboard_control_req {
72 u8 opcode;
73 u8 unused;
74 u16 req_ws_n;
75 u32 mask;
76 u8 auto_repeat_mode;
77 u8 pad[3];
78 } PACKED;
79 /* handle short write */
80 static void x11_write(void *data, u16 sz)
82 u8 *p;
83 size_t sent_bytes_n;
85 if (sz == 0)
86 return;
87 sent_bytes_n = 0;
88 p = data;
89 loop {
90 ssize_t r;
92 errno = 0;
93 r = write(so_fd, p, (size_t)sz - sent_bytes_n);
94 if (r == -1)
95 FATAL("error while sending %u bytes to the x11 server:%s\n", (int)((size_t)sz - sent_bytes_n), strerror(errno));
97 sent_bytes_n += (size_t)r;
98 if (sent_bytes_n == (size_t)sz)
99 break;
100 p += r;
103 /* handle short read */
104 static u16 x11_read(void *buf, u16 max_sz)
106 u8 *p;
107 size_t recv_bytes_n;
109 if (max_sz == 0)
110 return 0;
111 p = buf;
112 recv_bytes_n = 0;
113 loop {
114 ssize_t r;
116 errno = 0;
117 r = read(so_fd, p, (size_t)max_sz - recv_bytes_n);
118 if (r == -1)
119 FATAL("error while receiving %u bytes from the x11 server:%s\n", (int)((size_t)max_sz - recv_bytes_n), strerror(errno));
120 if (r == 0) /* no more data: 0-sized datagram, connection properly closed, end of file... */
121 break;
122 recv_bytes_n += (size_t)r;
123 if (recv_bytes_n == (size_t)max_sz)
124 break;
125 p += r;
127 return (u16)recv_bytes_n;
130 int main(int argc, u8 **argv)
132 int ri;
133 u16 r16;
134 struct sockaddr_un addr;
135 struct x11_setup x11_setup;
136 struct x11_setup_status_common x11_status;
137 u8 *additional_data;
138 struct x11_change_keyboard_control_req req;
140 close(0);
141 additional_data = 0;
143 errno = 0;
144 /* xserver expects a SOCK_STREAM socket */
145 ri = socket(AF_UNIX, SOCK_STREAM, 0);
146 if (ri == -1)
147 FATAL("unable to create a socket:%s\n", strerror(errno));
148 so_fd = ri;
150 memset(&addr, 0, sizeof(addr));
151 addr.sun_family = AF_UNIX;
152 strncpy(addr.sun_path, so_pathname, sizeof(addr.sun_path));
153 ri = connect(so_fd, (struct sockaddr*)&addr, sizeof(addr));
154 if (ri == -1)
155 FATAL("unable to connect the socket %d to address '%s':%s\n", so_fd, so_pathname, strerror(errno));
156 POUT("connected to unix socket '%s'\n", so_pathname);
157 /*--------------------------------------------------------------------*/
158 /* x11 setup */
159 memset(&x11_setup, 0, sizeof(x11_setup));
160 x11_setup.endian = 'l'; /* l-ittle endian or 'B'-ig endian */
161 x11_setup.major = 11; /* wayland is x12 */
163 x11_write(&x11_setup, sizeof(x11_setup));
164 POUT("x11 connection setup sent\n");
166 POUT("receiving x11 setup status common data...\n");
167 r16 = x11_read(&x11_status, sizeof(x11_status));
168 if (r16 != sizeof(x11_status))
169 FATAL("unable to get x11 setup status common data\n");
170 if (x11_status.additional_data_ws_n != 0) {
171 additional_data = realloc(additional_data, x11_status.additional_data_ws_n * 4);
172 if (additional_data == 0)
173 FATAL("unable to allocate memory to x11 setup status additional data\n");
174 POUT("receiving x11 setup status additional data, %u bytes...\n", x11_status.additional_data_ws_n * 4);
175 r16 = x11_read(additional_data, x11_status.additional_data_ws_n * 4);
176 if (r16 != (x11_status.additional_data_ws_n * 4))
177 FATAL("incomplete x11 setup status additional data\n");
180 if (x11_status.code == 0) {
181 POUT("x11 setup: failure\n");
182 if (x11_status.additional_data_ws_n != 0)
183 /* don't expect any string to end with '\0' */
184 FATAL("reason:%.*s\n", (int)x11_status.unused_or_reason_sz, additional_data);
185 FATAL("no failure reason provided\n");
188 free(additional_data);
189 additional_data = 0;
191 if (x11_status.code == 2)
192 FATAL("x11 setup: authentication is not supported\n");
193 if (x11_status.code != 1)
194 FATAL("x11 setup: unknown status code (0x%02x)\n", x11_status.code);
195 /* x11_status.code == 1 */
196 POUT("x11 setup success\n");
197 /*--------------------------------------------------------------------*/
198 /* change_keyboard_control req */
199 memset(&req, 0, sizeof(req));
200 req.opcode = 102;
201 req.req_ws_n = sizeof(req) / 4;
202 req.mask = 0x80; /* auto-repeat-mode */
203 if (argc > 1)
204 req.auto_repeat_mode = 1; /* 1 = on, 0 = off, 2 = default */
205 POUT("sending x11 change_keyboard_control request\n");
206 x11_write(&req, sizeof(req));
207 POUT("done\n");
208 exit(EXIT_SUCCESS);