source: branches/profile/WINDOW/AW_xkey.cxx

Last change on this file was 7888, checked in by westram, 13 years ago
  • added a fake ctor to AW_root (for unit-tests only)
    • initializes AWAR subsystem, w/o doing any X-stuff
    • use it in TEST_advice_id_awar_handling (failed when unit-test ran via cron)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_xkey.cxx                                       //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_keysym.hxx"
12#include "aw_xkey.hxx"
13#include "aw_msg.hxx"
14
15#include <arbdbt.h>
16#include <arb_defs.h>
17
18#include <X11/Xlib.h>
19#include <X11/keysym.h>
20#include <X11/Xutil.h>
21
22#ifndef aw_assert
23#define aw_assert(bed) arb_assert(bed)
24#endif
25
26// for keysyms see /usr/include/X11/keysymdef.h
27
28
29// each entry in awxkeymap_modfree generates 9 entries : 2*SHIFT, 2*ALT, 2*META, 2*CTRL, 1 unMODified
30// see awModDef below
31static awXKeymap_modfree awxkeymap_modfree[] = {
32    { XK_Left,   "Left",   AW_KEY_LEFT },
33    { XK_Right,  "Right",  AW_KEY_RIGHT },
34    { XK_Up,     "Up",     AW_KEY_UP },
35    { XK_Down,   "Down",   AW_KEY_DOWN },
36    { XK_Home,   "Home",   AW_KEY_HOME },
37    { XK_End,    "End",    AW_KEY_END },
38    { XK_Delete, "Delete", AW_KEY_DELETE }, // was same as BackSpace in the past -- 2007/11/15
39
40    { 0, 0, AW_KEY_NONE },
41};
42
43// manual key defs
44// keys where all (or most) modifiers don't work should go here
45static awXKeymap awxkeymap[] = {
46    // sun keypad ?
47    { XK_Shift_R, XK_R10, "Shift-Left",  AW_KEYMODE_SHIFT, AW_KEY_LEFT,  0 },
48    { XK_Shift_R, XK_R12, "Shift-Right", AW_KEYMODE_SHIFT, AW_KEY_RIGHT, 0 },
49    { XK_Shift_L, XK_R10, "Shift-Left",  AW_KEYMODE_SHIFT, AW_KEY_LEFT,  0 },
50    { XK_Shift_L, XK_R12, "Shift-Right", AW_KEYMODE_SHIFT, AW_KEY_RIGHT, 0 },
51    { 0,          XK_R7,  "Home",        AW_KEYMODE_NONE,  AW_KEY_HOME,  0 },
52    { 0,          XK_R13, "End",         AW_KEYMODE_NONE,  AW_KEY_END,   0 },
53
54    // functions keys
55    { 0, XK_F1,  0, AW_KEYMODE_NONE, AW_KEY_F1,  0 },
56    { 0, XK_F2,  0, AW_KEYMODE_NONE, AW_KEY_F2,  0 },
57    { 0, XK_F3,  0, AW_KEYMODE_NONE, AW_KEY_F3,  0 },
58    { 0, XK_F4,  0, AW_KEYMODE_NONE, AW_KEY_F4,  0 },
59    { 0, XK_F5,  0, AW_KEYMODE_NONE, AW_KEY_F5,  0 },
60    { 0, XK_F6,  0, AW_KEYMODE_NONE, AW_KEY_F6,  0 },
61    { 0, XK_F7,  0, AW_KEYMODE_NONE, AW_KEY_F7,  0 },
62    { 0, XK_F8,  0, AW_KEYMODE_NONE, AW_KEY_F8,  0 },
63    { 0, XK_F9,  0, AW_KEYMODE_NONE, AW_KEY_F9,  0 },
64    { 0, XK_F10, 0, AW_KEYMODE_NONE, AW_KEY_F10, 0 },
65    { 0, XK_F11, 0, AW_KEYMODE_NONE, AW_KEY_F11, 0 },
66    { 0, XK_F12, 0, AW_KEYMODE_NONE, AW_KEY_F12, 0 },
67
68    // other
69    { 0, XK_BackSpace, "BackSpace", AW_KEYMODE_NONE, AW_KEY_BACKSPACE, 0 },
70    { 0, XK_Help,      0,           AW_KEYMODE_NONE, AW_KEY_HELP,      0 },
71    { 0, XK_Escape,    0,           AW_KEYMODE_NONE, AW_KEY_ESCAPE,    0 },
72    { 0, XK_Return,    0,           AW_KEYMODE_NONE, AW_KEY_RETURN,    0 },
73    { 0, XK_Tab,       0,           AW_KEYMODE_NONE, AW_KEY_RETURN,    0 }, // done to accept input-field-changes via TAB, also disables inserting tabs
74
75    { 0, 0, (char*)1, AW_KEYMODE_NONE, AW_KEY_NONE, 0 }
76};
77
78struct awModDef {
79    int         xmod;
80    const char *xstr_prefix;
81    AW_key_mod  awmod;
82};
83
84static awModDef moddef[] = {
85    { XK_Shift_L,   "Shift",   AW_KEYMODE_SHIFT },
86    { XK_Shift_R,   "Shift",   AW_KEYMODE_SHIFT },
87    { XK_Meta_L,    "Meta",    AW_KEYMODE_ALT },     // handle Meta as Alt
88    { XK_Meta_R,    "Meta",    AW_KEYMODE_ALT },
89    { XK_Alt_L,     "Alt",     AW_KEYMODE_ALT },
90    { XK_Alt_R,     "Alt",     AW_KEYMODE_ALT },
91    { XK_Control_L, "Control", AW_KEYMODE_CONTROL },
92    { XK_Control_R, "Control", AW_KEYMODE_CONTROL },
93    { 0,            0,         AW_KEYMODE_NONE },   // "no modifier" (this is NO array terminator!)
94};
95
96const int FIXEDMOD = TERMINATED_ARRAY_ELEMS(awxkeymap);
97const int MODFREE  = TERMINATED_ARRAY_ELEMS(awxkeymap_modfree);
98const int MODS     = ARRAY_ELEMS(moddef);
99
100static GB_HASH    *awxkeymap_string_2_key_hash;
101static GB_NUMHASH *awxkeymap_xkey_2_key_hash;
102static int         generatedKeymaps_count = -1;
103static awXKeymap  *generatedKeymaps       = 0;
104
105
106const int MAPPED_KEYS = MODFREE*MODS+FIXEDMOD;
107
108#if defined(ASSERTION_USED)
109static int mappedKeys = 0;
110#endif // ASSERTION_USED
111
112static void map_awXKey(Display *display, const awXKeymap *awxk) {
113    if (awxk->xstr) {
114        KeySym modlist[2];
115        int    modsize;
116
117        modlist[0] = awxk->xmod;
118        modsize    = modlist[0] ? 1 : 0;
119
120        XRebindKeysym(display, awxk->xkey, modlist, modsize,
121                      (unsigned char*)awxk->xstr, strlen(awxk->xstr));
122
123        GBS_write_hash(awxkeymap_string_2_key_hash, awxk->xstr, (long)awxk);
124    }
125    GBS_write_numhash(awxkeymap_xkey_2_key_hash, awxk->xkey, (long)awxk);
126
127#if defined(ASSERTION_USED)
128    ++mappedKeys;
129#endif // ASSERTION_USED
130}
131
132void aw_install_xkeys(Display *display) {
133    int i;
134
135    awxkeymap_string_2_key_hash = GBS_create_hash(MAPPED_KEYS, GB_MIND_CASE);
136    awxkeymap_xkey_2_key_hash   = GBS_create_numhash(MAPPED_KEYS);
137
138    // auto-generate all key/modifier combinations for keys in awxkeymap_modfree
139    for (i=0; ; ++i) {
140        if (awxkeymap_modfree[i].xstr_suffix == 0) break;
141    }
142
143    int modfree = i;
144
145    aw_assert(generatedKeymaps == 0);               // oops - called twice
146   
147    generatedKeymaps_count = modfree*MODS;
148    generatedKeymaps       = (awXKeymap*)GB_calloc(generatedKeymaps_count, sizeof(*generatedKeymaps));
149
150    for (i=0; i<modfree; ++i) {
151        const awXKeymap_modfree *mf = awxkeymap_modfree+i;
152        for (int j = 0; j<MODS; ++j) {
153            awXKeymap *km = generatedKeymaps+i*MODS+j;
154            awModDef  *md = moddef+j;
155
156            km->xmod  = md->xmod;
157            km->xkey  = mf->xkey;
158            km->xstr  = md->xstr_prefix ? GBS_global_string_copy("%s-%s", md->xstr_prefix, mf->xstr_suffix) : mf->xstr_suffix;
159            km->awmod = md->awmod;
160            km->awkey = mf->awkey;
161            km->awstr = 0;
162
163            map_awXKey(display, km);
164        }
165    }
166
167    // add manually defined keys
168    for (i=0; ; ++i) {
169        if (awxkeymap[i].xstr == (char*)1) break;
170        map_awXKey(display, awxkeymap+i);
171    }
172
173    aw_assert(mappedKeys == MAPPED_KEYS);
174}
175
176void aw_uninstall_xkeys() {
177    for (int i = 0; i<generatedKeymaps_count; ++i) {
178        awXKeymap& km = generatedKeymaps[i];
179        int        j  = i%MODS;
180        awModDef&  md = moddef[j];
181
182        if (md.xstr_prefix) free((char*)km.xstr);
183    }
184    free(generatedKeymaps); generatedKeymaps = NULL;
185
186    if (awxkeymap_xkey_2_key_hash) GBS_free_numhash(awxkeymap_xkey_2_key_hash); awxkeymap_xkey_2_key_hash  = NULL;
187    if (awxkeymap_string_2_key_hash) GBS_free_hash(awxkeymap_string_2_key_hash); awxkeymap_string_2_key_hash = NULL;
188}
189
190#if defined(DEBUG)
191// #define DUMP_KEYEVENTS
192#endif // DEBUG
193
194const awXKeymap *aw_xkey_2_awkey(XKeyEvent *xkeyevent) {
195    awXKeymap *result;
196    static awXKeymap singlekey = { 0, 0, 0, AW_KEYMODE_NONE, AW_KEY_NONE, 0 };
197    bool numlockwason = false;
198
199    if (xkeyevent->state & AW_KEYMODE_NUMLOCK) {    // numlock is active
200        xkeyevent->state &= ~AW_KEYMODE_NUMLOCK;    // ignore NUMLOCK
201        numlockwason      = true;
202    }
203
204    const int   BUFFERSIZE = 256;;
205    static char buffer[BUFFERSIZE];
206    KeySym      keysym;
207    int         count      = XLookupString(xkeyevent, buffer, BUFFERSIZE, &keysym, NULL);
208    buffer[count]          = 0;
209
210    if (!buffer[0] && count) {
211#if defined(DUMP_KEYEVENTS)
212        printf("special case: Ctrl-Space\n");
213#endif
214        aw_assert(keysym == XK_space);
215        buffer[0] = ' ';
216    }
217
218#if defined(DUMP_KEYEVENTS)
219    printf("state=%u keycode=%u name='%s' ", xkeyevent->state, xkeyevent->keycode, buffer);
220#endif // DUMP_KEYEVENTS
221
222    if (keysym >= XK_space && keysym <= XK_asciitilde) {
223        singlekey.awkey = AW_KEY_ASCII;
224        singlekey.awmod = (AW_key_mod)(xkeyevent->state & (AW_KEYMODE_CONTROL|AW_KEYMODE_ALT));  // forward ctrl and alt state
225        singlekey.awstr = buffer;
226        aw_assert(buffer[0]);
227
228        result = &singlekey;
229
230        if (numlockwason && (xkeyevent->state & AW_KEYMODE_ALT)) {
231            static bool warned = false;
232            if (!warned) {
233                aw_message("Warning: Accelerator keys only work if NUMLOCK is off!");
234                warned = true;
235            }
236        }
237
238#if defined(DUMP_KEYEVENTS)
239        printf("AW_KEY_ASCII:");
240#endif // DUMP_KEYEVENTS
241    }
242    else {
243        long ptr;
244
245        if (count && (ptr = GBS_read_hash(awxkeymap_string_2_key_hash, buffer))) {
246            result    = (awXKeymap*)ptr;
247
248#if defined(DUMP_KEYEVENTS)
249            printf("_awxkeymap_string_2_key_hash['%s']=", buffer);
250#endif // DUMP_KEYEVENTS
251        }
252        else if ((ptr = GBS_read_numhash(awxkeymap_xkey_2_key_hash, keysym))) {
253            result    = (awXKeymap*)ptr;
254
255#if defined(DUMP_KEYEVENTS)
256            printf("_awxkeymap_xkey_2_key_hash['%x']='%s'", (unsigned)keysym, result->xstr);
257#endif // DUMP_KEYEVENTS
258        }
259        else {
260            singlekey.awkey = AW_KEY_NONE;
261            singlekey.awmod = AW_KEYMODE_NONE;
262            singlekey.awstr = 0;
263
264            result = &singlekey;
265
266#if defined(DUMP_KEYEVENTS)
267            printf("Undefined key (keysym=%x)", (unsigned)keysym);
268            if (count) printf(" name='%s'", buffer);
269#endif // DUMP_KEYEVENTS
270        }
271    }
272#if defined(DUMP_KEYEVENTS)
273    printf(" key='%u' mod='%u' awstr='%s'\n", result->awkey, result->awmod, result->awstr);
274#endif // DUMP_KEYEVENTS
275
276    return result;
277}
278
Note: See TracBrowser for help on using the repository browser.