Sending arbitrary keysyms/Unicode without xcb_change_keyboard_mapping()

Diego Alonso Cortez <[email protected]> Sun, 22 Sep 2024 05:54:28 -0400
Newsgroups gmane.comp.freedesktop.xcb
Message-ID <[email protected]>
------=_Part_884969_1582274729.1726998868032
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

By running something like



xmodmap -pke



or calling xcb_get_keyboard_mapping_unchecked()



one can get the mapping of 8-bit X11 keycodes to 32-bit keysyms, where each=
 keycode maps to (I think) 8 keysyms or so.



Then, one can send X11 keycodes to applications by calling xcb_send_event()=
. I have a helper function for that:





void xcb_send_key_press(xcb_connection_t* connection, xcb_window_t root, xc=
b_window_t window, xcb_keycode_t keycode){

=C2=A0 xcb_key_press_event_t ev;=C2=A0 memset(&ev,0x00,sizeof(xcb_key_press=
_event_t));

=C2=A0 ev.response_type =3D XCB_KEY_PRESS;

=C2=A0 ev.detail=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D keycode;

=C2=A0 ev.time=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D XC=
B_CURRENT_TIME;

=C2=A0 ev.root=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D ro=
ot;

=C2=A0 ev.event=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D window;

=C2=A0 ev.state=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0x0000;

=C2=A0 ev.same_screen=C2=A0=C2=A0 =3D 1;

=C2=A0 xcb_send_event(connection, 0, window, XCB_EVENT_MASK_NO_EVENT, (cons=
t char*)&ev);

}





I'm trying to send arbitrary Unicode codepoints (and, just as importantly, =
sequences of codepoints) to the X11 application/window currently in focus.

I know this is possible because "every possible Unicode character has alrea=
dy a keysym string defined algorithmically" (source:=C2=A0/usr/include/X11/=
keysymdef.h).



To send, eg., Unicode codepoint U+1f3f4, I'm doing:





#define X11_UNICODE_BASE=C2=A0 0x01000000

xcb_change_keyboard_mapping(connection, 1,255, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x01f3f4});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
255);





where I'm remapping keycode 255 (last X11 keycode) on-the-fly to the desire=
d Unicode codepoint.



But I can't figure out how to send keysyms directly, without having to call=
 xcb_change_keyboard_mapping(), which is very, very slow if you call it sev=
eral times in a row (in that case it freezes certain X11 things for several=
 seconds, like mouse clicking and alt-tabbing).



So, for example, what I'm doing in order to send (say) the flag of England =
(7 Unicode codepoints), I'm doing (what effectually amounts to):





xcb_get_input_focus_cookie_t get_input_focus_cookie =3D xcb_get_input_focus=
_unchecked(connection);

xcb_get_input_focus_reply_t* get_input_focus_reply=C2=A0 =3D xcb_get_input_=
focus_reply(connection, get_input_focus_cookie, NULL);

xcb_change_keyboard_mapping(connection, 1,249, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x01f3f4});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
249);

xcb_change_keyboard_mapping(connection, 1,250, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e0067});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
250);

xcb_change_keyboard_mapping(connection, 1,251, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e0062});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
251);

xcb_change_keyboard_mapping(connection, 1,252, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e0065});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
252);

xcb_change_keyboard_mapping(connection, 1,253, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e006e});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
253);

xcb_change_keyboard_mapping(connection, 1,254, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e0067});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
254);

xcb_change_keyboard_mapping(connection, 1,255, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x0e007f});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
255);

xcb_sync(connection);





which works, but looks insane to me, and is also slow (in the sense describ=
ed before).



Though the following also works:





xcb_change_keyboard_mapping(connection, 7,249, 1,(const xcb_keysym_t[]){X11=
_UNICODE_BASE|0x01f3f4,X11_UNICODE_BASE|0x0e0067,X11_UNICODE_BASE|0x0e0062,=
X11_UNICODE_BASE|0x0e0065,X11_UNICODE_BASE|0x0e006e,X11_UNICODE_BASE|0x0e00=
67,X11_UNICODE_BASE|0x0e007f});

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
249);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
250);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
251);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
252);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
253);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
254);

xcb_send_key_press(connection, screen->root, get_input_focus_reply->focus, =
255);





But in general I can't use the trick of calling=C2=A0xcb_change_keyboard_ma=
pping() with multiple desired Unicode values at once (which is way faster t=
han doing it one at a time) because for my application I don't know in adva=
nce what Unicode codepoints will be sent by the user.

And, since X11 keycodes are merely 8-bits, they can't fit all of Unicode an=
yway (not even practical things, like all 3790 emoji, which by my count amo=
unt to 11,192 Unicode codepoints).





What would much more sense is to do something like:





xcb_send_keysym(connection, X11_UNICODE_BASE|0x01f3f4);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e0067);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e0062);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e0065);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e006e);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e0067);

xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e007f);





without the freeze that multiple calls to=C2=A0xcb_change_keyboard_mapping(=
) cause.



So, how can I do that?



(I'm already doing this on Windows and Mac, but I've yet to find a solution=
 for X11.)
------=_Part_884969_1582274729.1726998868032
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>=
<meta content=3D"text/html;charset=3DUTF-8" http-equiv=3D"Content-Type"></h=
ead><body ><div style=3D"font-family: Verdana, Arial, Helvetica, sans-serif=
; font-size: 10pt;"><div>By running something like<br></div><div><br></div>=
<div>xmodmap -pke<br></div><div><br></div><div>or calling xcb_get_keyboard_=
mapping_unchecked()<br></div><div><br></div><div>one can get the mapping of=
 8-bit X11 keycodes to 32-bit keysyms, where each keycode maps to (I think)=
 8 keysyms or so.<br></div><div><br></div><div>Then, one can send X11 keyco=
des to applications by calling xcb_send_event(). I have a helper function f=
or that:<br></div><div><br></div><div><br></div><div>void xcb_send_key_pres=
s(xcb_connection_t* connection, xcb_window_t root, xcb_window_t window, xcb=
_keycode_t keycode){<br></div><div>&nbsp; xcb_key_press_event_t ev;&nbsp; m=
emset(&amp;ev,0x00,sizeof(xcb_key_press_event_t));<br></div><div>&nbsp; ev.=
response_type =3D XCB_KEY_PRESS;<br></div><div>&nbsp; ev.detail&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =3D keycode;<br></div><div>&nbsp; ev.time&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =3D XCB_CURRENT_TIME;<b=
r></div><div>&nbsp; ev.root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp; =3D root;<br></div><div>&nbsp; ev.event&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp; =3D window;<br></div><div>&nbsp; ev.state&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =3D 0x0000;<br></div><div>&nbsp; ev.same=
_screen&nbsp;&nbsp; =3D 1;<br></div><div>&nbsp; xcb_send_event(connection, =
0, window, XCB_EVENT_MASK_NO_EVENT, (const char*)&amp;ev);<br></div><div>}<=
br></div><div><br></div><div><br></div><div>I'm trying to send arbitrary Un=
icode codepoints (and, just as importantly, sequences of codepoints) to the=
 X11 application/window currently in focus.<br></div><div>I know this is po=
ssible because "every possible Unicode character has already a keysym strin=
g defined algorithmically" (source:&nbsp;/usr/include/X11/keysymdef.h).<br>=
</div><div><br></div><div>To send, eg., Unicode codepoint U+1f3f4, I'm doin=
g:<br></div><div><br></div><div><br></div><div>#define X11_UNICODE_BASE&nbs=
p; 0x01000000<br></div><div>xcb_change_keyboard_mapping(connection, 1,255, =
1,(const xcb_keysym_t[]){X11_UNICODE_BASE|0x01f3f4});<br></div><div>xcb_sen=
d_key_press(connection, screen-&gt;root, get_input_focus_reply-&gt;focus, 2=
55);<br></div><div><br></div><div><br></div><div>where I'm remapping keycod=
e 255 (last X11 keycode) on-the-fly to the desired Unicode codepoint.<br></=
div><div><br></div><div>But I can't figure out how to send keysyms directly=
, without having to call xcb_change_keyboard_mapping(), which is very, very=
 slow if you call it several times in a row (in that case it freezes certai=
n X11 things for several seconds, like mouse clicking and alt-tabbing).<br>=
</div><div><br></div><div>So, for example, what I'm doing in order to send =
(say) the flag of England (7 Unicode codepoints), I'm doing (what effectual=
ly amounts to):<br></div><div><br></div><div><br></div><div>xcb_get_input_f=
ocus_cookie_t get_input_focus_cookie =3D xcb_get_input_focus_unchecked(conn=
ection);<br></div><div>xcb_get_input_focus_reply_t* get_input_focus_reply&n=
bsp; =3D xcb_get_input_focus_reply(connection, get_input_focus_cookie, NULL=
);<br></div><div>xcb_change_keyboard_mapping(connection, 1,249, 1,(const xc=
b_keysym_t[]){X11_UNICODE_BASE|0x01f3f4});<br></div><div>xcb_send_key_press=
(connection, screen-&gt;root, get_input_focus_reply-&gt;focus, 249);<br></d=
iv><div>xcb_change_keyboard_mapping(connection, 1,250, 1,(const xcb_keysym_=
t[]){X11_UNICODE_BASE|0x0e0067});<br></div><div>xcb_send_key_press(connecti=
on, screen-&gt;root, get_input_focus_reply-&gt;focus, 250);<br></div><div>x=
cb_change_keyboard_mapping(connection, 1,251, 1,(const xcb_keysym_t[]){X11_=
UNICODE_BASE|0x0e0062});<br></div><div>xcb_send_key_press(connection, scree=
n-&gt;root, get_input_focus_reply-&gt;focus, 251);<br></div><div>xcb_change=
_keyboard_mapping(connection, 1,252, 1,(const xcb_keysym_t[]){X11_UNICODE_B=
ASE|0x0e0065});<br></div><div>xcb_send_key_press(connection, screen-&gt;roo=
t, get_input_focus_reply-&gt;focus, 252);<br></div><div>xcb_change_keyboard=
_mapping(connection, 1,253, 1,(const xcb_keysym_t[]){X11_UNICODE_BASE|0x0e0=
06e});<br></div><div>xcb_send_key_press(connection, screen-&gt;root, get_in=
put_focus_reply-&gt;focus, 253);<br></div><div>xcb_change_keyboard_mapping(=
connection, 1,254, 1,(const xcb_keysym_t[]){X11_UNICODE_BASE|0x0e0067});<br=
></div><div>xcb_send_key_press(connection, screen-&gt;root, get_input_focus=
_reply-&gt;focus, 254);<br></div><div>xcb_change_keyboard_mapping(connectio=
n, 1,255, 1,(const xcb_keysym_t[]){X11_UNICODE_BASE|0x0e007f});<br></div><d=
iv>xcb_send_key_press(connection, screen-&gt;root, get_input_focus_reply-&g=
t;focus, 255);<br></div><div>xcb_sync(connection);<br></div><div><br></div>=
<div><br></div><div>which works, but looks insane to me, and is also slow (=
in the sense described before).<br></div><div><br></div><div>Though the fol=
lowing also works:<br></div><div><br></div><div><br></div><div>xcb_change_k=
eyboard_mapping(connection, 7,249, 1,(const xcb_keysym_t[]){X11_UNICODE_BAS=
E|0x01f3f4,X11_UNICODE_BASE|0x0e0067,X11_UNICODE_BASE|0x0e0062,X11_UNICODE_=
BASE|0x0e0065,X11_UNICODE_BASE|0x0e006e,X11_UNICODE_BASE|0x0e0067,X11_UNICO=
DE_BASE|0x0e007f});<br></div><div>xcb_send_key_press(connection, screen-&gt=
;root, get_input_focus_reply-&gt;focus, 249);<br></div><div>xcb_send_key_pr=
ess(connection, screen-&gt;root, get_input_focus_reply-&gt;focus, 250);<br>=
</div><div>xcb_send_key_press(connection, screen-&gt;root, get_input_focus_=
reply-&gt;focus, 251);<br></div><div>xcb_send_key_press(connection, screen-=
&gt;root, get_input_focus_reply-&gt;focus, 252);<br></div><div>xcb_send_key=
_press(connection, screen-&gt;root, get_input_focus_reply-&gt;focus, 253);<=
br></div><div>xcb_send_key_press(connection, screen-&gt;root, get_input_foc=
us_reply-&gt;focus, 254);<br></div><div>xcb_send_key_press(connection, scre=
en-&gt;root, get_input_focus_reply-&gt;focus, 255);<br></div><div><br></div=
><div><br></div><div>But in general I can't use the trick of calling&nbsp;x=
cb_change_keyboard_mapping() with multiple desired Unicode values at once (=
which is way faster than doing it one at a time) because for my application=
 I don't know in advance what Unicode codepoints will be sent by the user.<=
br></div><div>And, since X11 keycodes are merely 8-bits, they can't fit all=
 of Unicode anyway (not even practical things, like all 3790 emoji, which b=
y my count amount to 11,192 Unicode codepoints).<br></div><div><br></div><d=
iv><br></div><div>What would much more sense is to do something like:<br></=
div><div><br></div><div><br></div><div>xcb_send_keysym(connection, X11_UNIC=
ODE_BASE|0x01f3f4);<br></div><div>xcb_send_keysym(connection, X11_UNICODE_B=
ASE|0x0e0067);<br></div><div>xcb_send_keysym(connection, X11_UNICODE_BASE|0=
x0e0062);<br></div><div>xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e00=
65);<br></div><div>xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e006e);<=
br></div><div>xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e0067);<br></=
div><div>xcb_send_keysym(connection, X11_UNICODE_BASE|0x0e007f);<br></div><=
div><br></div><div><br></div><div>without the freeze that multiple calls to=
&nbsp;xcb_change_keyboard_mapping() cause.<br></div><div><br></div><div>So,=
 how can I do that?<br></div><div><br></div><div>(I'm already doing this on=
 Windows and Mac, but I've yet to find a solution for X11.)<br></div><div><=
br></div></div><br></body></html>
------=_Part_884969_1582274729.1726998868032--