source: psi/trunk/src/tools/globalaccel/globalaccelman_x11.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 9.9 KB
Line 
1/*
2 * globalaccelman_x11.cpp - manager for global hotkeys
3 * Copyright (C) 2003 Justin Karneges
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include"globalaccelman.h"
22
23#include<qkeysequence.h>
24#include<qwidget.h>
25#include<qapplication.h>
26
27#include<X11/X.h>
28#include<X11/Xlib.h>
29#include<X11/keysym.h>
30
31#ifdef KeyPress
32// defined by X11 headers
33const int XKeyPress = KeyPress;
34const int XKeyRelease = KeyRelease;
35#undef KeyPress
36#endif
37
38struct QT_XK_KEYGROUP
39{
40 char num;
41 int sym[3];
42};
43
44struct QT_XK_KEYMAP
45{
46 int key;
47 QT_XK_KEYGROUP xk;
48} qt_xk_table[] = {
49 { Qt::Key_Escape, {1, { XK_Escape }}},
50 { Qt::Key_Tab, {2, { XK_Tab, XK_KP_Tab }}},
51 { Qt::Key_Backtab, {1, { XK_ISO_Left_Tab }}},
52 { Qt::Key_Backspace, {1, { XK_BackSpace }}},
53 { Qt::Key_Return, {1, { XK_Return }}},
54 { Qt::Key_Enter, {1, { XK_KP_Enter }}},
55 { Qt::Key_Insert, {2, { XK_Insert, XK_KP_Insert }}},
56 { Qt::Key_Delete, {3, { XK_Delete, XK_KP_Delete, XK_Clear }}},
57 { Qt::Key_Pause, {1, { XK_Pause }}},
58 { Qt::Key_Print, {1, { XK_Print }}},
59 { Qt::Key_SysReq, {1, { XK_Sys_Req }}},
60 { Qt::Key_Clear, {1, { XK_KP_Begin }}},
61 { Qt::Key_Home, {2, { XK_Home, XK_KP_Home }}},
62 { Qt::Key_End, {2, { XK_End, XK_KP_End }}},
63 { Qt::Key_Left, {2, { XK_Left, XK_KP_Left }}},
64 { Qt::Key_Up, {2, { XK_Up, XK_KP_Up }}},
65 { Qt::Key_Right, {2, { XK_Right, XK_KP_Right }}},
66 { Qt::Key_Down, {2, { XK_Down, XK_KP_Down }}},
67 { Qt::Key_Prior, {2, { XK_Prior, XK_KP_Prior }}},
68 { Qt::Key_Next, {2, { XK_Next, XK_KP_Next }}},
69 { Qt::Key_Shift, {3, { XK_Shift_L, XK_Shift_R, XK_Shift_Lock }}},
70 { Qt::Key_Control, {2, { XK_Control_L, XK_Control_R }}},
71 { Qt::Key_Meta, {2, { XK_Meta_L, XK_Meta_R }}},
72 { Qt::Key_Alt, {2, { XK_Alt_L, XK_Alt_R }}},
73 { Qt::Key_CapsLock, {1, { XK_Caps_Lock }}},
74 { Qt::Key_NumLock, {1, { XK_Num_Lock }}},
75 { Qt::Key_ScrollLock, {1, { XK_Scroll_Lock }}},
76 { Qt::Key_Space, {2, { XK_space, XK_KP_Space }}},
77 { Qt::Key_Equal, {2, { XK_equal, XK_KP_Equal }}},
78 { Qt::Key_Asterisk, {2, { XK_asterisk, XK_KP_Multiply }}},
79 { Qt::Key_Plus, {2, { XK_plus, XK_KP_Add }}},
80 { Qt::Key_Comma, {2, { XK_comma, XK_KP_Separator }}},
81 { Qt::Key_Minus, {2, { XK_minus, XK_KP_Subtract }}},
82 { Qt::Key_Period, {2, { XK_period, XK_KP_Decimal }}},
83 { Qt::Key_Slash, {2, { XK_slash, XK_KP_Divide }}},
84 { Qt::Key_F1, {1, { XK_F1 }}},
85 { Qt::Key_F2, {1, { XK_F2 }}},
86 { Qt::Key_F3, {1, { XK_F3 }}},
87 { Qt::Key_F4, {1, { XK_F4 }}},
88 { Qt::Key_F5, {1, { XK_F5 }}},
89 { Qt::Key_F6, {1, { XK_F6 }}},
90 { Qt::Key_F7, {1, { XK_F7 }}},
91 { Qt::Key_F8, {1, { XK_F8 }}},
92 { Qt::Key_F9, {1, { XK_F9 }}},
93 { Qt::Key_F10, {1, { XK_F10 }}},
94 { Qt::Key_F11, {1, { XK_F11 }}},
95 { Qt::Key_F12, {1, { XK_F12 }}},
96 { Qt::Key_F13, {1, { XK_F13 }}},
97 { Qt::Key_F14, {1, { XK_F14 }}},
98 { Qt::Key_F15, {1, { XK_F15 }}},
99 { Qt::Key_F16, {1, { XK_F16 }}},
100 { Qt::Key_F17, {1, { XK_F17 }}},
101 { Qt::Key_F18, {1, { XK_F18 }}},
102 { Qt::Key_F19, {1, { XK_F19 }}},
103 { Qt::Key_F20, {1, { XK_F20 }}},
104 { Qt::Key_F21, {1, { XK_F21 }}},
105 { Qt::Key_F22, {1, { XK_F22 }}},
106 { Qt::Key_F23, {1, { XK_F23 }}},
107 { Qt::Key_F24, {1, { XK_F24 }}},
108 { Qt::Key_F25, {1, { XK_F25 }}},
109 { Qt::Key_F26, {1, { XK_F26 }}},
110 { Qt::Key_F27, {1, { XK_F27 }}},
111 { Qt::Key_F28, {1, { XK_F28 }}},
112 { Qt::Key_F29, {1, { XK_F29 }}},
113 { Qt::Key_F30, {1, { XK_F30 }}},
114 { Qt::Key_F31, {1, { XK_F31 }}},
115 { Qt::Key_F32, {1, { XK_F32 }}},
116 { Qt::Key_F33, {1, { XK_F33 }}},
117 { Qt::Key_F34, {1, { XK_F34 }}},
118 { Qt::Key_F35, {1, { XK_F35 }}},
119 { Qt::Key_Super_L, {1, { XK_Super_L }}},
120 { Qt::Key_Super_R, {1, { XK_Super_R }}},
121 { Qt::Key_Menu, {1, { XK_Menu }}},
122 { Qt::Key_Hyper_L, {1, { XK_Hyper_L }}},
123 { Qt::Key_Hyper_R, {1, { XK_Hyper_R }}},
124 { Qt::Key_Help, {1, { XK_Help }}},
125 { Qt::Key_Direction_L,{0, { 0 }}},
126 { Qt::Key_Direction_R,{0, { 0 }}},
127
128 { Qt::Key_unknown, {0, { 0 }}},
129};
130
131static long alt_mask = 0;
132static long meta_mask = 0;
133static bool haveMods = false;
134
135// adapted from qapplication_x11.cpp
136static void ensureModifiers()
137{
138 if(haveMods)
139 return;
140
141 Display *appDpy = qt_xdisplay();
142 XModifierKeymap *map = XGetModifierMapping(appDpy);
143 if(map) {
144 int i, maskIndex = 0, mapIndex = 0;
145 for (maskIndex = 0; maskIndex < 8; maskIndex++) {
146 for (i = 0; i < map->max_keypermod; i++) {
147 if (map->modifiermap[mapIndex]) {
148 KeySym sym = XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], 0);
149 if ( alt_mask == 0 && ( sym == XK_Alt_L || sym == XK_Alt_R ) ) {
150 alt_mask = 1 << maskIndex;
151 }
152 if ( meta_mask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R ) ) {
153 meta_mask = 1 << maskIndex;
154 }
155 }
156 mapIndex++;
157 }
158 }
159
160 XFreeModifiermap(map);
161 }
162 else {
163 // assume defaults
164 alt_mask = Mod1Mask;
165 meta_mask = Mod4Mask;
166 }
167
168 haveMods = true;
169}
170
171static bool convertKeySequence(const QKeySequence &ks, unsigned int *_mod, QT_XK_KEYGROUP *_kg)
172{
173 int code = ks;
174 ensureModifiers();
175
176 unsigned int mod = 0;
177 if(code & Qt::META)
178 mod |= meta_mask;
179 if(code & Qt::SHIFT)
180 mod |= ShiftMask;
181 if(code & Qt::CTRL)
182 mod |= ControlMask;
183 if(code & Qt::ALT)
184 mod |= alt_mask;
185
186 QT_XK_KEYGROUP kg;
187 kg.num = 0;
188 code &= 0xffff;
189 // see if it is in our table
190 bool found = false;
191 for(int n = 0; qt_xk_table[n].key != Qt::Key_unknown; ++n) {
192 if(qt_xk_table[n].key == code) {
193 kg = qt_xk_table[n].xk;
194 found = true;
195 break;
196 }
197 }
198 // not found?
199 if(!found) {
200 // try latin1
201 if(code >= 0x20 && code <= 0x7f) {
202 kg.num = 1;
203 kg.sym[0] = code;
204 }
205 }
206 if(!kg.num)
207 return false;
208
209 if(_mod)
210 *_mod = mod;
211 if(_kg)
212 *_kg = kg;
213
214 return true;
215}
216
217class X11HotKey
218{
219public:
220 X11HotKey() {}
221 ~X11HotKey()
222 {
223 XUngrabKey(dsp, code, mod, grab);
224 }
225
226 static bool failed;
227 static int XGrabErrorHandler(Display *, XErrorEvent *)
228 {
229 failed = true;
230 return 0;
231 }
232
233 static X11HotKey * bind(int keysym, unsigned int mod)
234 {
235 Display *dsp = qt_xdisplay();
236 Window grab = qt_xrootwin();
237 int code = XKeysymToKeycode(dsp, keysym);
238
239 // don't grab keys with empty code (because it means just the modifier key)
240 if ( keysym && !code )
241 return 0;
242
243 failed = false;
244 XErrorHandler savedErrorHandler = XSetErrorHandler(XGrabErrorHandler);
245 XGrabKey(dsp, code, mod, grab, False, GrabModeAsync, GrabModeAsync);
246 XSync(dsp, False);
247 XSetErrorHandler(savedErrorHandler);
248 if(failed)
249 return 0;
250 X11HotKey *k = new X11HotKey;
251 k->dsp = dsp;
252 k->grab = grab;
253 k->code = code;
254 k->mod = mod;
255 return k;
256 }
257
258 Display *dsp; // X11 display
259 Window grab; // Window (root window, in our case)
260 int code; // Keycode
261 unsigned int mod; // modifiers (shift/alt/etc)
262};
263
264bool X11HotKey::failed;
265
266class X11HotKeyGroup
267{
268public:
269 X11HotKeyGroup()
270 {
271 list.setAutoDelete(true);
272 }
273
274 ~X11HotKeyGroup()
275 {
276 }
277
278 static X11HotKeyGroup * bind(const QT_XK_KEYGROUP &kg, unsigned int mod, int qkey, int id)
279 {
280 QPtrList<X11HotKey> list;
281 for(int n = 0; n < kg.num; ++n) {
282 X11HotKey *k = X11HotKey::bind(kg.sym[n], mod);
283 if(k)
284 list.append(k);
285 }
286 if(list.isEmpty())
287 return 0;
288 X11HotKeyGroup *h = new X11HotKeyGroup;
289 h->list = list;
290 h->qkey = qkey;
291 h->id = id;
292 return h;
293 }
294
295 QPtrList<X11HotKey> list; // Associated X11HotKeys
296 int qkey; // Qt keycode (with modifiers)
297 int id; // GlobalAccelManager unique ID for this hotkey
298};
299
300class GlobalAccelManager::Private
301{
302public:
303 Private(GlobalAccelManager *_man)
304 {
305 man = _man;
306 id_at = 1;
307 list.setAutoDelete(true);
308 f = new Filter(this);
309 qApp->installEventFilter(f);
310 }
311
312 ~Private()
313 {
314 qApp->removeEventFilter(f);
315 delete f;
316 }
317
318 bool isThisYours(int qkey)
319 {
320 QPtrListIterator<X11HotKeyGroup> it(list);
321 for(X11HotKeyGroup *k; (k = it.current()); ++it) {
322 if(k->qkey == qkey) {
323 man->triggerActivated(k->id);
324 return true;
325 }
326 }
327 return false;
328 }
329
330 class Filter : public QObject
331 {
332 public:
333 Filter(Private *_p)
334 {
335 p = _p;
336 }
337
338 protected:
339 bool eventFilter(QObject *o, QEvent *e)
340 {
341 if(e->type() == QEvent::KeyPress) {
342 QKeyEvent *k = (QKeyEvent *)e;
343 int qkey = k->key();
344 if(k->state() & ShiftButton)
345 qkey |= Qt::SHIFT;
346 if(k->state() & ControlButton)
347 qkey |= Qt::CTRL;
348 if(k->state() & AltButton)
349 qkey |= Qt::ALT;
350 if(k->state() & MetaButton)
351 qkey |= Qt::META;
352
353 if(p->isThisYours(qkey))
354 return true;
355 }
356 return QObject::eventFilter(o, e);
357 }
358
359 private:
360 Private *p;
361 };
362
363 GlobalAccelManager *man;
364 int id_at;
365 Filter *f;
366 QPtrList<X11HotKeyGroup> list;
367};
368
369GlobalAccelManager::GlobalAccelManager()
370{
371 d = new Private(this);
372}
373
374GlobalAccelManager::~GlobalAccelManager()
375{
376 delete d;
377}
378
379int GlobalAccelManager::setAccel(const QKeySequence &ks)
380{
381 QT_XK_KEYGROUP kg;
382 unsigned int mod;
383 if(!convertKeySequence(ks, &mod, &kg))
384 return 0;
385
386 X11HotKeyGroup *h = X11HotKeyGroup::bind(kg, mod, ks, d->id_at++);
387 if(!h)
388 return 0;
389 d->list.append(h);
390
391 return h->id;
392}
393
394void GlobalAccelManager::removeAccel(int id)
395{
396 QPtrListIterator<X11HotKeyGroup> it(d->list);
397 for(X11HotKeyGroup *hk = 0; (hk = it.current()); ++it) {
398 if(hk->id == id) {
399 d->list.removeRef(hk);
400 return;
401 }
402 }
403}
Note: See TracBrowser for help on using the repository browser.