1ecce36beSmrg/*
2ecce36beSmrg * Copyright © 2008 Ian Osgood <iano@quirkster.com>
3ecce36beSmrg * Copyright © 2008 Jamey Sharp <jamey@minilop.net>
4ecce36beSmrg * Copyright © 2008 Josh Triplett <josh@freedesktop.org>
5ecce36beSmrg * Copyright © 2008 Ulrich Eckhardt <doomster@knuut.de>
6ecce36beSmrg *
7ecce36beSmrg * Permission is hereby granted, free of charge, to any person
8ecce36beSmrg * obtaining a copy of this software and associated documentation
9ecce36beSmrg * files (the "Software"), to deal in the Software without
10ecce36beSmrg * restriction, including without limitation the rights to use, copy,
11ecce36beSmrg * modify, merge, publish, distribute, sublicense, and/or sell copies
12ecce36beSmrg * of the Software, and to permit persons to whom the Software is
13ecce36beSmrg * furnished to do so, subject to the following conditions:
14ecce36beSmrg *
15ecce36beSmrg * The above copyright notice and this permission notice shall be
16ecce36beSmrg * included in all copies or substantial portions of the Software.
17ecce36beSmrg *
18ecce36beSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19ecce36beSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20ecce36beSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21ecce36beSmrg * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
22ecce36beSmrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23ecce36beSmrg * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24ecce36beSmrg * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25ecce36beSmrg *
26ecce36beSmrg * Except as contained in this notice, the names of the authors or
27ecce36beSmrg * their institutions shall not be used in advertising or otherwise to
28ecce36beSmrg * promote the sale, use or other dealings in this Software without
29ecce36beSmrg * prior written authorization from the authors.
30ecce36beSmrg */
31ecce36beSmrg
32ecce36beSmrg#include <stdlib.h>
33ecce36beSmrg
34ecce36beSmrg#include <xcb/xcb.h>
35ecce36beSmrg#define XK_MISCELLANY
36ecce36beSmrg#define XK_XKB_KEYS
37ecce36beSmrg#define XK_LATIN1
38ecce36beSmrg#define XK_LATIN2
39ecce36beSmrg#define XK_LATIN3
40ecce36beSmrg#define XK_LATIN4
41ecce36beSmrg#define XK_CYRILLIC
42ecce36beSmrg#define XK_GREEK
43ecce36beSmrg#define XK_ARMENIAN
44ecce36beSmrg#include <X11/keysymdef.h>
45ecce36beSmrg
46ecce36beSmrg#include "xcb_keysyms.h"
47ecce36beSmrg
48ecce36beSmrg/* Private declaration */
49ecce36beSmrgenum tag_t {
50ecce36beSmrg  TAG_COOKIE,
51ecce36beSmrg  TAG_VALUE
52ecce36beSmrg};
53ecce36beSmrg
54ecce36beSmrgstruct _XCBKeySymbols
55ecce36beSmrg{
56ecce36beSmrg  xcb_connection_t *c;
57ecce36beSmrg  enum tag_t     tag;
58ecce36beSmrg  union {
59ecce36beSmrg    xcb_get_keyboard_mapping_cookie_t cookie;
60ecce36beSmrg    xcb_get_keyboard_mapping_reply_t *reply;
61ecce36beSmrg  } u;
62ecce36beSmrg};
63ecce36beSmrg
64ecce36beSmrgstatic void xcb_convert_case(xcb_keysym_t  sym,
65ecce36beSmrg			   xcb_keysym_t *lower,
66ecce36beSmrg			   xcb_keysym_t *upper);
67ecce36beSmrg
68ecce36beSmrgstatic void xcb_key_symbols_get_reply (xcb_key_symbols_t    *syms,
69ecce36beSmrg				   xcb_generic_error_t **e);
70ecce36beSmrg
71ecce36beSmrg/* public implementation */
72ecce36beSmrg
73ecce36beSmrgxcb_key_symbols_t *
74ecce36beSmrgxcb_key_symbols_alloc (xcb_connection_t *c)
75ecce36beSmrg{
76ecce36beSmrg  xcb_key_symbols_t *syms;
77ecce36beSmrg  xcb_keycode_t     min_keycode;
78ecce36beSmrg  xcb_keycode_t     max_keycode;
79ecce36beSmrg
80ecce36beSmrg  if (!c)
81ecce36beSmrg    return NULL;
82ecce36beSmrg
83ecce36beSmrg  syms = malloc (sizeof (xcb_key_symbols_t));
84ecce36beSmrg
85ecce36beSmrg  syms->c = c;
86ecce36beSmrg  syms->tag = TAG_COOKIE;
87ecce36beSmrg
88ecce36beSmrg  min_keycode = xcb_get_setup (c)->min_keycode;
89ecce36beSmrg  max_keycode = xcb_get_setup (c)->max_keycode;
90ecce36beSmrg
91ecce36beSmrg  syms->u.cookie = xcb_get_keyboard_mapping(c,
92ecce36beSmrg					 min_keycode,
93ecce36beSmrg					 max_keycode - min_keycode + 1);
94ecce36beSmrg
95ecce36beSmrg  return syms;
96ecce36beSmrg}
97ecce36beSmrg
98ecce36beSmrgvoid
99ecce36beSmrgxcb_key_symbols_free (xcb_key_symbols_t *syms)
100ecce36beSmrg{
101ecce36beSmrg  if (syms)
102ecce36beSmrg    {
103ecce36beSmrg      if (syms->tag == TAG_VALUE)
104ecce36beSmrg	free (syms->u.reply);
105ecce36beSmrg      free (syms);
106ecce36beSmrg      syms = NULL;
107ecce36beSmrg    }
108ecce36beSmrg}
109ecce36beSmrg
110ecce36beSmrg/*  Use of the 'col' parameter:
111ecce36beSmrg
112ecce36beSmrgA list of KeySyms is associated with each KeyCode. The list is intended
113ecce36beSmrgto convey the set of symbols on the corresponding key. If the list
114ecce36beSmrg(ignoring trailing NoSymbol entries) is a single KeySym ``K'', then the
115ecce36beSmrglist is treated as if it were the list ``K NoSymbol K NoSymbol''. If the
116ecce36beSmrglist (ignoring trailing NoSymbol entries) is a pair of KeySyms ``K1
117ecce36beSmrgK2'', then the list is treated as if it were the list ``K1 K2 K1 K2''.
118ecce36beSmrgIf the list (ignoring trailing NoSymbol entries) is a triple of KeySyms
119ecce36beSmrg``K1 K2 K3'', then the list is treated as if it were the list ``K1 K2 K3
120ecce36beSmrgNoSymbol''. When an explicit ``void'' element is desired in the list,
121ecce36beSmrgthe value VoidSymbol can be used.
122ecce36beSmrg
123ecce36beSmrgThe first four elements of the list are split into two groups of
124ecce36beSmrgKeySyms. Group 1 contains the first and second KeySyms; Group 2 contains
125ecce36beSmrgthe third and fourth KeySyms. Within each group, if the second element
126ecce36beSmrgof the group is NoSymbol , then the group should be treated as if the
127ecce36beSmrgsecond element were the same as the first element, except when the first
128ecce36beSmrgelement is an alphabetic KeySym ``K'' for which both lowercase and
129ecce36beSmrguppercase forms are defined. In that case, the group should be treated
130ecce36beSmrgas if the first element were the lowercase form of ``K'' and the second
131ecce36beSmrgelement were the uppercase form of ``K.''
132ecce36beSmrg
133ecce36beSmrgThe standard rules for obtaining a KeySym from a KeyPress event make use
134ecce36beSmrgof only the Group 1 and Group 2 KeySyms; no interpretation of other
135ecce36beSmrgKeySyms in the list is given. Which group to use is determined by the
136ecce36beSmrgmodifier state. Switching between groups is controlled by the KeySym
137ecce36beSmrgnamed MODE SWITCH, by attaching that KeySym to some KeyCode and
138ecce36beSmrgattaching that KeyCode to any one of the modifiers Mod1 through Mod5.
139ecce36beSmrgThis modifier is called the group modifier. For any KeyCode, Group 1 is
140ecce36beSmrgused when the group modifier is off, and Group 2 is used when the group
141ecce36beSmrgmodifier is on.
142ecce36beSmrg
143ecce36beSmrgThe Lock modifier is interpreted as CapsLock when the KeySym named
144ecce36beSmrgXK_Caps_Lock is attached to some KeyCode and that KeyCode is attached to
145ecce36beSmrgthe Lock modifier. The Lock modifier is interpreted as ShiftLock when
146ecce36beSmrgthe KeySym named XK_Shift_Lock is attached to some KeyCode and that
147ecce36beSmrgKeyCode is attached to the Lock modifier. If the Lock modifier could be
148ecce36beSmrginterpreted as both CapsLock and ShiftLock, the CapsLock interpretation
149ecce36beSmrgis used.
150ecce36beSmrg
151ecce36beSmrgThe operation of keypad keys is controlled by the KeySym named
152ecce36beSmrgXK_Num_Lock, by attaching that KeySym to some KeyCode and attaching that
153ecce36beSmrgKeyCode to any one of the modifiers Mod1 through Mod5 . This modifier is
154ecce36beSmrgcalled the numlock modifier. The standard KeySyms with the prefix
155ecce36beSmrg``XK_KP_'' in their name are called keypad KeySyms; these are KeySyms
156ecce36beSmrgwith numeric value in the hexadecimal range 0xFF80 to 0xFFBD inclusive.
157ecce36beSmrgIn addition, vendor-specific KeySyms in the hexadecimal range 0x11000000
158ecce36beSmrgto 0x1100FFFF are also keypad KeySyms.
159ecce36beSmrg
160ecce36beSmrgWithin a group, the choice of KeySym is determined by applying the first
161ecce36beSmrgrule that is satisfied from the following list:
162ecce36beSmrg
163ecce36beSmrg* The numlock modifier is on and the second KeySym is a keypad KeySym. In
164ecce36beSmrg  this case, if the Shift modifier is on, or if the Lock modifier is on
165ecce36beSmrg  and is interpreted as ShiftLock, then the first KeySym is used,
166ecce36beSmrg  otherwise the second KeySym is used.
167ecce36beSmrg
168ecce36beSmrg* The Shift and Lock modifiers are both off. In this case, the first
169ecce36beSmrg  KeySym is used.
170ecce36beSmrg
171ecce36beSmrg* The Shift modifier is off, and the Lock modifier is on and is
172ecce36beSmrg  interpreted as CapsLock. In this case, the first KeySym is used, but
173ecce36beSmrg  if that KeySym is lowercase alphabetic, then the corresponding
174ecce36beSmrg  uppercase KeySym is used instead.
175ecce36beSmrg
176ecce36beSmrg* The Shift modifier is on, and the Lock modifier is on and is
177ecce36beSmrg  interpreted as CapsLock. In this case, the second KeySym is used, but
178ecce36beSmrg  if that KeySym is lowercase alphabetic, then the corresponding
179ecce36beSmrg  uppercase KeySym is used instead.
180ecce36beSmrg
181ecce36beSmrg* The Shift modifier is on, or the Lock modifier is on and is
182ecce36beSmrg  interpreted as ShiftLock, or both. In this case, the second KeySym is
183ecce36beSmrg  used.
184ecce36beSmrg
185ecce36beSmrg*/
186ecce36beSmrg
187ecce36beSmrgxcb_keysym_t xcb_key_symbols_get_keysym (xcb_key_symbols_t *syms,
188ecce36beSmrg				  xcb_keycode_t     keycode,
189ecce36beSmrg				  int            col)
190ecce36beSmrg{
191ecce36beSmrg  xcb_keysym_t *keysyms;
192ecce36beSmrg  xcb_keysym_t  keysym_null = { XCB_NO_SYMBOL };
193ecce36beSmrg  xcb_keysym_t  lsym;
194ecce36beSmrg  xcb_keysym_t  usym;
195ecce36beSmrg  xcb_keycode_t min_keycode;
196ecce36beSmrg  xcb_keycode_t max_keycode;
197ecce36beSmrg  int        per;
198ecce36beSmrg
199ecce36beSmrg  if (!syms)
200ecce36beSmrg    return keysym_null;
201ecce36beSmrg
202ecce36beSmrg  xcb_key_symbols_get_reply (syms, NULL);
203ecce36beSmrg
204ecce36beSmrg  keysyms = xcb_get_keyboard_mapping_keysyms (syms->u.reply);
205ecce36beSmrg  min_keycode = xcb_get_setup (syms->c)->min_keycode;
206ecce36beSmrg  max_keycode = xcb_get_setup (syms->c)->max_keycode;
207ecce36beSmrg
208ecce36beSmrg  per = syms->u.reply->keysyms_per_keycode;
209ecce36beSmrg  if ((col < 0) || ((col >= per) && (col > 3)) ||
210ecce36beSmrg      (keycode < min_keycode) ||
211ecce36beSmrg      (keycode > max_keycode))
212ecce36beSmrg    return keysym_null;
213ecce36beSmrg
214ecce36beSmrg  keysyms = &keysyms[(keycode - min_keycode) * per];
215ecce36beSmrg  if (col < 4)
216ecce36beSmrg    {
217ecce36beSmrg      if (col > 1)
218ecce36beSmrg	{
219ecce36beSmrg	  while ((per > 2) && (keysyms[per - 1] == XCB_NO_SYMBOL))
220ecce36beSmrg	    per--;
221ecce36beSmrg	  if (per < 3)
222ecce36beSmrg	    col -= 2;
223ecce36beSmrg	}
224ecce36beSmrg      if ((per <= (col|1)) || (keysyms[col|1] == XCB_NO_SYMBOL))
225ecce36beSmrg	{
226ecce36beSmrg	  xcb_convert_case(keysyms[col&~1], &lsym, &usym);
227ecce36beSmrg	  if (!(col & 1))
228ecce36beSmrg	    return lsym;
229ecce36beSmrg	  else if (usym == lsym)
230ecce36beSmrg	    return keysym_null;
231ecce36beSmrg	  else
232ecce36beSmrg	    return usym;
233ecce36beSmrg	}
234ecce36beSmrg    }
235ecce36beSmrg  return keysyms[col];
236ecce36beSmrg}
237ecce36beSmrg
238ecce36beSmrgxcb_keycode_t *
239ecce36beSmrgxcb_key_symbols_get_keycode(xcb_key_symbols_t *syms,
240ecce36beSmrg                            xcb_keysym_t      keysym)
241ecce36beSmrg{
242ecce36beSmrg  xcb_keysym_t ks;
243ecce36beSmrg  int j, nresult = 0;
244ecce36beSmrg  xcb_keycode_t i, min, max, *result = NULL;
245ecce36beSmrg
246ecce36beSmrg  if(syms)
247ecce36beSmrg  {
248ecce36beSmrg      xcb_key_symbols_get_reply (syms, NULL);
249ecce36beSmrg      min = xcb_get_setup(syms->c)->min_keycode;
250ecce36beSmrg      max = xcb_get_setup(syms->c)->max_keycode;
251ecce36beSmrg
252ecce36beSmrg      for(j = 0; j < syms->u.reply->keysyms_per_keycode; j++)
253ecce36beSmrg          for(i = min; i && i <= max; i++)
254ecce36beSmrg          {
255ecce36beSmrg              ks = xcb_key_symbols_get_keysym(syms, i, j);
256ecce36beSmrg              if(ks == keysym)
257ecce36beSmrg              {
258ecce36beSmrg                  nresult++;
259ecce36beSmrg                  result = realloc(result, sizeof(xcb_keycode_t) * (nresult + 1));
260ecce36beSmrg                  result[nresult - 1] = i;
261ecce36beSmrg                  result[nresult] = XCB_NO_SYMBOL;
262ecce36beSmrg              }
263ecce36beSmrg          }
264ecce36beSmrg  }
265ecce36beSmrg
266ecce36beSmrg  return result;
267ecce36beSmrg}
268ecce36beSmrg
269ecce36beSmrgxcb_keysym_t
270ecce36beSmrgxcb_key_press_lookup_keysym (xcb_key_symbols_t    *syms,
271ecce36beSmrg			 xcb_key_press_event_t *event,
272ecce36beSmrg			 int               col)
273ecce36beSmrg{
274ecce36beSmrg  return xcb_key_symbols_get_keysym (syms, event->detail, col);
275ecce36beSmrg}
276ecce36beSmrg
277ecce36beSmrgxcb_keysym_t
278ecce36beSmrgxcb_key_release_lookup_keysym (xcb_key_symbols_t      *syms,
279ecce36beSmrg			   xcb_key_release_event_t *event,
280ecce36beSmrg			   int                 col)
281ecce36beSmrg{
282ecce36beSmrg  return xcb_key_symbols_get_keysym (syms, event->detail, col);
283ecce36beSmrg}
284ecce36beSmrg
285ecce36beSmrgint
286ecce36beSmrgxcb_refresh_keyboard_mapping (xcb_key_symbols_t         *syms,
287ecce36beSmrg			   xcb_mapping_notify_event_t *event)
288ecce36beSmrg{
289ecce36beSmrg  if (event->request == XCB_MAPPING_KEYBOARD && syms) {
290ecce36beSmrg    if (syms->tag == TAG_VALUE) {
291ecce36beSmrg      xcb_keycode_t     min_keycode;
292ecce36beSmrg      xcb_keycode_t     max_keycode;
293ecce36beSmrg
294ecce36beSmrg      if (syms->u.reply) {
295ecce36beSmrg	free (syms->u.reply);
296ecce36beSmrg	syms->u.reply = NULL;
297ecce36beSmrg      }
298ecce36beSmrg      syms->tag = TAG_COOKIE;
299ecce36beSmrg      min_keycode = xcb_get_setup (syms->c)->min_keycode;
300ecce36beSmrg      max_keycode = xcb_get_setup (syms->c)->max_keycode;
301ecce36beSmrg
302ecce36beSmrg      syms->u.cookie = xcb_get_keyboard_mapping(syms->c,
303ecce36beSmrg					     min_keycode,
304ecce36beSmrg					     max_keycode - min_keycode + 1);
305ecce36beSmrg
306ecce36beSmrg    }
307ecce36beSmrg    return 1;
308ecce36beSmrg  }
309ecce36beSmrg  return 0;
310ecce36beSmrg}
311ecce36beSmrg
312ecce36beSmrg
313ecce36beSmrg/* Tests for classes of symbols */
314ecce36beSmrg
315ecce36beSmrgint
316ecce36beSmrgxcb_is_keypad_key (xcb_keysym_t keysym)
317ecce36beSmrg{
318ecce36beSmrg  return ((keysym >= XK_KP_Space) && (keysym <= XK_KP_Equal));
319ecce36beSmrg}
320ecce36beSmrg
321ecce36beSmrgint
322ecce36beSmrgxcb_is_private_keypad_key (xcb_keysym_t keysym)
323ecce36beSmrg{
324ecce36beSmrg  return ((keysym >= 0x11000000) && (keysym <= 0x1100FFFF));
325ecce36beSmrg}
326ecce36beSmrg
327ecce36beSmrgint
328ecce36beSmrgxcb_is_cursor_key (xcb_keysym_t keysym)
329ecce36beSmrg{
330ecce36beSmrg  return ((keysym >= XK_Home) && (keysym <= XK_Select));
331ecce36beSmrg}
332ecce36beSmrg
333ecce36beSmrgint
334ecce36beSmrgxcb_is_pf_key (xcb_keysym_t keysym)
335ecce36beSmrg{
336ecce36beSmrg  return ((keysym >= XK_KP_F1) && (keysym <= XK_KP_F4));
337ecce36beSmrg}
338ecce36beSmrg
339ecce36beSmrgint
340ecce36beSmrgxcb_is_function_key (xcb_keysym_t keysym)
341ecce36beSmrg{
342ecce36beSmrg  return ((keysym >= XK_F1) && (keysym <= XK_F35));
343ecce36beSmrg}
344ecce36beSmrg
345ecce36beSmrgint
346ecce36beSmrgxcb_is_misc_function_key (xcb_keysym_t keysym)
347ecce36beSmrg{
348ecce36beSmrg  return ((keysym >= XK_Select) && (keysym <= XK_Break));
349ecce36beSmrg}
350ecce36beSmrg
351ecce36beSmrgint
352ecce36beSmrgxcb_is_modifier_key (xcb_keysym_t keysym)
353ecce36beSmrg{
354ecce36beSmrg  return  (((keysym >= XK_Shift_L)  && (keysym <= XK_Hyper_R)) ||
355ecce36beSmrg	   ((keysym >= XK_ISO_Lock) && (keysym <= XK_ISO_Last_Group_Lock)) ||
356ecce36beSmrg	   (keysym == XK_Mode_switch) ||
357ecce36beSmrg	   (keysym == XK_Num_Lock));
358ecce36beSmrg}
359ecce36beSmrg
360ecce36beSmrg/* private functions */
361ecce36beSmrg
362ecce36beSmrgvoid
363ecce36beSmrgxcb_convert_case(xcb_keysym_t  sym,
364ecce36beSmrg	       xcb_keysym_t *lower,
365ecce36beSmrg	       xcb_keysym_t *upper)
366ecce36beSmrg{
367ecce36beSmrg  *lower = sym;
368ecce36beSmrg  *upper = sym;
369ecce36beSmrg
370ecce36beSmrg  switch(sym >> 8)
371ecce36beSmrg    {
372ecce36beSmrg    case 0: /* Latin 1 */
373ecce36beSmrg      if ((sym >= XK_A) && (sym <= XK_Z))
374ecce36beSmrg	*lower += (XK_a - XK_A);
375ecce36beSmrg      else if ((sym >= XK_a) && (sym <= XK_z))
376ecce36beSmrg	*upper -= (XK_a - XK_A);
377ecce36beSmrg      else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
378ecce36beSmrg	*lower += (XK_agrave - XK_Agrave);
379ecce36beSmrg      else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
380ecce36beSmrg	*upper -= (XK_agrave - XK_Agrave);
381ecce36beSmrg      else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
382ecce36beSmrg	*lower += (XK_oslash - XK_Ooblique);
383ecce36beSmrg      else if ((sym >= XK_oslash) && (sym <= XK_thorn))
384ecce36beSmrg	*upper -= (XK_oslash - XK_Ooblique);
385ecce36beSmrg      break;
386ecce36beSmrg    case 1: /* Latin 2 */
387ecce36beSmrg      /* Assume the KeySym is a legal value (ignore discontinuities) */
388ecce36beSmrg      if (sym == XK_Aogonek)
389ecce36beSmrg	*lower = XK_aogonek;
390ecce36beSmrg      else if (sym >= XK_Lstroke && sym <= XK_Sacute)
391ecce36beSmrg	*lower += (XK_lstroke - XK_Lstroke);
392ecce36beSmrg      else if (sym >= XK_Scaron && sym <= XK_Zacute)
393ecce36beSmrg	*lower += (XK_scaron - XK_Scaron);
394ecce36beSmrg      else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
395ecce36beSmrg	*lower += (XK_zcaron - XK_Zcaron);
396ecce36beSmrg      else if (sym == XK_aogonek)
397ecce36beSmrg	*upper = XK_Aogonek;
398ecce36beSmrg      else if (sym >= XK_lstroke && sym <= XK_sacute)
399ecce36beSmrg	*upper -= (XK_lstroke - XK_Lstroke);
400ecce36beSmrg      else if (sym >= XK_scaron && sym <= XK_zacute)
401ecce36beSmrg	*upper -= (XK_scaron - XK_Scaron);
402ecce36beSmrg      else if (sym >= XK_zcaron && sym <= XK_zabovedot)
403ecce36beSmrg	*upper -= (XK_zcaron - XK_Zcaron);
404ecce36beSmrg      else if (sym >= XK_Racute && sym <= XK_Tcedilla)
405ecce36beSmrg	*lower += (XK_racute - XK_Racute);
406ecce36beSmrg      else if (sym >= XK_racute && sym <= XK_tcedilla)
407ecce36beSmrg	*upper -= (XK_racute - XK_Racute);
408ecce36beSmrg      break;
409ecce36beSmrg    case 2: /* Latin 3 */
410ecce36beSmrg      /* Assume the KeySym is a legal value (ignore discontinuities) */
411ecce36beSmrg      if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
412ecce36beSmrg	*lower += (XK_hstroke - XK_Hstroke);
413ecce36beSmrg      else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
414ecce36beSmrg	*lower += (XK_gbreve - XK_Gbreve);
415ecce36beSmrg      else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
416ecce36beSmrg	*upper -= (XK_hstroke - XK_Hstroke);
417ecce36beSmrg      else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
418ecce36beSmrg	*upper -= (XK_gbreve - XK_Gbreve);
419ecce36beSmrg      else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
420ecce36beSmrg	*lower += (XK_cabovedot - XK_Cabovedot);
421ecce36beSmrg      else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
422ecce36beSmrg	*upper -= (XK_cabovedot - XK_Cabovedot);
423ecce36beSmrg      break;
424ecce36beSmrg    case 3: /* Latin 4 */
425ecce36beSmrg      /* Assume the KeySym is a legal value (ignore discontinuities) */
426ecce36beSmrg      if (sym >= XK_Rcedilla && sym <= XK_Tslash)
427ecce36beSmrg	*lower += (XK_rcedilla - XK_Rcedilla);
428ecce36beSmrg      else if (sym >= XK_rcedilla && sym <= XK_tslash)
429ecce36beSmrg	*upper -= (XK_rcedilla - XK_Rcedilla);
430ecce36beSmrg      else if (sym == XK_ENG)
431ecce36beSmrg	*lower = XK_eng;
432ecce36beSmrg      else if (sym == XK_eng)
433ecce36beSmrg	*upper = XK_ENG;
434ecce36beSmrg      else if (sym >= XK_Amacron && sym <= XK_Umacron)
435ecce36beSmrg	*lower += (XK_amacron - XK_Amacron);
436ecce36beSmrg      else if (sym >= XK_amacron && sym <= XK_umacron)
437ecce36beSmrg	*upper -= (XK_amacron - XK_Amacron);
438ecce36beSmrg      break;
439ecce36beSmrg    case 6: /* Cyrillic */
440ecce36beSmrg      /* Assume the KeySym is a legal value (ignore discontinuities) */
441ecce36beSmrg      if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
442ecce36beSmrg	*lower -= (XK_Serbian_DJE - XK_Serbian_dje);
443ecce36beSmrg      else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
444ecce36beSmrg	*upper += (XK_Serbian_DJE - XK_Serbian_dje);
445ecce36beSmrg      else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
446ecce36beSmrg	*lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
447ecce36beSmrg      else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
448ecce36beSmrg	*upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
449ecce36beSmrg      break;
450ecce36beSmrg    case 7: /* Greek */
451ecce36beSmrg      /* Assume the KeySym is a legal value (ignore discontinuities) */
452ecce36beSmrg      if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
453ecce36beSmrg	*lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
454ecce36beSmrg      else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
455ecce36beSmrg	       sym != XK_Greek_iotaaccentdieresis &&
456ecce36beSmrg	       sym != XK_Greek_upsilonaccentdieresis)
457ecce36beSmrg	*upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
458ecce36beSmrg      else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
459ecce36beSmrg	*lower += (XK_Greek_alpha - XK_Greek_ALPHA);
460ecce36beSmrg      else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
461ecce36beSmrg	       sym != XK_Greek_finalsmallsigma)
462ecce36beSmrg	*upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
463ecce36beSmrg      break;
464ecce36beSmrg    case 0x14: /* Armenian */
465ecce36beSmrg      if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
466ecce36beSmrg	*lower = sym | 1;
467ecce36beSmrg	*upper = sym & ~1;
468ecce36beSmrg      }
469ecce36beSmrg      break;
470ecce36beSmrg    }
471ecce36beSmrg}
472ecce36beSmrg
473ecce36beSmrgvoid
474ecce36beSmrgxcb_key_symbols_get_reply (xcb_key_symbols_t    *syms,
475ecce36beSmrg		       xcb_generic_error_t **e)
476ecce36beSmrg{
477ecce36beSmrg  if (!syms)
478ecce36beSmrg    return;
479ecce36beSmrg
480ecce36beSmrg  if (syms->tag == TAG_COOKIE)
481ecce36beSmrg    {
482ecce36beSmrg      syms->tag = TAG_VALUE;
483ecce36beSmrg      syms->u.reply = xcb_get_keyboard_mapping_reply(syms->c,
484ecce36beSmrg						 syms->u.cookie,
485ecce36beSmrg						 e);
486ecce36beSmrg    }
487ecce36beSmrg}
488