1 /*
2
3 Copyright (c) 2003-2018 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 /*
35 * key conversion utility for uim-gtk
36 */
37
38 #include <config.h>
39
40 #include <glib.h>
41 #include <gtk/gtk.h>
42 #if GTK_CHECK_VERSION(2, 90, 0)
43 # include <gdk/gdkkeysyms-compat.h>
44 #else
45 # include <gdk/gdkkeysyms.h>
46 #endif
47 #ifdef GDK_WINDOWING_X11
48 #include <gdk/gdkx.h>
49 #include <X11/Xlib.h>
50 #include <X11/XKBlib.h>
51 #endif
52
53 #ifdef GDK_WINDOWING_X11
54 #define UIM_GTK_USE_JAPANESE_KANA_KEYBOARD_HACK 1
55 #endif
56
57 #include "uim/uim.h"
58 #include "uim/uim-scm.h"
59 #if UIM_GTK_USE_JAPANESE_KANA_KEYBOARD_HACK
60 #include "uim/uim-x-util.h"
61 #endif
62
63 #include "key-util-gtk.h"
64
65 static gboolean g_use_custom_modifier_masks = FALSE;
66
67 #ifdef GDK_WINDOWING_X11
68 static guint g_mod1_mask, g_mod2_mask, g_mod3_mask, g_mod4_mask, g_mod5_mask;
69 static gint g_numlock_mask;
70 static guint g_modifier_state, g_pre_modifier_state;
71 #endif
72
73 void
im_uim_convert_keyevent(GdkEventKey * event,int * ukey,int * umod)74 im_uim_convert_keyevent(GdkEventKey *event, int *ukey, int *umod)
75 {
76 int keyval = event->keyval;
77 int mod = event->state;
78
79 *umod = 0;
80 #ifdef GDK_WINDOWING_X11
81 if (event->type == GDK_KEY_PRESS) {
82 if (!mod || mod == GDK_LOCK_MASK ||
83 mod == g_numlock_mask)
84 g_modifier_state = 0;
85 }
86 g_pre_modifier_state = g_modifier_state;
87 #endif
88
89 /* 1. check key */
90 if (keyval < 256)
91 *ukey = keyval;
92 else if (keyval >= GDK_F1 && keyval <= GDK_F35)
93 *ukey = keyval - GDK_F1 + UKey_F1;
94 else if (keyval >= GDK_KP_0 && keyval <= GDK_KP_9)
95 *ukey = keyval - GDK_KP_0 + UKey_0;
96 #if GTK_CHECK_VERSION(2, 6, 0)
97 else if (keyval >= GDK_dead_grave && keyval <= GDK_dead_horn)
98 #else
99 else if (keyval >= GDK_dead_grave && keyval <= GDK_dead_belowdot)
100 #endif
101 *ukey = keyval - GDK_dead_grave + UKey_Dead_Grave;
102 else if (keyval >= GDK_Kanji && keyval <= GDK_Eisu_toggle)
103 *ukey = keyval - GDK_Kanji + UKey_Kanji;
104 else if (keyval >= GDK_Hangul && keyval <= GDK_Hangul_Special)
105 *ukey = keyval - GDK_Hangul + UKey_Hangul;
106 else if (keyval >= GDK_kana_fullstop && keyval <= GDK_semivoicedsound)
107 *ukey = keyval - GDK_kana_fullstop + UKey_Kana_Fullstop;
108 else {
109 switch (keyval) {
110 case GDK_BackSpace:
111 *ukey = UKey_Backspace;
112 break;
113 case GDK_Delete:
114 *ukey = UKey_Delete;
115 break;
116 case GDK_Insert:
117 *ukey = UKey_Insert;
118 break;
119 case GDK_Escape:
120 *ukey = UKey_Escape;
121 break;
122 case GDK_Tab:
123 case GDK_ISO_Left_Tab:
124 *ukey = UKey_Tab;
125 break;
126 case GDK_Return:
127 *ukey = UKey_Return;
128 break;
129 case GDK_Left:
130 *ukey = UKey_Left;
131 break;
132 case GDK_Up:
133 *ukey = UKey_Up;
134 break;
135 case GDK_Right:
136 *ukey = UKey_Right;
137 break;
138 case GDK_Down:
139 *ukey = UKey_Down;
140 break;
141 case GDK_Prior:
142 *ukey = UKey_Prior;
143 break;
144 case GDK_Next:
145 *ukey = UKey_Next;
146 break;
147 case GDK_Home:
148 *ukey = UKey_Home;
149 break;
150 case GDK_End:
151 *ukey = UKey_End;
152 break;
153 case GDK_Multi_key:
154 *ukey = UKey_Multi_key;
155 break;
156 case GDK_Codeinput:
157 *ukey = UKey_Codeinput;
158 break;
159 case GDK_SingleCandidate:
160 *ukey = UKey_SingleCandidate;
161 break;
162 case GDK_MultipleCandidate:
163 *ukey = UKey_MultipleCandidate;
164 break;
165 case GDK_PreviousCandidate:
166 *ukey = UKey_PreviousCandidate;
167 break;
168 case GDK_Mode_switch:
169 *ukey = UKey_Mode_switch;
170 break;
171 case GDK_Shift_L:
172 case GDK_Shift_R:
173 #ifdef GDK_WINDOWING_X11
174 if (event->type == GDK_KEY_PRESS)
175 g_modifier_state |= UMod_Shift;
176 else
177 g_modifier_state &= ~UMod_Shift;
178 #endif
179 *ukey = UKey_Shift_key;
180 break;
181 case GDK_Control_L:
182 case GDK_Control_R:
183 #ifdef GDK_WINDOWING_X11
184 if (event->type == GDK_KEY_PRESS)
185 g_modifier_state |= UMod_Control;
186 else
187 g_modifier_state &= ~UMod_Control;
188 #endif
189 *ukey = UKey_Control_key;
190 break;
191 case GDK_Alt_L:
192 case GDK_Alt_R:
193 #ifdef GDK_WINDOWING_X11
194 if (event->type == GDK_KEY_PRESS)
195 g_modifier_state |= UMod_Alt;
196 else
197 g_modifier_state &= ~UMod_Alt;
198 #endif
199 *ukey = UKey_Alt_key;
200 break;
201 case GDK_Meta_L:
202 case GDK_Meta_R:
203 #ifdef GDK_WINDOWING_X11
204 if (event->type == GDK_KEY_PRESS)
205 g_modifier_state |= UMod_Meta;
206 else
207 g_modifier_state &= ~UMod_Meta;
208 #endif
209 *ukey = UKey_Meta_key;
210 break;
211 case GDK_Super_L:
212 case GDK_Super_R:
213 #ifdef GDK_WINDOWING_X11
214 if (event->type == GDK_KEY_PRESS)
215 g_modifier_state |= UMod_Super;
216 else
217 g_modifier_state &= ~UMod_Super;
218 #endif
219 *ukey = UKey_Super_key;
220 break;
221 case GDK_Hyper_L:
222 case GDK_Hyper_R:
223 #ifdef GDK_WINDOWING_X11
224 if (event->type == GDK_KEY_PRESS)
225 g_modifier_state |= UMod_Hyper;
226 else
227 g_modifier_state &= ~UMod_Hyper;
228 #endif
229 *ukey = UKey_Hyper_key;
230 break;
231 case GDK_Caps_Lock:
232 *ukey = UKey_Caps_Lock;
233 break;
234 case GDK_Num_Lock:
235 *ukey = UKey_Num_Lock;
236 break;
237 case GDK_Scroll_Lock:
238 *ukey = UKey_Scroll_Lock;
239 break;
240 default:
241 *ukey = UKey_Other;
242 break;
243 }
244 }
245 #if UIM_GTK_USE_JAPANESE_KANA_KEYBOARD_HACK
246 /* 1'. replace keysym for Japanese keyboard */
247 *ukey = uim_x_kana_input_hack_translate_key(*ukey, event->hardware_keycode);
248 #endif
249
250 /* 2. check modifier */
251 if (mod & GDK_SHIFT_MASK)
252 *umod |= UMod_Shift;
253 if (mod & GDK_CONTROL_MASK)
254 *umod |= UMod_Control;
255 if (g_use_custom_modifier_masks) {
256 #ifdef GDK_WINDOWING_X11
257 if (mod & GDK_MOD1_MASK)
258 *umod |= (g_mod1_mask & g_pre_modifier_state);
259 if (mod & GDK_MOD2_MASK)
260 *umod |= (g_mod2_mask & g_pre_modifier_state);
261 if (mod & GDK_MOD3_MASK)
262 *umod |= (g_mod3_mask & g_pre_modifier_state);
263 if (mod & GDK_MOD4_MASK)
264 *umod |= (g_mod4_mask & g_pre_modifier_state);
265 if (mod & GDK_MOD5_MASK)
266 *umod |= (g_mod5_mask & g_pre_modifier_state);
267 #endif
268 } else {
269 if (mod & GDK_MOD1_MASK)
270 *umod |= UMod_Alt;
271 if (mod & GDK_MOD3_MASK) /* assuming mod3 */
272 *umod |= UMod_Super;
273 if (mod & GDK_MOD4_MASK) /* assuming mod4 */
274 *umod |= UMod_Hyper;
275 }
276 }
277
278 #ifdef GDK_WINDOWING_X11
279 static int
check_modifier(GSList * slist)280 check_modifier(GSList *slist)
281 {
282 int ret;
283 GSList *tmp_list;
284
285 ret = 0;
286 for (tmp_list = slist; tmp_list; tmp_list = tmp_list->next) {
287 switch (GPOINTER_TO_UINT(tmp_list->data)) {
288 case XK_Shift_L:
289 case XK_Shift_R:
290 ret |= UMod_Shift;
291 break;
292 case XK_Control_L:
293 case XK_Control_R:
294 ret |= UMod_Control;
295 break;
296 case XK_Meta_L:
297 case XK_Meta_R:
298 ret |= UMod_Meta;
299 break;
300 case XK_Alt_L:
301 case XK_Alt_R:
302 ret |= UMod_Alt;
303 break;
304 case XK_Super_L:
305 case XK_Super_R:
306 ret |= UMod_Super;
307 break;
308 case XK_Hyper_L:
309 case XK_Hyper_R:
310 ret |= UMod_Hyper;
311 break;
312 default:
313 break;
314 }
315 }
316 return ret;
317 }
318 #endif
319
320 void
im_uim_init_modifier_keys()321 im_uim_init_modifier_keys()
322 {
323 #ifdef GDK_WINDOWING_X11
324 int i, k = 0;
325 int min_keycode, max_keycode, keysyms_per_keycode = 0;
326 GdkDisplay *gdk_display;
327 Display *display;
328 GSList *mod1_list, *mod2_list, *mod3_list, *mod4_list, *mod5_list;
329 XModifierKeymap *map;
330 KeySym *sym;
331
332 g_modifier_state = 0;
333 g_numlock_mask = 0;
334
335 mod1_list = mod2_list = mod3_list = mod4_list = mod5_list = NULL;
336
337 gdk_display = gdk_display_get_default();
338 # ifdef GDK_TYPE_X11_DISPLAY
339 if (!GDK_IS_X11_DISPLAY(gdk_display)) {
340 /* TODO: We may need to something for Wayland. */
341 return;
342 }
343 # endif
344 display = GDK_DISPLAY_XDISPLAY(gdk_display);
345 map = XGetModifierMapping(display);
346 XDisplayKeycodes(display, &min_keycode, &max_keycode);
347 sym = XGetKeyboardMapping(display, min_keycode,
348 (max_keycode - min_keycode + 1),
349 &keysyms_per_keycode);
350 for (i = 0; i < 8; i++) {
351 int j;
352 for (j = 0; j < map->max_keypermod; j++) {
353 if (map->modifiermap[k]) {
354 KeySym ks;
355 int index = 0;
356 do {
357 ks = XkbKeycodeToKeysym(display, map->modifiermap[k], 0, index);
358 index++;
359 } while (!ks && index < keysyms_per_keycode);
360
361 switch (i) {
362 case ShiftMapIndex:
363 break;
364 case LockMapIndex:
365 break;
366 case ControlMapIndex:
367 break;
368 case Mod1MapIndex:
369 mod1_list = g_slist_prepend(mod1_list, GUINT_TO_POINTER(ks));
370 g_mod1_mask = check_modifier(mod1_list);
371 break;
372 case Mod2MapIndex:
373 mod2_list = g_slist_prepend(mod2_list, GUINT_TO_POINTER(ks));
374 g_mod2_mask = check_modifier(mod2_list);
375 break;
376 case Mod3MapIndex:
377 mod3_list = g_slist_prepend(mod3_list, GUINT_TO_POINTER(ks));
378 g_mod3_mask = check_modifier(mod3_list);
379 break;
380 case Mod4MapIndex:
381 mod4_list = g_slist_prepend(mod4_list, GUINT_TO_POINTER(ks));
382 g_mod4_mask = check_modifier(mod4_list);
383 break;
384 case Mod5MapIndex:
385 mod5_list = g_slist_prepend(mod5_list, GUINT_TO_POINTER(ks));
386 g_mod5_mask = check_modifier(mod5_list);
387 break;
388 default:
389 break;
390 }
391 if (ks == XK_Num_Lock)
392 g_numlock_mask |= (1 << i);
393 }
394 k++;
395 }
396 }
397 g_slist_free(mod1_list);
398 g_slist_free(mod2_list);
399 g_slist_free(mod3_list);
400 g_slist_free(mod4_list);
401 g_slist_free(mod5_list);
402 XFreeModifiermap(map);
403 XFree(sym);
404
405 g_use_custom_modifier_masks = TRUE;
406
407 if (uim_scm_c_bool(uim_scm_callf("require-dynlib", "s", "xkb")))
408 uim_scm_callf("%xkb-set-display", "p", display);
409
410 #if UIM_GTK_USE_JAPANESE_KANA_KEYBOARD_HACK
411 uim_x_kana_input_hack_init(display);
412 #endif
413 #endif
414 }
415