xref: /aosp_15_r20/external/libxkbcommon/tools/interactive-x11.c (revision 2b949d0487e80d67f1fda82db69e101e761f8064)
1*2b949d04SAndroid Build Coastguard Worker /*
2*2b949d04SAndroid Build Coastguard Worker  * Copyright © 2013 Ran Benita <[email protected]>
3*2b949d04SAndroid Build Coastguard Worker  *
4*2b949d04SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*2b949d04SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*2b949d04SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*2b949d04SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*2b949d04SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*2b949d04SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*2b949d04SAndroid Build Coastguard Worker  *
11*2b949d04SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*2b949d04SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*2b949d04SAndroid Build Coastguard Worker  * Software.
14*2b949d04SAndroid Build Coastguard Worker  *
15*2b949d04SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2b949d04SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2b949d04SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*2b949d04SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2b949d04SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*2b949d04SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*2b949d04SAndroid Build Coastguard Worker  * DEALINGS IN THE SOFTWARE.
22*2b949d04SAndroid Build Coastguard Worker  */
23*2b949d04SAndroid Build Coastguard Worker 
24*2b949d04SAndroid Build Coastguard Worker #include "config.h"
25*2b949d04SAndroid Build Coastguard Worker 
26*2b949d04SAndroid Build Coastguard Worker #include <locale.h>
27*2b949d04SAndroid Build Coastguard Worker #include <stdbool.h>
28*2b949d04SAndroid Build Coastguard Worker #include <stdlib.h>
29*2b949d04SAndroid Build Coastguard Worker #include <string.h>
30*2b949d04SAndroid Build Coastguard Worker 
31*2b949d04SAndroid Build Coastguard Worker #include <xcb/xkb.h>
32*2b949d04SAndroid Build Coastguard Worker 
33*2b949d04SAndroid Build Coastguard Worker #include "xkbcommon/xkbcommon-x11.h"
34*2b949d04SAndroid Build Coastguard Worker #include "tools-common.h"
35*2b949d04SAndroid Build Coastguard Worker 
36*2b949d04SAndroid Build Coastguard Worker /*
37*2b949d04SAndroid Build Coastguard Worker  * Note: This program only handles the core keyboard device for now.
38*2b949d04SAndroid Build Coastguard Worker  * It should be straigtforward to change struct keyboard to a list of
39*2b949d04SAndroid Build Coastguard Worker  * keyboards with device IDs, as in tools/interactive-evdev.c. This would
40*2b949d04SAndroid Build Coastguard Worker  * require:
41*2b949d04SAndroid Build Coastguard Worker  *
42*2b949d04SAndroid Build Coastguard Worker  * - Initially listing the keyboard devices.
43*2b949d04SAndroid Build Coastguard Worker  * - Listening to device changes.
44*2b949d04SAndroid Build Coastguard Worker  * - Matching events to their devices.
45*2b949d04SAndroid Build Coastguard Worker  *
46*2b949d04SAndroid Build Coastguard Worker  * XKB itself knows about xinput1 devices, and most requests and events are
47*2b949d04SAndroid Build Coastguard Worker  * device-specific.
48*2b949d04SAndroid Build Coastguard Worker  *
49*2b949d04SAndroid Build Coastguard Worker  * In order to list the devices and react to changes, you need xinput1/2.
50*2b949d04SAndroid Build Coastguard Worker  * You also need xinput for the key press/release event, since the core
51*2b949d04SAndroid Build Coastguard Worker  * protocol key press event does not carry a device ID to match on.
52*2b949d04SAndroid Build Coastguard Worker  */
53*2b949d04SAndroid Build Coastguard Worker 
54*2b949d04SAndroid Build Coastguard Worker struct keyboard {
55*2b949d04SAndroid Build Coastguard Worker     xcb_connection_t *conn;
56*2b949d04SAndroid Build Coastguard Worker     uint8_t first_xkb_event;
57*2b949d04SAndroid Build Coastguard Worker     struct xkb_context *ctx;
58*2b949d04SAndroid Build Coastguard Worker 
59*2b949d04SAndroid Build Coastguard Worker     struct xkb_keymap *keymap;
60*2b949d04SAndroid Build Coastguard Worker     struct xkb_state *state;
61*2b949d04SAndroid Build Coastguard Worker     int32_t device_id;
62*2b949d04SAndroid Build Coastguard Worker };
63*2b949d04SAndroid Build Coastguard Worker 
64*2b949d04SAndroid Build Coastguard Worker static bool terminate;
65*2b949d04SAndroid Build Coastguard Worker 
66*2b949d04SAndroid Build Coastguard Worker static int
select_xkb_events_for_device(xcb_connection_t * conn,int32_t device_id)67*2b949d04SAndroid Build Coastguard Worker select_xkb_events_for_device(xcb_connection_t *conn, int32_t device_id)
68*2b949d04SAndroid Build Coastguard Worker {
69*2b949d04SAndroid Build Coastguard Worker     enum {
70*2b949d04SAndroid Build Coastguard Worker         required_events =
71*2b949d04SAndroid Build Coastguard Worker             (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
72*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
73*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_EVENT_TYPE_STATE_NOTIFY),
74*2b949d04SAndroid Build Coastguard Worker 
75*2b949d04SAndroid Build Coastguard Worker         required_nkn_details =
76*2b949d04SAndroid Build Coastguard Worker             (XCB_XKB_NKN_DETAIL_KEYCODES),
77*2b949d04SAndroid Build Coastguard Worker 
78*2b949d04SAndroid Build Coastguard Worker         required_map_parts =
79*2b949d04SAndroid Build Coastguard Worker             (XCB_XKB_MAP_PART_KEY_TYPES |
80*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_KEY_SYMS |
81*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_MODIFIER_MAP |
82*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
83*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_KEY_ACTIONS |
84*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_VIRTUAL_MODS |
85*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP),
86*2b949d04SAndroid Build Coastguard Worker 
87*2b949d04SAndroid Build Coastguard Worker         required_state_details =
88*2b949d04SAndroid Build Coastguard Worker             (XCB_XKB_STATE_PART_MODIFIER_BASE |
89*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_STATE_PART_MODIFIER_LATCH |
90*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_STATE_PART_MODIFIER_LOCK |
91*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_STATE_PART_GROUP_BASE |
92*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_STATE_PART_GROUP_LATCH |
93*2b949d04SAndroid Build Coastguard Worker              XCB_XKB_STATE_PART_GROUP_LOCK),
94*2b949d04SAndroid Build Coastguard Worker     };
95*2b949d04SAndroid Build Coastguard Worker 
96*2b949d04SAndroid Build Coastguard Worker     static const xcb_xkb_select_events_details_t details = {
97*2b949d04SAndroid Build Coastguard Worker         .affectNewKeyboard = required_nkn_details,
98*2b949d04SAndroid Build Coastguard Worker         .newKeyboardDetails = required_nkn_details,
99*2b949d04SAndroid Build Coastguard Worker         .affectState = required_state_details,
100*2b949d04SAndroid Build Coastguard Worker         .stateDetails = required_state_details,
101*2b949d04SAndroid Build Coastguard Worker     };
102*2b949d04SAndroid Build Coastguard Worker 
103*2b949d04SAndroid Build Coastguard Worker     xcb_void_cookie_t cookie =
104*2b949d04SAndroid Build Coastguard Worker         xcb_xkb_select_events_aux_checked(conn,
105*2b949d04SAndroid Build Coastguard Worker                                           device_id,
106*2b949d04SAndroid Build Coastguard Worker                                           required_events,    /* affectWhich */
107*2b949d04SAndroid Build Coastguard Worker                                           0,                  /* clear */
108*2b949d04SAndroid Build Coastguard Worker                                           0,                  /* selectAll */
109*2b949d04SAndroid Build Coastguard Worker                                           required_map_parts, /* affectMap */
110*2b949d04SAndroid Build Coastguard Worker                                           required_map_parts, /* map */
111*2b949d04SAndroid Build Coastguard Worker                                           &details);          /* details */
112*2b949d04SAndroid Build Coastguard Worker 
113*2b949d04SAndroid Build Coastguard Worker     xcb_generic_error_t *error = xcb_request_check(conn, cookie);
114*2b949d04SAndroid Build Coastguard Worker     if (error) {
115*2b949d04SAndroid Build Coastguard Worker         free(error);
116*2b949d04SAndroid Build Coastguard Worker         return -1;
117*2b949d04SAndroid Build Coastguard Worker     }
118*2b949d04SAndroid Build Coastguard Worker 
119*2b949d04SAndroid Build Coastguard Worker     return 0;
120*2b949d04SAndroid Build Coastguard Worker }
121*2b949d04SAndroid Build Coastguard Worker 
122*2b949d04SAndroid Build Coastguard Worker static int
update_keymap(struct keyboard * kbd)123*2b949d04SAndroid Build Coastguard Worker update_keymap(struct keyboard *kbd)
124*2b949d04SAndroid Build Coastguard Worker {
125*2b949d04SAndroid Build Coastguard Worker     struct xkb_keymap *new_keymap;
126*2b949d04SAndroid Build Coastguard Worker     struct xkb_state *new_state;
127*2b949d04SAndroid Build Coastguard Worker 
128*2b949d04SAndroid Build Coastguard Worker     new_keymap = xkb_x11_keymap_new_from_device(kbd->ctx, kbd->conn,
129*2b949d04SAndroid Build Coastguard Worker                                                 kbd->device_id,
130*2b949d04SAndroid Build Coastguard Worker                                                 XKB_KEYMAP_COMPILE_NO_FLAGS);
131*2b949d04SAndroid Build Coastguard Worker     if (!new_keymap)
132*2b949d04SAndroid Build Coastguard Worker         goto err_out;
133*2b949d04SAndroid Build Coastguard Worker 
134*2b949d04SAndroid Build Coastguard Worker     new_state = xkb_x11_state_new_from_device(new_keymap, kbd->conn,
135*2b949d04SAndroid Build Coastguard Worker                                               kbd->device_id);
136*2b949d04SAndroid Build Coastguard Worker     if (!new_state)
137*2b949d04SAndroid Build Coastguard Worker         goto err_keymap;
138*2b949d04SAndroid Build Coastguard Worker 
139*2b949d04SAndroid Build Coastguard Worker     if (kbd->keymap)
140*2b949d04SAndroid Build Coastguard Worker         printf("Keymap updated!\n");
141*2b949d04SAndroid Build Coastguard Worker 
142*2b949d04SAndroid Build Coastguard Worker     xkb_state_unref(kbd->state);
143*2b949d04SAndroid Build Coastguard Worker     xkb_keymap_unref(kbd->keymap);
144*2b949d04SAndroid Build Coastguard Worker     kbd->keymap = new_keymap;
145*2b949d04SAndroid Build Coastguard Worker     kbd->state = new_state;
146*2b949d04SAndroid Build Coastguard Worker     return 0;
147*2b949d04SAndroid Build Coastguard Worker 
148*2b949d04SAndroid Build Coastguard Worker err_keymap:
149*2b949d04SAndroid Build Coastguard Worker     xkb_keymap_unref(new_keymap);
150*2b949d04SAndroid Build Coastguard Worker err_out:
151*2b949d04SAndroid Build Coastguard Worker     return -1;
152*2b949d04SAndroid Build Coastguard Worker }
153*2b949d04SAndroid Build Coastguard Worker 
154*2b949d04SAndroid Build Coastguard Worker static int
init_kbd(struct keyboard * kbd,xcb_connection_t * conn,uint8_t first_xkb_event,int32_t device_id,struct xkb_context * ctx)155*2b949d04SAndroid Build Coastguard Worker init_kbd(struct keyboard *kbd, xcb_connection_t *conn, uint8_t first_xkb_event,
156*2b949d04SAndroid Build Coastguard Worker          int32_t device_id, struct xkb_context *ctx)
157*2b949d04SAndroid Build Coastguard Worker {
158*2b949d04SAndroid Build Coastguard Worker     int ret;
159*2b949d04SAndroid Build Coastguard Worker 
160*2b949d04SAndroid Build Coastguard Worker     kbd->conn = conn;
161*2b949d04SAndroid Build Coastguard Worker     kbd->first_xkb_event = first_xkb_event;
162*2b949d04SAndroid Build Coastguard Worker     kbd->ctx = ctx;
163*2b949d04SAndroid Build Coastguard Worker     kbd->keymap = NULL;
164*2b949d04SAndroid Build Coastguard Worker     kbd->state = NULL;
165*2b949d04SAndroid Build Coastguard Worker     kbd->device_id = device_id;
166*2b949d04SAndroid Build Coastguard Worker 
167*2b949d04SAndroid Build Coastguard Worker     ret = update_keymap(kbd);
168*2b949d04SAndroid Build Coastguard Worker     if (ret)
169*2b949d04SAndroid Build Coastguard Worker         goto err_out;
170*2b949d04SAndroid Build Coastguard Worker 
171*2b949d04SAndroid Build Coastguard Worker     ret = select_xkb_events_for_device(conn, device_id);
172*2b949d04SAndroid Build Coastguard Worker     if (ret)
173*2b949d04SAndroid Build Coastguard Worker         goto err_state;
174*2b949d04SAndroid Build Coastguard Worker 
175*2b949d04SAndroid Build Coastguard Worker     return 0;
176*2b949d04SAndroid Build Coastguard Worker 
177*2b949d04SAndroid Build Coastguard Worker err_state:
178*2b949d04SAndroid Build Coastguard Worker     xkb_state_unref(kbd->state);
179*2b949d04SAndroid Build Coastguard Worker     xkb_keymap_unref(kbd->keymap);
180*2b949d04SAndroid Build Coastguard Worker err_out:
181*2b949d04SAndroid Build Coastguard Worker     return -1;
182*2b949d04SAndroid Build Coastguard Worker }
183*2b949d04SAndroid Build Coastguard Worker 
184*2b949d04SAndroid Build Coastguard Worker static void
deinit_kbd(struct keyboard * kbd)185*2b949d04SAndroid Build Coastguard Worker deinit_kbd(struct keyboard *kbd)
186*2b949d04SAndroid Build Coastguard Worker {
187*2b949d04SAndroid Build Coastguard Worker     xkb_state_unref(kbd->state);
188*2b949d04SAndroid Build Coastguard Worker     xkb_keymap_unref(kbd->keymap);
189*2b949d04SAndroid Build Coastguard Worker }
190*2b949d04SAndroid Build Coastguard Worker 
191*2b949d04SAndroid Build Coastguard Worker static void
process_xkb_event(xcb_generic_event_t * gevent,struct keyboard * kbd)192*2b949d04SAndroid Build Coastguard Worker process_xkb_event(xcb_generic_event_t *gevent, struct keyboard *kbd)
193*2b949d04SAndroid Build Coastguard Worker {
194*2b949d04SAndroid Build Coastguard Worker     union xkb_event {
195*2b949d04SAndroid Build Coastguard Worker         struct {
196*2b949d04SAndroid Build Coastguard Worker             uint8_t response_type;
197*2b949d04SAndroid Build Coastguard Worker             uint8_t xkbType;
198*2b949d04SAndroid Build Coastguard Worker             uint16_t sequence;
199*2b949d04SAndroid Build Coastguard Worker             xcb_timestamp_t time;
200*2b949d04SAndroid Build Coastguard Worker             uint8_t deviceID;
201*2b949d04SAndroid Build Coastguard Worker         } any;
202*2b949d04SAndroid Build Coastguard Worker         xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
203*2b949d04SAndroid Build Coastguard Worker         xcb_xkb_map_notify_event_t map_notify;
204*2b949d04SAndroid Build Coastguard Worker         xcb_xkb_state_notify_event_t state_notify;
205*2b949d04SAndroid Build Coastguard Worker     } *event = (union xkb_event *) gevent;
206*2b949d04SAndroid Build Coastguard Worker 
207*2b949d04SAndroid Build Coastguard Worker     if (event->any.deviceID != kbd->device_id)
208*2b949d04SAndroid Build Coastguard Worker         return;
209*2b949d04SAndroid Build Coastguard Worker 
210*2b949d04SAndroid Build Coastguard Worker     /*
211*2b949d04SAndroid Build Coastguard Worker      * XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap
212*2b949d04SAndroid Build Coastguard Worker      * updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent
213*2b949d04SAndroid Build Coastguard Worker      * recompilations.
214*2b949d04SAndroid Build Coastguard Worker      */
215*2b949d04SAndroid Build Coastguard Worker     switch (event->any.xkbType) {
216*2b949d04SAndroid Build Coastguard Worker     case XCB_XKB_NEW_KEYBOARD_NOTIFY:
217*2b949d04SAndroid Build Coastguard Worker         if (event->new_keyboard_notify.changed & XCB_XKB_NKN_DETAIL_KEYCODES)
218*2b949d04SAndroid Build Coastguard Worker             update_keymap(kbd);
219*2b949d04SAndroid Build Coastguard Worker         break;
220*2b949d04SAndroid Build Coastguard Worker 
221*2b949d04SAndroid Build Coastguard Worker     case XCB_XKB_MAP_NOTIFY:
222*2b949d04SAndroid Build Coastguard Worker         update_keymap(kbd);
223*2b949d04SAndroid Build Coastguard Worker         break;
224*2b949d04SAndroid Build Coastguard Worker 
225*2b949d04SAndroid Build Coastguard Worker     case XCB_XKB_STATE_NOTIFY:
226*2b949d04SAndroid Build Coastguard Worker         xkb_state_update_mask(kbd->state,
227*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.baseMods,
228*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.latchedMods,
229*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.lockedMods,
230*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.baseGroup,
231*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.latchedGroup,
232*2b949d04SAndroid Build Coastguard Worker                               event->state_notify.lockedGroup);
233*2b949d04SAndroid Build Coastguard Worker         break;
234*2b949d04SAndroid Build Coastguard Worker     }
235*2b949d04SAndroid Build Coastguard Worker }
236*2b949d04SAndroid Build Coastguard Worker 
237*2b949d04SAndroid Build Coastguard Worker static void
process_event(xcb_generic_event_t * gevent,struct keyboard * kbd)238*2b949d04SAndroid Build Coastguard Worker process_event(xcb_generic_event_t *gevent, struct keyboard *kbd)
239*2b949d04SAndroid Build Coastguard Worker {
240*2b949d04SAndroid Build Coastguard Worker     switch (gevent->response_type) {
241*2b949d04SAndroid Build Coastguard Worker     case XCB_KEY_PRESS: {
242*2b949d04SAndroid Build Coastguard Worker         xcb_key_press_event_t *event = (xcb_key_press_event_t *) gevent;
243*2b949d04SAndroid Build Coastguard Worker         xkb_keycode_t keycode = event->detail;
244*2b949d04SAndroid Build Coastguard Worker 
245*2b949d04SAndroid Build Coastguard Worker         tools_print_keycode_state(kbd->state, NULL, keycode,
246*2b949d04SAndroid Build Coastguard Worker                                   XKB_CONSUMED_MODE_XKB);
247*2b949d04SAndroid Build Coastguard Worker 
248*2b949d04SAndroid Build Coastguard Worker         /* Exit on ESC. */
249*2b949d04SAndroid Build Coastguard Worker         if (xkb_state_key_get_one_sym(kbd->state, keycode) == XKB_KEY_Escape)
250*2b949d04SAndroid Build Coastguard Worker             terminate = true;
251*2b949d04SAndroid Build Coastguard Worker         break;
252*2b949d04SAndroid Build Coastguard Worker     }
253*2b949d04SAndroid Build Coastguard Worker     default:
254*2b949d04SAndroid Build Coastguard Worker         if (gevent->response_type == kbd->first_xkb_event)
255*2b949d04SAndroid Build Coastguard Worker             process_xkb_event(gevent, kbd);
256*2b949d04SAndroid Build Coastguard Worker         break;
257*2b949d04SAndroid Build Coastguard Worker     }
258*2b949d04SAndroid Build Coastguard Worker }
259*2b949d04SAndroid Build Coastguard Worker 
260*2b949d04SAndroid Build Coastguard Worker static int
loop(xcb_connection_t * conn,struct keyboard * kbd)261*2b949d04SAndroid Build Coastguard Worker loop(xcb_connection_t *conn, struct keyboard *kbd)
262*2b949d04SAndroid Build Coastguard Worker {
263*2b949d04SAndroid Build Coastguard Worker     while (!terminate) {
264*2b949d04SAndroid Build Coastguard Worker         xcb_generic_event_t *event;
265*2b949d04SAndroid Build Coastguard Worker 
266*2b949d04SAndroid Build Coastguard Worker         switch (xcb_connection_has_error(conn)) {
267*2b949d04SAndroid Build Coastguard Worker         case 0:
268*2b949d04SAndroid Build Coastguard Worker             break;
269*2b949d04SAndroid Build Coastguard Worker         case XCB_CONN_ERROR:
270*2b949d04SAndroid Build Coastguard Worker             fprintf(stderr,
271*2b949d04SAndroid Build Coastguard Worker                     "Closed connection to X server: connection error\n");
272*2b949d04SAndroid Build Coastguard Worker             return -1;
273*2b949d04SAndroid Build Coastguard Worker         case XCB_CONN_CLOSED_EXT_NOTSUPPORTED:
274*2b949d04SAndroid Build Coastguard Worker             fprintf(stderr,
275*2b949d04SAndroid Build Coastguard Worker                     "Closed connection to X server: extension not supported\n");
276*2b949d04SAndroid Build Coastguard Worker             return -1;
277*2b949d04SAndroid Build Coastguard Worker         default:
278*2b949d04SAndroid Build Coastguard Worker             fprintf(stderr,
279*2b949d04SAndroid Build Coastguard Worker                     "Closed connection to X server: error code %d\n",
280*2b949d04SAndroid Build Coastguard Worker                     xcb_connection_has_error(conn));
281*2b949d04SAndroid Build Coastguard Worker             return -1;
282*2b949d04SAndroid Build Coastguard Worker         }
283*2b949d04SAndroid Build Coastguard Worker 
284*2b949d04SAndroid Build Coastguard Worker         event = xcb_wait_for_event(conn);
285*2b949d04SAndroid Build Coastguard Worker         if (!event) {
286*2b949d04SAndroid Build Coastguard Worker             continue;
287*2b949d04SAndroid Build Coastguard Worker         }
288*2b949d04SAndroid Build Coastguard Worker 
289*2b949d04SAndroid Build Coastguard Worker         process_event(event, kbd);
290*2b949d04SAndroid Build Coastguard Worker         free(event);
291*2b949d04SAndroid Build Coastguard Worker     }
292*2b949d04SAndroid Build Coastguard Worker 
293*2b949d04SAndroid Build Coastguard Worker     return 0;
294*2b949d04SAndroid Build Coastguard Worker }
295*2b949d04SAndroid Build Coastguard Worker 
296*2b949d04SAndroid Build Coastguard Worker static int
create_capture_window(xcb_connection_t * conn)297*2b949d04SAndroid Build Coastguard Worker create_capture_window(xcb_connection_t *conn)
298*2b949d04SAndroid Build Coastguard Worker {
299*2b949d04SAndroid Build Coastguard Worker     xcb_generic_error_t *error;
300*2b949d04SAndroid Build Coastguard Worker     xcb_void_cookie_t cookie;
301*2b949d04SAndroid Build Coastguard Worker     xcb_screen_t *screen =
302*2b949d04SAndroid Build Coastguard Worker         xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
303*2b949d04SAndroid Build Coastguard Worker     xcb_window_t window = xcb_generate_id(conn);
304*2b949d04SAndroid Build Coastguard Worker     uint32_t values[2] = {
305*2b949d04SAndroid Build Coastguard Worker         screen->white_pixel,
306*2b949d04SAndroid Build Coastguard Worker         XCB_EVENT_MASK_KEY_PRESS,
307*2b949d04SAndroid Build Coastguard Worker     };
308*2b949d04SAndroid Build Coastguard Worker 
309*2b949d04SAndroid Build Coastguard Worker     cookie = xcb_create_window_checked(conn, XCB_COPY_FROM_PARENT,
310*2b949d04SAndroid Build Coastguard Worker                                        window, screen->root,
311*2b949d04SAndroid Build Coastguard Worker                                        10, 10, 100, 100, 1,
312*2b949d04SAndroid Build Coastguard Worker                                        XCB_WINDOW_CLASS_INPUT_OUTPUT,
313*2b949d04SAndroid Build Coastguard Worker                                        screen->root_visual,
314*2b949d04SAndroid Build Coastguard Worker                                        XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
315*2b949d04SAndroid Build Coastguard Worker                                        values);
316*2b949d04SAndroid Build Coastguard Worker     if ((error = xcb_request_check(conn, cookie)) != NULL) {
317*2b949d04SAndroid Build Coastguard Worker         free(error);
318*2b949d04SAndroid Build Coastguard Worker         return -1;
319*2b949d04SAndroid Build Coastguard Worker     }
320*2b949d04SAndroid Build Coastguard Worker 
321*2b949d04SAndroid Build Coastguard Worker     cookie = xcb_map_window_checked(conn, window);
322*2b949d04SAndroid Build Coastguard Worker     if ((error = xcb_request_check(conn, cookie)) != NULL) {
323*2b949d04SAndroid Build Coastguard Worker         free(error);
324*2b949d04SAndroid Build Coastguard Worker         return -1;
325*2b949d04SAndroid Build Coastguard Worker     }
326*2b949d04SAndroid Build Coastguard Worker 
327*2b949d04SAndroid Build Coastguard Worker     return 0;
328*2b949d04SAndroid Build Coastguard Worker }
329*2b949d04SAndroid Build Coastguard Worker 
330*2b949d04SAndroid Build Coastguard Worker int
main(int argc,char * argv[])331*2b949d04SAndroid Build Coastguard Worker main(int argc, char *argv[])
332*2b949d04SAndroid Build Coastguard Worker {
333*2b949d04SAndroid Build Coastguard Worker     int ret;
334*2b949d04SAndroid Build Coastguard Worker     xcb_connection_t *conn;
335*2b949d04SAndroid Build Coastguard Worker     uint8_t first_xkb_event;
336*2b949d04SAndroid Build Coastguard Worker     int32_t core_kbd_device_id;
337*2b949d04SAndroid Build Coastguard Worker     struct xkb_context *ctx;
338*2b949d04SAndroid Build Coastguard Worker     struct keyboard core_kbd;
339*2b949d04SAndroid Build Coastguard Worker 
340*2b949d04SAndroid Build Coastguard Worker     if (argc != 1) {
341*2b949d04SAndroid Build Coastguard Worker         ret = strcmp(argv[1], "--help");
342*2b949d04SAndroid Build Coastguard Worker         fprintf(ret ? stderr : stdout, "Usage: %s [--help]\n", argv[0]);
343*2b949d04SAndroid Build Coastguard Worker         if (ret)
344*2b949d04SAndroid Build Coastguard Worker             fprintf(stderr, "unrecognized option: %s\n", argv[1]);
345*2b949d04SAndroid Build Coastguard Worker         return ret ? EXIT_INVALID_USAGE : EXIT_SUCCESS;
346*2b949d04SAndroid Build Coastguard Worker     }
347*2b949d04SAndroid Build Coastguard Worker 
348*2b949d04SAndroid Build Coastguard Worker     setlocale(LC_ALL, "");
349*2b949d04SAndroid Build Coastguard Worker 
350*2b949d04SAndroid Build Coastguard Worker     conn = xcb_connect(NULL, NULL);
351*2b949d04SAndroid Build Coastguard Worker     if (!conn || xcb_connection_has_error(conn)) {
352*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't connect to X server: error code %d\n",
353*2b949d04SAndroid Build Coastguard Worker                 conn ? xcb_connection_has_error(conn) : -1);
354*2b949d04SAndroid Build Coastguard Worker         ret = -1;
355*2b949d04SAndroid Build Coastguard Worker         goto err_out;
356*2b949d04SAndroid Build Coastguard Worker     }
357*2b949d04SAndroid Build Coastguard Worker 
358*2b949d04SAndroid Build Coastguard Worker     ret = xkb_x11_setup_xkb_extension(conn,
359*2b949d04SAndroid Build Coastguard Worker                                       XKB_X11_MIN_MAJOR_XKB_VERSION,
360*2b949d04SAndroid Build Coastguard Worker                                       XKB_X11_MIN_MINOR_XKB_VERSION,
361*2b949d04SAndroid Build Coastguard Worker                                       XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
362*2b949d04SAndroid Build Coastguard Worker                                       NULL, NULL, &first_xkb_event, NULL);
363*2b949d04SAndroid Build Coastguard Worker     if (!ret) {
364*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't setup XKB extension\n");
365*2b949d04SAndroid Build Coastguard Worker         goto err_conn;
366*2b949d04SAndroid Build Coastguard Worker     }
367*2b949d04SAndroid Build Coastguard Worker 
368*2b949d04SAndroid Build Coastguard Worker     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
369*2b949d04SAndroid Build Coastguard Worker     if (!ctx) {
370*2b949d04SAndroid Build Coastguard Worker         ret = -1;
371*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't create xkb context\n");
372*2b949d04SAndroid Build Coastguard Worker         goto err_conn;
373*2b949d04SAndroid Build Coastguard Worker     }
374*2b949d04SAndroid Build Coastguard Worker 
375*2b949d04SAndroid Build Coastguard Worker     core_kbd_device_id = xkb_x11_get_core_keyboard_device_id(conn);
376*2b949d04SAndroid Build Coastguard Worker     if (core_kbd_device_id == -1) {
377*2b949d04SAndroid Build Coastguard Worker         ret = -1;
378*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't find core keyboard device\n");
379*2b949d04SAndroid Build Coastguard Worker         goto err_ctx;
380*2b949d04SAndroid Build Coastguard Worker     }
381*2b949d04SAndroid Build Coastguard Worker 
382*2b949d04SAndroid Build Coastguard Worker     ret = init_kbd(&core_kbd, conn, first_xkb_event, core_kbd_device_id, ctx);
383*2b949d04SAndroid Build Coastguard Worker     if (ret) {
384*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't initialize core keyboard device\n");
385*2b949d04SAndroid Build Coastguard Worker         goto err_ctx;
386*2b949d04SAndroid Build Coastguard Worker     }
387*2b949d04SAndroid Build Coastguard Worker 
388*2b949d04SAndroid Build Coastguard Worker     ret = create_capture_window(conn);
389*2b949d04SAndroid Build Coastguard Worker     if (ret) {
390*2b949d04SAndroid Build Coastguard Worker         fprintf(stderr, "Couldn't create a capture window\n");
391*2b949d04SAndroid Build Coastguard Worker         goto err_core_kbd;
392*2b949d04SAndroid Build Coastguard Worker     }
393*2b949d04SAndroid Build Coastguard Worker 
394*2b949d04SAndroid Build Coastguard Worker     tools_disable_stdin_echo();
395*2b949d04SAndroid Build Coastguard Worker     ret = loop(conn, &core_kbd);
396*2b949d04SAndroid Build Coastguard Worker     tools_enable_stdin_echo();
397*2b949d04SAndroid Build Coastguard Worker 
398*2b949d04SAndroid Build Coastguard Worker err_core_kbd:
399*2b949d04SAndroid Build Coastguard Worker     deinit_kbd(&core_kbd);
400*2b949d04SAndroid Build Coastguard Worker err_ctx:
401*2b949d04SAndroid Build Coastguard Worker     xkb_context_unref(ctx);
402*2b949d04SAndroid Build Coastguard Worker err_conn:
403*2b949d04SAndroid Build Coastguard Worker     xcb_disconnect(conn);
404*2b949d04SAndroid Build Coastguard Worker err_out:
405*2b949d04SAndroid Build Coastguard Worker     exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
406*2b949d04SAndroid Build Coastguard Worker }
407