1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 *
16 * Copyright (C) 2006-2016 XNeur Team
17 *
18 */
19
20 #include <X11/XKBlib.h>
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25
26 #include "xnconfig.h"
27
28 #include "types.h"
29 #include "utils.h"
30 #include "log.h"
31 #include "list_char.h"
32
33 #include "window.h"
34 #include "keymap.h"
35
36 #include "bind_table.h"
37
38 static struct _bind_table *ubtable;
39
40 static struct _bind_table *btable;
41
42 static const char *normal_action_names[] = {
43 "Correct/Undo correction", "Transliterate", "Change case", "Preview correction",
44 "Correct last line",
45 "Correct selected text", "Transliterate selected text", "Change case of selected text", "Preview correction of selected text",
46 "Correct clipboard text", "Transliterate clipboard text", "Change case of clipboard text", "Preview correction of clipboard text",
47 "Switch to layout 1", "Switch to layout 2", "Switch to layout 3", "Switch to layout 4",
48 "Rotate layouts", "Rotate layouts back", "Expand abbreviations", "Autocompletion confirmation",
49 "Rotate autocompletion", "Insert date"
50 };
51
52 static const char *modifier_names[] = {"Shift", "Control", "Alt", "Super"};
53
54 extern struct _xneur_config *xconfig;
55 extern struct _window *main_window;
56
hotkey_concat_bind(struct _xneur_hotkey * hotkey)57 static char* hotkey_concat_bind(struct _xneur_hotkey * hotkey)
58 {
59 char *text = (char *) malloc((24 + 1 + strlen(hotkey->key)) * sizeof(char));
60 text[0] = '\0';
61
62 int total_modifiers = sizeof(modifier_names) / sizeof(modifier_names[0]);
63 for (int i = 0; i < total_modifiers; i++)
64 {
65 if ((hotkey->modifiers & (0x1 << i)) == 0)
66 continue;
67
68 strcat(text, modifier_names[i]);
69 strcat(text, "+");
70 }
71
72 strcat(text, hotkey->key);
73
74 return text;
75 }
76
create_modifier_mask(int modifiers)77 static int create_modifier_mask(int modifiers){
78 // This function should be single point to edit modifiers
79 int modifier_mask = 0;
80 if (modifiers & 0x01)
81 modifier_mask += 1; // Shift
82 if (modifiers & 0x02)
83 modifier_mask += 4; // Control
84 if (modifiers & 0x04)
85 modifier_mask += 8; // Alt
86 if (modifiers & 0x08)
87 modifier_mask += 64;// Win
88 return modifier_mask;
89 }
90
bind_action(enum _hotkey_action action)91 static void bind_action(enum _hotkey_action action)
92 {
93 btable[action].key_sym = 0;
94 btable[action].key_sym_shift = 0;
95 btable[action].key_code = 0;
96 btable[action].modifier_mask = 0;
97
98 if (xconfig->actions[action].hotkey.key == NULL)
99 {
100 log_message(DEBUG, _(" No key set for action \"%s\""), _(normal_action_names[xconfig->actions[action].action]));
101 return;
102 }
103
104 btable[action].modifier_mask = create_modifier_mask(xconfig->actions[action].hotkey.modifiers);
105
106 KeySym key_sym, key_sym_shift;
107 key_sym = NoSymbol;
108 key_sym_shift = NoSymbol;
109 main_window->keymap->get_keysyms_by_string(main_window->keymap, xconfig->actions[action].hotkey.key, &key_sym, &key_sym_shift);
110 if (key_sym == NoSymbol)
111 key_sym = None;
112 if (key_sym_shift == NoSymbol)
113 key_sym_shift = key_sym;
114
115 btable[action].key_sym = key_sym;
116 btable[action].key_sym_shift = key_sym_shift;
117 btable[action].key_code = XKeysymToKeycode(main_window->display, key_sym);
118
119 char *key = hotkey_concat_bind (&(xconfig->actions[action].hotkey));
120 log_message(DEBUG, _(" Action \"%s\" with key \"%s\""), _(normal_action_names[xconfig->actions[action].action]), key);
121 //log_message(ERROR, _(" KeySym %d (%d) keycode %d"), key_sym, key_sym_shift, ubtable[action].key_code);
122 if ((key_sym == None) || (key_sym_shift == None))
123 {
124 log_message(ERROR, _(" KeySym (or with Shift modifier) is undefined!"), _(normal_action_names[action]), key);
125
126 }
127 if (key != NULL)
128 free(key);
129 }
130
bind_user_action(int action)131 static void bind_user_action(int action)
132 {
133 ubtable[action].key_sym = 0;
134 ubtable[action].key_sym_shift = 0;
135 ubtable[action].key_code = 0;
136 ubtable[action].modifier_mask = 0;
137
138 if (xconfig->user_actions[action].hotkey.key == NULL)
139 {
140 log_message(DEBUG, _(" No key set for action \"%s\""), xconfig->user_actions[action].name);
141 return;
142 }
143
144 ubtable[action].modifier_mask = create_modifier_mask(xconfig->user_actions[action].hotkey.modifiers);
145
146 KeySym key_sym, key_sym_shift;
147 key_sym = NoSymbol;
148 key_sym_shift = NoSymbol;
149 main_window->keymap->get_keysyms_by_string(main_window->keymap, xconfig->user_actions[action].hotkey.key, &key_sym, &key_sym_shift);
150 if (key_sym == NoSymbol)
151 key_sym = None;
152 if (key_sym_shift == NoSymbol)
153 key_sym_shift = key_sym;
154
155 ubtable[action].key_sym = key_sym;
156 ubtable[action].key_sym_shift = key_sym_shift;
157 ubtable[action].key_code = XKeysymToKeycode(main_window->display, key_sym);
158
159 char *key = hotkey_concat_bind (&(xconfig->user_actions[action].hotkey));
160 log_message(DEBUG, _(" Action \"%s\" with key \"%s\""), xconfig->user_actions[action].name, key);
161 //log_message(ERROR, _(" KeySym %d (%d) keycode %d"), key_sym, key_sym_shift, ubtable[action].key_code);
162 if ((key_sym == None) || (key_sym_shift == None))
163 {
164 log_message(ERROR, _(" KeySym (or with Shift modifier) is undefined!"));
165
166 }
167 if (key != NULL)
168 free(key);
169 }
170
get_action(KeySym key_sym,int mask)171 enum _hotkey_action get_action(KeySym key_sym, int mask)
172 {
173 // Reset Caps and Num mask
174 if (key_sym != XK_Caps_Lock)
175 mask &= ~LockMask;
176 if (key_sym != XK_Num_Lock)
177 mask &= ~Mod2Mask;
178 if (key_sym != XK_Scroll_Lock)
179 mask &= ~Mod3Mask;
180
181 KeyCode kc = XKeysymToKeycode(main_window->display, key_sym);
182 if (IsModifierKey(key_sym))
183 {
184 if (key_sym == XK_Shift_L || key_sym == XK_Shift_R)
185 mask -= (1 << 0);
186 if (key_sym == XK_Caps_Lock)
187 mask -= (1 << 1);
188 if (key_sym == XK_Control_L || key_sym == XK_Control_R)
189 mask -= (1 << 2);
190 if (key_sym == XK_Alt_L || key_sym == XK_Alt_R)
191 mask -= (1 << 3);
192 if (key_sym == XK_Meta_L || key_sym == XK_Meta_R)
193 mask -= (1 << 4);
194 if (key_sym == XK_Num_Lock)
195 mask -= (1 << 5);
196 if (key_sym == XK_Super_L || key_sym == XK_Super_R)
197 mask -= (1 << 6);
198 if (key_sym == XK_Hyper_L || key_sym == XK_Hyper_R || key_sym == XK_ISO_Level3_Shift)
199 mask += (1 << 7);
200 }
201
202 for (int action = 0; action < xconfig->actions_count; action++)
203 {
204 //log_message (ERROR, "A%d---bt:(%d)%d, ac:(%d)%d", action, btable[action].modifier_mask, btable[action].key_code, mask, kc);
205 //if (btable[action].key_sym != key_sym && btable[action].key_sym_shift != key_sym)
206 // continue;
207 if (btable[action].key_code != kc)
208 continue;
209 if (btable[action].modifier_mask == mask)
210 {
211 return action;
212 }
213 }
214
215 return ACTION_NONE;
216 }
217
bind_actions(void)218 void bind_actions(void)
219 {
220 log_message(DEBUG, _("Binded hotkeys actions:"));
221 btable = (struct _bind_table *) malloc(xconfig->actions_count * sizeof(struct _bind_table));
222 for (int action = 0; action < xconfig->actions_count; action++)
223 bind_action(action);
224 }
225
unbind_actions(void)226 void unbind_actions(void)
227 {
228 if (btable != NULL)
229 free(btable);
230 btable = NULL;
231 }
232
get_user_action(KeySym key_sym,int mask)233 int get_user_action(KeySym key_sym, int mask)
234 {
235 // Reset Caps and Num mask
236 if (key_sym != XK_Caps_Lock)
237 mask &= ~LockMask;
238 if (key_sym != XK_Num_Lock)
239 mask &= ~Mod2Mask;
240 if (key_sym != XK_Scroll_Lock)
241 mask &= ~Mod3Mask;
242
243 KeyCode kc = XKeysymToKeycode(main_window->display, key_sym);
244 if (IsModifierKey(key_sym))
245 {
246 if (key_sym == XK_Shift_L || key_sym == XK_Shift_R)
247 mask -= (1 << 0);
248 if (key_sym == XK_Caps_Lock)
249 mask -= (1 << 1);
250 if (key_sym == XK_Control_L || key_sym == XK_Control_R)
251 mask -= (1 << 2);
252 if (key_sym == XK_Alt_L || key_sym == XK_Alt_R)
253 mask -= (1 << 3);
254 if (key_sym == XK_Meta_L || key_sym == XK_Meta_R)
255 mask -= (1 << 4);
256 if (key_sym == XK_Num_Lock)
257 mask -= (1 << 5);
258 if (key_sym == XK_Super_L || key_sym == XK_Super_R)
259 mask -= (1 << 6);
260 if (key_sym == XK_Hyper_L || key_sym == XK_Hyper_R || key_sym == XK_ISO_Level3_Shift)
261 mask += (1 << 7);
262 }
263
264 for (int action = 0; action < xconfig->user_actions_count; action++)
265 {
266 //log_message (ERROR, "U%d---bt:(%d)%d, ac:(%d)%d", action, ubtable[action].modifier_mask, ubtable[action].key_code, mask, kc);
267 //if (ubtable[action].key_sym != key_sym && ubtable[action].key_sym_shift != key_sym)
268 // continue;
269 if (ubtable[action].key_code != kc)
270 continue;
271 if (ubtable[action].modifier_mask == mask)
272 {
273 return action;
274 }
275 }
276 return -1;
277 }
278
bind_user_actions(void)279 void bind_user_actions(void)
280 {
281 log_message(DEBUG, _("Binded hotkeys user actions:"));
282 ubtable = (struct _bind_table *) malloc(xconfig->user_actions_count * sizeof(struct _bind_table));
283 for (int action = 0; action < xconfig->user_actions_count; action++)
284 bind_user_action(action);
285 }
286
unbind_user_actions(void)287 void unbind_user_actions(void)
288 {
289 if (ubtable != NULL)
290 free(ubtable);
291 ubtable = NULL;
292 }
293
grab_action(Window window)294 void grab_action(Window window)
295 {
296 for (enum _hotkey_action action = 0; action < MAX_HOTKEYS; action++)
297 {
298 grab_action_common(btable[action],window);
299 }
300 }
301
grab_user_action(Window window)302 void grab_user_action(Window window)
303 {
304 for (int action = 0; action < xconfig->actions_count; action++)
305 {
306 grab_action_common(ubtable[action],window);
307 }
308 }
309
grab_action_common(struct _bind_table btaction,Window window)310 void grab_action_common(struct _bind_table btaction, Window window)
311 {
312 if (window){};
313 if (btaction.key_sym == 0)
314 return;
315
316 if (IsModifierKey(btaction.key_sym))
317 return;
318
319 XGrabKey(main_window->display,
320 XKeysymToKeycode(main_window->display, btaction.key_sym),
321 btaction.modifier_mask,
322 DefaultRootWindow(main_window->display),
323 FALSE, GrabModeAsync, GrabModeAsync);
324
325 if (main_window->keymap->numlock_mask)
326 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
327 btaction.modifier_mask | main_window->keymap->numlock_mask,
328 DefaultRootWindow(main_window->display),
329 FALSE, GrabModeAsync, GrabModeAsync);
330
331 if (main_window->keymap->capslock_mask)
332 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
333 btaction.modifier_mask | main_window->keymap->capslock_mask,
334 DefaultRootWindow(main_window->display),
335 FALSE, GrabModeAsync, GrabModeAsync);
336
337 if (main_window->keymap->scrolllock_mask)
338 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
339 btaction.modifier_mask | main_window->keymap->scrolllock_mask,
340 DefaultRootWindow(main_window->display),
341 FALSE, GrabModeAsync, GrabModeAsync);
342
343 if (main_window->keymap->numlock_mask && main_window->keymap->capslock_mask)
344 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
345 btaction.modifier_mask | main_window->keymap->numlock_mask | main_window->keymap->capslock_mask,
346 DefaultRootWindow(main_window->display),
347 FALSE, GrabModeAsync, GrabModeAsync);
348
349 if (main_window->keymap->numlock_mask && main_window->keymap->scrolllock_mask)
350 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
351 btaction.modifier_mask | main_window->keymap->numlock_mask | main_window->keymap->scrolllock_mask,
352 DefaultRootWindow(main_window->display),
353 FALSE, GrabModeAsync, GrabModeAsync);
354
355 if (main_window->keymap->capslock_mask && main_window->keymap->scrolllock_mask)
356 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
357 btaction.modifier_mask | main_window->keymap->capslock_mask | main_window->keymap->scrolllock_mask,
358 DefaultRootWindow(main_window->display),
359 FALSE, GrabModeAsync, GrabModeAsync);
360
361 if (main_window->keymap->numlock_mask && main_window->keymap->capslock_mask && main_window->keymap->scrolllock_mask)
362 XGrabKey (main_window->display, XKeysymToKeycode(main_window->display, btaction.key_sym),
363 btaction.modifier_mask | main_window->keymap->numlock_mask | main_window->keymap->capslock_mask | main_window->keymap->scrolllock_mask,
364 DefaultRootWindow(main_window->display),
365 FALSE, GrabModeAsync, GrabModeAsync);
366
367 }
368