File: git-xbrlapi

package info (click to toggle)
brltty 5.6-10
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 25,116 kB
  • sloc: ansic: 117,871; sh: 6,590; java: 4,785; xml: 3,451; makefile: 1,973; tcl: 1,499; awk: 611; ml: 293; python: 250; lisp: 52
file content (140 lines) | stat: -rw-r--r-- 5,549 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
commit b1e831709e2c524c5e2bbe0b106bcdb239502183
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Tue Apr 24 02:12:08 2018 +0200

    xbrlapi: map unmapped keysyms to temporary keycodes
    
    So that we can simulate any keysym, independently from the keyboard
    layout, and notably characters only reachable with dead keys.

diff --git a/Programs/xbrlapi.c b/Programs/xbrlapi.c
index 0a6e59a11..d546273da 100644
--- a/Programs/xbrlapi.c
+++ b/Programs/xbrlapi.c
@@ -581,6 +581,11 @@ static void toX_f(const char *display) {
   unsigned int keysym, keycode, modifiers, next_modifiers = 0;
   Bool haveXTest;
   int eventBase, errorBase, majorVersion, minorVersion;
+  XkbDescPtr xkb = NULL;
+  XkbMapChangesRec changes = { .changed = XkbKeyTypesMask|XkbKeySymsMask };
+  int oneGroupType[XkbNumKbdGroups] = { XkbOneLevelIndex };
+  Status status;
+  int last_remap_keycode = -1, remap_keycode;
 #endif /* CAN_SIMULATE_KEY_PRESSES */
 
   Xdisplay = display;
@@ -591,7 +596,6 @@ static void toX_f(const char *display) {
 
 #ifdef CAN_SIMULATE_KEY_PRESSES
   haveXTest = XTestQueryExtension(dpy, &eventBase, &errorBase, &majorVersion, &minorVersion);
-#endif /* CAN_SIMULATE_KEY_PRESSES */
 
   {
     int foo;
@@ -601,6 +605,7 @@ static void toX_f(const char *display) {
     if (!XkbQueryExtension(dpy, &foo, &foo, &foo, &major, &minor))
       fatal(gettext("Incompatible XKB server support\n"));
   }
+#endif /* CAN_SIMULATE_KEY_PRESSES */
 
   X_fd = XConnectionNumber(dpy);
 
@@ -796,9 +801,10 @@ static void toX_f(const char *display) {
 	    modifiers = ((code & BRLAPI_KEY_FLAGS_MASK) >> BRLAPI_KEY_FLAGS_SHIFT) & 0xFF;
 	    keysym = code & BRLAPI_KEY_CODE_MASK;
 	    keycode = XKeysymToKeycode(dpy,keysym);
+	    remap_keycode = -1;
 	    if (keycode == NoSymbol) {
-	      fprintf(stderr,gettext("xbrlapi: Couldn't translate keysym %08X to keycode.\n"),keysym);
-	      continue;
+	      debugf(gettext("xbrlapi: Couldn't translate keysym %08X to keycode.\n"),keysym);
+	      goto needRemap;
 	    }
 
 	    {
@@ -821,21 +827,80 @@ static void toX_f(const char *display) {
 		if (tryModifiers(keycode, &modifiers, *try, keysym)) goto foundModifiers;
 	      } while (*++try);
 
-	      fprintf(stderr,gettext("xbrlapi: Couldn't find modifiers to apply to %d for getting keysym %08X\n"),keycode,keysym);
-	      continue;
+	      debugf(gettext("xbrlapi: Couldn't find modifiers to apply to %d for getting keysym %08X\n"),keycode,keysym);
+	    }
+
+	  needRemap:
+	    {
+	      /* Try tofind an unassigned keycode to remap it temporarily to the requested keysym. */
+	      xkb = XkbGetMap(dpy,XkbKeyTypesMask|XkbKeySymsMask,XkbUseCoreKbd);
+	      /* Start from big keycodes, usually unassigned. */
+	      for (i = xkb->max_key_code;
+		   i >= xkb->min_key_code && (XkbKeyNumGroups(xkb,i) != 0 || i == last_remap_keycode);
+		   i--)
+		;
+	      if (i < xkb->min_key_code) {
+		fprintf(stderr,gettext("xbrlapi: Couldn't find a keycode to remap for simulating unbound keysym %08X\n"),keysym);
+		goto abortRemap;
+	      }
+	      remap_keycode = keycode = i;
+	      next_modifiers = modifiers = 0;
+
+	      /* Remap this keycode. */
+	      changes.first_key_sym = keycode;
+	      changes.num_key_syms = 1;
+	      if ((status = XkbChangeTypesOfKey(xkb,keycode,1,XkbGroup1Mask,oneGroupType,&changes))) {
+		debugf("Error while changing client keymap: %d\n", status);
+		goto abortRemap;
+	      }
+	      XkbKeySymEntry(xkb,keycode,0,0) = keysym;
+	      if (!XkbChangeMap(dpy,xkb,&changes)) {
+		debugf("Error while changing server keymap\n");
+		goto abortRemap;
+	      }
+	      XkbFreeKeyboard(xkb,0,True);
+	      debugf("Remapped keycode %d to keysym %08X\n",keycode,keysym);
 	    }
-	  foundModifiers:
 
+	  foundModifiers:
 	    debugf("key %08X: (%d,%x,%x)\n", keysym, keycode, next_modifiers, modifiers);
 	    modifiers |= next_modifiers;
 	    next_modifiers = 0;
 	    if (modifiers)
 	      XkbLockModifiers(dpy, XkbUseCoreKbd, modifiers, modifiers);
-	    XTestFakeKeyEvent(dpy,keycode,True,CurrentTime);
-	    XTestFakeKeyEvent(dpy,keycode,False,CurrentTime);
+	    XTestFakeKeyEvent(dpy,keycode,True,1);
+	    XTestFakeKeyEvent(dpy,keycode,False,1);
 	    if (modifiers)
 	      XkbLockModifiers(dpy, XkbUseCoreKbd, modifiers, 0);
+
+	    /* Remove previous keycode mapping */
+	    if (last_remap_keycode != -1) {
+	      /* Note: since X11 is asynchronous, we should not immediately
+	       * unmap the just-mapped keycode, otherwise when the client
+	       * eventually gets to read the new Xkb state from the server,
+	       * the key might have been synthesized and the keycode unmapped
+	       * already. We just hope the user does not type too fast for the
+	       * application to catch up. */
+	      xkb = XkbGetMap(dpy,XkbKeyTypesMask|XkbKeySymsMask,XkbUseCoreKbd);
+	      changes.first_key_sym = last_remap_keycode;
+	      changes.num_key_syms = 1;
+	      if ((status = XkbChangeTypesOfKey(xkb,last_remap_keycode,0,XkbGroup1Mask,NULL,&changes))) {
+		debugf("Oops, error while restoring client keymap: %d\n", status);
+	      } else {
+		XkbChangeMap(dpy,xkb,&changes);
+		debugf("restored last keycode %d\n", last_remap_keycode);
+	      }
+	      XkbFreeKeyboard(xkb,0,True);
+	    }
+	    XFlush(dpy);
+	    last_remap_keycode = remap_keycode;
 	    break;
+
+	  abortRemap:
+	    XkbFreeKeyboard(xkb, 0, True);
+	    xkb = NULL;
+	    break;
+
 	  default:
 	    fprintf(stderr, "xbrlapi: %s: %" BRLAPI_PRIxKEYCODE "\n",
 		    gettext("unexpected block type"), code);