summaryrefslogtreecommitdiff
path: root/dist/xcb-util/keysyms/keysyms.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2009-05-23 14:38:22 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2009-05-23 14:38:22 +0000
commit86bb951017acff65627eb198fe1fa4c73b46aad4 (patch)
tree18afd632e81d724b548b60373016d1459dfce5f3 /dist/xcb-util/keysyms/keysyms.c
parent013b4a3065ff281c23c32277f08a521fd7922c23 (diff)
import xcb-util 0.3.4
Diffstat (limited to 'dist/xcb-util/keysyms/keysyms.c')
-rw-r--r--dist/xcb-util/keysyms/keysyms.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/dist/xcb-util/keysyms/keysyms.c b/dist/xcb-util/keysyms/keysyms.c
new file mode 100644
index 000000000..c3e7f2e49
--- /dev/null
+++ b/dist/xcb-util/keysyms/keysyms.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright © 2008 Ian Osgood <iano@quirkster.com>
+ * Copyright © 2008 Jamey Sharp <jamey@minilop.net>
+ * Copyright © 2008 Josh Triplett <josh@freedesktop.org>
+ * Copyright © 2008 Ulrich Eckhardt <doomster@knuut.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors or
+ * their institutions shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without
+ * prior written authorization from the authors.
+ */
+
+#include <stdlib.h>
+
+#include <xcb/xcb.h>
+#define XK_MISCELLANY
+#define XK_XKB_KEYS
+#define XK_LATIN1
+#define XK_LATIN2
+#define XK_LATIN3
+#define XK_LATIN4
+#define XK_CYRILLIC
+#define XK_GREEK
+#define XK_ARMENIAN
+#include <X11/keysymdef.h>
+
+#include "xcb_keysyms.h"
+
+/* Private declaration */
+enum tag_t {
+ TAG_COOKIE,
+ TAG_VALUE
+};
+
+struct _XCBKeySymbols
+{
+ xcb_connection_t *c;
+ enum tag_t tag;
+ union {
+ xcb_get_keyboard_mapping_cookie_t cookie;
+ xcb_get_keyboard_mapping_reply_t *reply;
+ } u;
+};
+
+static void xcb_convert_case(xcb_keysym_t sym,
+ xcb_keysym_t *lower,
+ xcb_keysym_t *upper);
+
+static void xcb_key_symbols_get_reply (xcb_key_symbols_t *syms,
+ xcb_generic_error_t **e);
+
+/* public implementation */
+
+xcb_key_symbols_t *
+xcb_key_symbols_alloc (xcb_connection_t *c)
+{
+ xcb_key_symbols_t *syms;
+ xcb_keycode_t min_keycode;
+ xcb_keycode_t max_keycode;
+
+ if (!c)
+ return NULL;
+
+ syms = malloc (sizeof (xcb_key_symbols_t));
+
+ syms->c = c;
+ syms->tag = TAG_COOKIE;
+
+ min_keycode = xcb_get_setup (c)->min_keycode;
+ max_keycode = xcb_get_setup (c)->max_keycode;
+
+ syms->u.cookie = xcb_get_keyboard_mapping(c,
+ min_keycode,
+ max_keycode - min_keycode + 1);
+
+ return syms;
+}
+
+void
+xcb_key_symbols_free (xcb_key_symbols_t *syms)
+{
+ if (syms)
+ {
+ if (syms->tag == TAG_VALUE)
+ free (syms->u.reply);
+ free (syms);
+ syms = NULL;
+ }
+}
+
+/* Use of the 'col' parameter:
+
+A list of KeySyms is associated with each KeyCode. The list is intended
+to convey the set of symbols on the corresponding key. If the list
+(ignoring trailing NoSymbol entries) is a single KeySym ``K'', then the
+list is treated as if it were the list ``K NoSymbol K NoSymbol''. If the
+list (ignoring trailing NoSymbol entries) is a pair of KeySyms ``K1
+K2'', then the list is treated as if it were the list ``K1 K2 K1 K2''.
+If the list (ignoring trailing NoSymbol entries) is a triple of KeySyms
+``K1 K2 K3'', then the list is treated as if it were the list ``K1 K2 K3
+NoSymbol''. When an explicit ``void'' element is desired in the list,
+the value VoidSymbol can be used.
+
+The first four elements of the list are split into two groups of
+KeySyms. Group 1 contains the first and second KeySyms; Group 2 contains
+the third and fourth KeySyms. Within each group, if the second element
+of the group is NoSymbol , then the group should be treated as if the
+second element were the same as the first element, except when the first
+element is an alphabetic KeySym ``K'' for which both lowercase and
+uppercase forms are defined. In that case, the group should be treated
+as if the first element were the lowercase form of ``K'' and the second
+element were the uppercase form of ``K.''
+
+The standard rules for obtaining a KeySym from a KeyPress event make use
+of only the Group 1 and Group 2 KeySyms; no interpretation of other
+KeySyms in the list is given. Which group to use is determined by the
+modifier state. Switching between groups is controlled by the KeySym
+named MODE SWITCH, by attaching that KeySym to some KeyCode and
+attaching that KeyCode to any one of the modifiers Mod1 through Mod5.
+This modifier is called the group modifier. For any KeyCode, Group 1 is
+used when the group modifier is off, and Group 2 is used when the group
+modifier is on.
+
+The Lock modifier is interpreted as CapsLock when the KeySym named
+XK_Caps_Lock is attached to some KeyCode and that KeyCode is attached to
+the Lock modifier. The Lock modifier is interpreted as ShiftLock when
+the KeySym named XK_Shift_Lock is attached to some KeyCode and that
+KeyCode is attached to the Lock modifier. If the Lock modifier could be
+interpreted as both CapsLock and ShiftLock, the CapsLock interpretation
+is used.
+
+The operation of keypad keys is controlled by the KeySym named
+XK_Num_Lock, by attaching that KeySym to some KeyCode and attaching that
+KeyCode to any one of the modifiers Mod1 through Mod5 . This modifier is
+called the numlock modifier. The standard KeySyms with the prefix
+``XK_KP_'' in their name are called keypad KeySyms; these are KeySyms
+with numeric value in the hexadecimal range 0xFF80 to 0xFFBD inclusive.
+In addition, vendor-specific KeySyms in the hexadecimal range 0x11000000
+to 0x1100FFFF are also keypad KeySyms.
+
+Within a group, the choice of KeySym is determined by applying the first
+rule that is satisfied from the following list:
+
+* The numlock modifier is on and the second KeySym is a keypad KeySym. In
+ this case, if the Shift modifier is on, or if the Lock modifier is on
+ and is interpreted as ShiftLock, then the first KeySym is used,
+ otherwise the second KeySym is used.
+
+* The Shift and Lock modifiers are both off. In this case, the first
+ KeySym is used.
+
+* The Shift modifier is off, and the Lock modifier is on and is
+ interpreted as CapsLock. In this case, the first KeySym is used, but
+ if that KeySym is lowercase alphabetic, then the corresponding
+ uppercase KeySym is used instead.
+
+* The Shift modifier is on, and the Lock modifier is on and is
+ interpreted as CapsLock. In this case, the second KeySym is used, but
+ if that KeySym is lowercase alphabetic, then the corresponding
+ uppercase KeySym is used instead.
+
+* The Shift modifier is on, or the Lock modifier is on and is
+ interpreted as ShiftLock, or both. In this case, the second KeySym is
+ used.
+
+*/
+
+xcb_keysym_t xcb_key_symbols_get_keysym (xcb_key_symbols_t *syms,
+ xcb_keycode_t keycode,
+ int col)
+{
+ xcb_keysym_t *keysyms;
+ xcb_keysym_t keysym_null = { XCB_NO_SYMBOL };
+ xcb_keysym_t lsym;
+ xcb_keysym_t usym;
+ xcb_keycode_t min_keycode;
+ xcb_keycode_t max_keycode;
+ int per;
+
+ if (!syms)
+ return keysym_null;
+
+ xcb_key_symbols_get_reply (syms, NULL);
+
+ keysyms = xcb_get_keyboard_mapping_keysyms (syms->u.reply);
+ min_keycode = xcb_get_setup (syms->c)->min_keycode;
+ max_keycode = xcb_get_setup (syms->c)->max_keycode;
+
+ per = syms->u.reply->keysyms_per_keycode;
+ if ((col < 0) || ((col >= per) && (col > 3)) ||
+ (keycode < min_keycode) ||
+ (keycode > max_keycode))
+ return keysym_null;
+
+ keysyms = &keysyms[(keycode - min_keycode) * per];
+ if (col < 4)
+ {
+ if (col > 1)
+ {
+ while ((per > 2) && (keysyms[per - 1] == XCB_NO_SYMBOL))
+ per--;
+ if (per < 3)
+ col -= 2;
+ }
+ if ((per <= (col|1)) || (keysyms[col|1] == XCB_NO_SYMBOL))
+ {
+ xcb_convert_case(keysyms[col&~1], &lsym, &usym);
+ if (!(col & 1))
+ return lsym;
+ else if (usym == lsym)
+ return keysym_null;
+ else
+ return usym;
+ }
+ }
+ return keysyms[col];
+}
+
+xcb_keycode_t *
+xcb_key_symbols_get_keycode(xcb_key_symbols_t *syms,
+ xcb_keysym_t keysym)
+{
+ xcb_keysym_t ks;
+ int j, nresult = 0;
+ xcb_keycode_t i, min, max, *result = NULL;
+
+ if(syms)
+ {
+ xcb_key_symbols_get_reply (syms, NULL);
+ min = xcb_get_setup(syms->c)->min_keycode;
+ max = xcb_get_setup(syms->c)->max_keycode;
+
+ for(j = 0; j < syms->u.reply->keysyms_per_keycode; j++)
+ for(i = min; i && i <= max; i++)
+ {
+ ks = xcb_key_symbols_get_keysym(syms, i, j);
+ if(ks == keysym)
+ {
+ nresult++;
+ result = realloc(result, sizeof(xcb_keycode_t) * (nresult + 1));
+ result[nresult - 1] = i;
+ result[nresult] = XCB_NO_SYMBOL;
+ }
+ }
+ }
+
+ return result;
+}
+
+xcb_keysym_t
+xcb_key_press_lookup_keysym (xcb_key_symbols_t *syms,
+ xcb_key_press_event_t *event,
+ int col)
+{
+ return xcb_key_symbols_get_keysym (syms, event->detail, col);
+}
+
+xcb_keysym_t
+xcb_key_release_lookup_keysym (xcb_key_symbols_t *syms,
+ xcb_key_release_event_t *event,
+ int col)
+{
+ return xcb_key_symbols_get_keysym (syms, event->detail, col);
+}
+
+int
+xcb_refresh_keyboard_mapping (xcb_key_symbols_t *syms,
+ xcb_mapping_notify_event_t *event)
+{
+ if (event->request == XCB_MAPPING_KEYBOARD && syms) {
+ if (syms->tag == TAG_VALUE) {
+ xcb_keycode_t min_keycode;
+ xcb_keycode_t max_keycode;
+
+ if (syms->u.reply) {
+ free (syms->u.reply);
+ syms->u.reply = NULL;
+ }
+ syms->tag = TAG_COOKIE;
+ min_keycode = xcb_get_setup (syms->c)->min_keycode;
+ max_keycode = xcb_get_setup (syms->c)->max_keycode;
+
+ syms->u.cookie = xcb_get_keyboard_mapping(syms->c,
+ min_keycode,
+ max_keycode - min_keycode + 1);
+
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Tests for classes of symbols */
+
+int
+xcb_is_keypad_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= XK_KP_Space) && (keysym <= XK_KP_Equal));
+}
+
+int
+xcb_is_private_keypad_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= 0x11000000) && (keysym <= 0x1100FFFF));
+}
+
+int
+xcb_is_cursor_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= XK_Home) && (keysym <= XK_Select));
+}
+
+int
+xcb_is_pf_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= XK_KP_F1) && (keysym <= XK_KP_F4));
+}
+
+int
+xcb_is_function_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= XK_F1) && (keysym <= XK_F35));
+}
+
+int
+xcb_is_misc_function_key (xcb_keysym_t keysym)
+{
+ return ((keysym >= XK_Select) && (keysym <= XK_Break));
+}
+
+int
+xcb_is_modifier_key (xcb_keysym_t keysym)
+{
+ return (((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R)) ||
+ ((keysym >= XK_ISO_Lock) && (keysym <= XK_ISO_Last_Group_Lock)) ||
+ (keysym == XK_Mode_switch) ||
+ (keysym == XK_Num_Lock));
+}
+
+/* private functions */
+
+void
+xcb_convert_case(xcb_keysym_t sym,
+ xcb_keysym_t *lower,
+ xcb_keysym_t *upper)
+{
+ *lower = sym;
+ *upper = sym;
+
+ switch(sym >> 8)
+ {
+ case 0: /* Latin 1 */
+ if ((sym >= XK_A) && (sym <= XK_Z))
+ *lower += (XK_a - XK_A);
+ else if ((sym >= XK_a) && (sym <= XK_z))
+ *upper -= (XK_a - XK_A);
+ else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+ *lower += (XK_agrave - XK_Agrave);
+ else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+ *upper -= (XK_agrave - XK_Agrave);
+ else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+ *lower += (XK_oslash - XK_Ooblique);
+ else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+ *upper -= (XK_oslash - XK_Ooblique);
+ break;
+ case 1: /* Latin 2 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym == XK_Aogonek)
+ *lower = XK_aogonek;
+ else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+ *lower += (XK_lstroke - XK_Lstroke);
+ else if (sym >= XK_Scaron && sym <= XK_Zacute)
+ *lower += (XK_scaron - XK_Scaron);
+ else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+ *lower += (XK_zcaron - XK_Zcaron);
+ else if (sym == XK_aogonek)
+ *upper = XK_Aogonek;
+ else if (sym >= XK_lstroke && sym <= XK_sacute)
+ *upper -= (XK_lstroke - XK_Lstroke);
+ else if (sym >= XK_scaron && sym <= XK_zacute)
+ *upper -= (XK_scaron - XK_Scaron);
+ else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+ *upper -= (XK_zcaron - XK_Zcaron);
+ else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+ *lower += (XK_racute - XK_Racute);
+ else if (sym >= XK_racute && sym <= XK_tcedilla)
+ *upper -= (XK_racute - XK_Racute);
+ break;
+ case 2: /* Latin 3 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+ *lower += (XK_hstroke - XK_Hstroke);
+ else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+ *lower += (XK_gbreve - XK_Gbreve);
+ else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+ *upper -= (XK_hstroke - XK_Hstroke);
+ else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+ *upper -= (XK_gbreve - XK_Gbreve);
+ else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+ *lower += (XK_cabovedot - XK_Cabovedot);
+ else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+ *upper -= (XK_cabovedot - XK_Cabovedot);
+ break;
+ case 3: /* Latin 4 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+ *lower += (XK_rcedilla - XK_Rcedilla);
+ else if (sym >= XK_rcedilla && sym <= XK_tslash)
+ *upper -= (XK_rcedilla - XK_Rcedilla);
+ else if (sym == XK_ENG)
+ *lower = XK_eng;
+ else if (sym == XK_eng)
+ *upper = XK_ENG;
+ else if (sym >= XK_Amacron && sym <= XK_Umacron)
+ *lower += (XK_amacron - XK_Amacron);
+ else if (sym >= XK_amacron && sym <= XK_umacron)
+ *upper -= (XK_amacron - XK_Amacron);
+ break;
+ case 6: /* Cyrillic */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+ *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+ else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+ *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+ else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+ *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+ else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+ *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+ break;
+ case 7: /* Greek */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+ *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+ else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+ sym != XK_Greek_iotaaccentdieresis &&
+ sym != XK_Greek_upsilonaccentdieresis)
+ *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+ else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+ *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+ else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+ sym != XK_Greek_finalsmallsigma)
+ *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+ break;
+ case 0x14: /* Armenian */
+ if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
+ *lower = sym | 1;
+ *upper = sym & ~1;
+ }
+ break;
+ }
+}
+
+void
+xcb_key_symbols_get_reply (xcb_key_symbols_t *syms,
+ xcb_generic_error_t **e)
+{
+ if (!syms)
+ return;
+
+ if (syms->tag == TAG_COOKIE)
+ {
+ syms->tag = TAG_VALUE;
+ syms->u.reply = xcb_get_keyboard_mapping_reply(syms->c,
+ syms->u.cookie,
+ e);
+ }
+}