1 | /*
|
---|
2 | * globalaccelman_win.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 | // TODO:
|
---|
22 | // - don't invoke hotkey if there is a modal dialog?
|
---|
23 | // - do multi-mapping, like the x11 version
|
---|
24 |
|
---|
25 | #include"globalaccelman.h"
|
---|
26 |
|
---|
27 | #include<qkeysequence.h>
|
---|
28 | #include<qwidget.h>
|
---|
29 | #include<qptrlist.h>
|
---|
30 |
|
---|
31 | #include<windows.h>
|
---|
32 |
|
---|
33 | // We'll start our hotkeys at offset 0x1000 in the Windows hotkey table (no real reason)
|
---|
34 | #define HOTKEY_START 0x1000
|
---|
35 |
|
---|
36 | struct QT_VK_KEYMAP
|
---|
37 | {
|
---|
38 | int key;
|
---|
39 | UINT vk;
|
---|
40 | } qt_vk_table[] = {
|
---|
41 | { Qt::Key_Escape, VK_ESCAPE },
|
---|
42 | { Qt::Key_Tab, VK_TAB },
|
---|
43 | { Qt::Key_Backtab, 0 },
|
---|
44 | { Qt::Key_Backspace, VK_BACK },
|
---|
45 | { Qt::Key_Return, VK_RETURN },
|
---|
46 | { Qt::Key_Enter, VK_RETURN },
|
---|
47 | { Qt::Key_Insert, VK_INSERT },
|
---|
48 | { Qt::Key_Delete, VK_DELETE },
|
---|
49 | { Qt::Key_Pause, VK_PAUSE },
|
---|
50 | { Qt::Key_Print, VK_PRINT },
|
---|
51 | { Qt::Key_SysReq, 0 },
|
---|
52 | { Qt::Key_Clear, VK_CLEAR },
|
---|
53 | { Qt::Key_Home, VK_HOME },
|
---|
54 | { Qt::Key_End, VK_END },
|
---|
55 | { Qt::Key_Left, VK_LEFT },
|
---|
56 | { Qt::Key_Up, VK_UP },
|
---|
57 | { Qt::Key_Right, VK_RIGHT },
|
---|
58 | { Qt::Key_Down, VK_DOWN },
|
---|
59 | { Qt::Key_Prior, VK_PRIOR },
|
---|
60 | { Qt::Key_Next, VK_NEXT },
|
---|
61 | { Qt::Key_Shift, VK_SHIFT },
|
---|
62 | { Qt::Key_Control, VK_CONTROL },
|
---|
63 | { Qt::Key_Meta, VK_LWIN },
|
---|
64 | { Qt::Key_Alt, VK_MENU },
|
---|
65 | { Qt::Key_CapsLock, VK_CAPITAL },
|
---|
66 | { Qt::Key_NumLock, VK_NUMLOCK },
|
---|
67 | { Qt::Key_ScrollLock, VK_SCROLL },
|
---|
68 | { Qt::Key_F1, VK_F1 },
|
---|
69 | { Qt::Key_F2, VK_F2 },
|
---|
70 | { Qt::Key_F3, VK_F3 },
|
---|
71 | { Qt::Key_F4, VK_F4 },
|
---|
72 | { Qt::Key_F5, VK_F5 },
|
---|
73 | { Qt::Key_F6, VK_F6 },
|
---|
74 | { Qt::Key_F7, VK_F7 },
|
---|
75 | { Qt::Key_F8, VK_F8 },
|
---|
76 | { Qt::Key_F9, VK_F9 },
|
---|
77 | { Qt::Key_F10, VK_F10 },
|
---|
78 | { Qt::Key_F11, VK_F11 },
|
---|
79 | { Qt::Key_F12, VK_F12 },
|
---|
80 | { Qt::Key_F13, VK_F13 },
|
---|
81 | { Qt::Key_F14, VK_F14 },
|
---|
82 | { Qt::Key_F15, VK_F15 },
|
---|
83 | { Qt::Key_F16, VK_F16 },
|
---|
84 | { Qt::Key_F17, VK_F17 },
|
---|
85 | { Qt::Key_F18, VK_F18 },
|
---|
86 | { Qt::Key_F19, VK_F19 },
|
---|
87 | { Qt::Key_F20, VK_F20 },
|
---|
88 | { Qt::Key_F21, VK_F21 },
|
---|
89 | { Qt::Key_F22, VK_F22 },
|
---|
90 | { Qt::Key_F23, VK_F23 },
|
---|
91 | { Qt::Key_F24, VK_F24 },
|
---|
92 | { Qt::Key_F25, 0 },
|
---|
93 | { Qt::Key_F26, 0 },
|
---|
94 | { Qt::Key_F27, 0 },
|
---|
95 | { Qt::Key_F28, 0 },
|
---|
96 | { Qt::Key_F29, 0 },
|
---|
97 | { Qt::Key_F30, 0 },
|
---|
98 | { Qt::Key_F31, 0 },
|
---|
99 | { Qt::Key_F32, 0 },
|
---|
100 | { Qt::Key_F33, 0 },
|
---|
101 | { Qt::Key_F34, 0 },
|
---|
102 | { Qt::Key_F35, 0 },
|
---|
103 | { Qt::Key_Super_L, 0 },
|
---|
104 | { Qt::Key_Super_R, 0 },
|
---|
105 | { Qt::Key_Menu, 0 },
|
---|
106 | { Qt::Key_Hyper_L, 0 },
|
---|
107 | { Qt::Key_Hyper_R, 0 },
|
---|
108 | { Qt::Key_Help, 0 },
|
---|
109 | { Qt::Key_Direction_L,0 },
|
---|
110 | { Qt::Key_Direction_R,0 },
|
---|
111 |
|
---|
112 | { Qt::Key_unknown, 0 },
|
---|
113 | };
|
---|
114 |
|
---|
115 | static bool convertKeySequence(const QKeySequence &ks, UINT *_mod, UINT *_key)
|
---|
116 | {
|
---|
117 | int code = ks;
|
---|
118 |
|
---|
119 | UINT mod = 0;
|
---|
120 | if(code & Qt::META)
|
---|
121 | mod |= MOD_WIN;
|
---|
122 | if(code & Qt::SHIFT)
|
---|
123 | mod |= MOD_SHIFT;
|
---|
124 | if(code & Qt::CTRL)
|
---|
125 | mod |= MOD_CONTROL;
|
---|
126 | if(code & Qt::ALT)
|
---|
127 | mod |= MOD_ALT;
|
---|
128 |
|
---|
129 | UINT key = 0;
|
---|
130 | code &= 0xffff;
|
---|
131 | if(code >= 0x20 && code <= 0x7f)
|
---|
132 | key = code;
|
---|
133 | else {
|
---|
134 | for(int n = 0; qt_vk_table[n].key != Qt::Key_unknown; ++n) {
|
---|
135 | if(qt_vk_table[n].key == code) {
|
---|
136 | key = qt_vk_table[n].vk;
|
---|
137 | break;
|
---|
138 | }
|
---|
139 | }
|
---|
140 | if(!key)
|
---|
141 | return false;
|
---|
142 | }
|
---|
143 |
|
---|
144 | if(_mod)
|
---|
145 | *_mod = mod;
|
---|
146 | if(_key)
|
---|
147 | *_key = key;
|
---|
148 |
|
---|
149 | return true;
|
---|
150 | }
|
---|
151 |
|
---|
152 | class WindowsHotKey
|
---|
153 | {
|
---|
154 | public:
|
---|
155 | WindowsHotKey(HWND _w, int _win_key_id, int _id)
|
---|
156 | {
|
---|
157 | w = _w;
|
---|
158 | win_key_id = _win_key_id;
|
---|
159 | id = _id;
|
---|
160 | }
|
---|
161 |
|
---|
162 | ~WindowsHotKey()
|
---|
163 | {
|
---|
164 | UnregisterHotKey(w, win_key_id);
|
---|
165 | }
|
---|
166 |
|
---|
167 | HWND w;
|
---|
168 | int win_key_id; // Windows hotkey slot number
|
---|
169 | int id; // GlobalAccelManager unique ID for this hotkey
|
---|
170 | };
|
---|
171 |
|
---|
172 | class GlobalAccelManager::Private
|
---|
173 | {
|
---|
174 | public:
|
---|
175 | Private(GlobalAccelManager *par)
|
---|
176 | {
|
---|
177 | manager = par;
|
---|
178 | id_at = 1;
|
---|
179 | hidden = new HiddenWidget(this);
|
---|
180 | list.setAutoDelete(true);
|
---|
181 | }
|
---|
182 |
|
---|
183 | ~Private()
|
---|
184 | {
|
---|
185 | delete hidden;
|
---|
186 | }
|
---|
187 |
|
---|
188 | int getFreeSlot() const
|
---|
189 | {
|
---|
190 | QPtrListIterator<WindowsHotKey> it(list);
|
---|
191 | // find first non-match
|
---|
192 | int n = HOTKEY_START;
|
---|
193 | for(WindowsHotKey *hk = 0; (hk = it.current()); ++it) {
|
---|
194 | if(hk->win_key_id != n)
|
---|
195 | break;
|
---|
196 | ++n;
|
---|
197 | }
|
---|
198 | return n;
|
---|
199 | }
|
---|
200 |
|
---|
201 | int insertHotKey(int win_key_id)
|
---|
202 | {
|
---|
203 | WindowsHotKey *hk = new WindowsHotKey(hidden->winId(), win_key_id, id_at++);
|
---|
204 | if(win_key_id >= (int)list.count())
|
---|
205 | list.append(hk);
|
---|
206 | else
|
---|
207 | list.insert(win_key_id - HOTKEY_START, hk);
|
---|
208 | return hk->id;
|
---|
209 | }
|
---|
210 |
|
---|
211 | void hotkeyActivated(int win_key_id)
|
---|
212 | {
|
---|
213 | QPtrListIterator<WindowsHotKey> it(list);
|
---|
214 | for(WindowsHotKey *hk = 0; (hk = it.current()); ++it) {
|
---|
215 | if(hk->win_key_id == win_key_id)
|
---|
216 | manager->triggerActivated(hk->id);
|
---|
217 | }
|
---|
218 | }
|
---|
219 |
|
---|
220 | class HiddenWidget : public QWidget
|
---|
221 | {
|
---|
222 | public:
|
---|
223 | HiddenWidget(Private *_p)
|
---|
224 | {
|
---|
225 | p = _p;
|
---|
226 | }
|
---|
227 |
|
---|
228 | protected:
|
---|
229 | bool winEvent(MSG *m)
|
---|
230 | {
|
---|
231 | m->message &= 0xffff;
|
---|
232 | if(m->message == WM_HOTKEY) {
|
---|
233 | p->hotkeyActivated(m->wParam);
|
---|
234 | return true;
|
---|
235 | }
|
---|
236 | return QWidget::winEvent(m);
|
---|
237 | }
|
---|
238 |
|
---|
239 | private:
|
---|
240 | Private *p;
|
---|
241 | };
|
---|
242 |
|
---|
243 | GlobalAccelManager *manager;
|
---|
244 | int id_at;
|
---|
245 | HiddenWidget *hidden;
|
---|
246 | QPtrList<WindowsHotKey> list;
|
---|
247 | };
|
---|
248 |
|
---|
249 | GlobalAccelManager::GlobalAccelManager()
|
---|
250 | {
|
---|
251 | d = new Private(this);
|
---|
252 | }
|
---|
253 |
|
---|
254 | GlobalAccelManager::~GlobalAccelManager()
|
---|
255 | {
|
---|
256 | delete d;
|
---|
257 | }
|
---|
258 |
|
---|
259 | int GlobalAccelManager::setAccel(const QKeySequence &ks)
|
---|
260 | {
|
---|
261 | UINT mod, key;
|
---|
262 | if(!convertKeySequence(ks, &mod, &key))
|
---|
263 | return 0;
|
---|
264 |
|
---|
265 | int win_key_id = d->getFreeSlot();
|
---|
266 |
|
---|
267 | if(!RegisterHotKey(d->hidden->winId(), win_key_id, mod, key))
|
---|
268 | return 0;
|
---|
269 |
|
---|
270 | return d->insertHotKey(win_key_id);
|
---|
271 | }
|
---|
272 |
|
---|
273 | void GlobalAccelManager::removeAccel(int id)
|
---|
274 | {
|
---|
275 | QPtrListIterator<WindowsHotKey> it(d->list);
|
---|
276 | for(WindowsHotKey *hk = 0; (hk = it.current()); ++it) {
|
---|
277 | if(hk->id == id) {
|
---|
278 | d->list.removeRef(hk);
|
---|
279 | return;
|
---|
280 | }
|
---|
281 | }
|
---|
282 | }
|
---|