1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
6 
7 #include "build/build_config.h"
8 #include "ui/events/keycodes/dom/dom_key.h"
9 #include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
10 #include "ui/gfx/x/keysyms/keysyms.h"
11 
12 namespace ui {
13 
14 // We support dead keys beyond those with predefined keysym names,
15 // expressed as numeric constants with |kDeadKeyFlag| set.
16 // Xkbcommon accepts and does not use any bits in 0x0E000000.
17 //
18 constexpr xkb_keysym_t kDeadKeyFlag = 0x08000000;
19 constexpr int32_t kUnicodeMax = 0x10FFFF;
20 
NonPrintableXKeySymToDomKey(xkb_keysym_t keysym)21 DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym) {
22   switch (keysym) {
23     case XKB_KEY_BackSpace:
24       return DomKey::BACKSPACE;
25     case XKB_KEY_Tab:
26     case XKB_KEY_KP_Tab:
27     case XKB_KEY_ISO_Left_Tab:
28       return DomKey::TAB;
29     case XKB_KEY_Clear:
30     case XKB_KEY_KP_Begin:
31     case XKB_KEY_XF86Clear:
32       return DomKey::CLEAR;
33     case XKB_KEY_Return:
34     case XKB_KEY_KP_Enter:
35       return DomKey::ENTER;
36     case XKB_KEY_Linefeed:
37       return DomKey::ENTER;
38     case XKB_KEY_Pause:
39       return DomKey::PAUSE;
40     case XKB_KEY_Scroll_Lock:
41       return DomKey::SCROLL_LOCK;
42     case XKB_KEY_Escape:
43       return DomKey::ESCAPE;
44     case XKB_KEY_Multi_key:
45       return DomKey::COMPOSE;
46     case XKB_KEY_Kanji:
47       return DomKey::KANJI_MODE;
48     case XKB_KEY_Muhenkan:
49       return DomKey::NON_CONVERT;
50     case XKB_KEY_Henkan_Mode:
51       return DomKey::CONVERT;
52     case XKB_KEY_Romaji:
53       return DomKey::ROMAJI;
54     case XKB_KEY_Hiragana:
55       return DomKey::HIRAGANA;
56     case XKB_KEY_Katakana:
57       return DomKey::KATAKANA;
58     case XKB_KEY_Hiragana_Katakana:
59       return DomKey::HIRAGANA_KATAKANA;
60     case XKB_KEY_Zenkaku:
61       return DomKey::ZENKAKU;
62     case XKB_KEY_Hankaku:
63       return DomKey::HANKAKU;
64     case XKB_KEY_Zenkaku_Hankaku:
65       return DomKey::ZENKAKU_HANKAKU;
66     case XKB_KEY_Kana_Lock:
67       return DomKey::KANA_MODE;
68     case XKB_KEY_Eisu_Shift:
69     case XKB_KEY_Eisu_toggle:
70       return DomKey::ALPHANUMERIC;
71     case XKB_KEY_Hangul:
72       return DomKey::HANGUL_MODE;
73     case XKB_KEY_Hangul_Hanja:
74       return DomKey::HANJA_MODE;
75     case XKB_KEY_Codeinput:
76       return DomKey::CODE_INPUT;
77     case XKB_KEY_SingleCandidate:
78       return DomKey::SINGLE_CANDIDATE;
79     case XKB_KEY_MultipleCandidate:
80       return DomKey::ALL_CANDIDATES;
81     case XKB_KEY_PreviousCandidate:
82       return DomKey::PREVIOUS_CANDIDATE;
83     case XKB_KEY_Home:
84     case XKB_KEY_KP_Home:
85       return DomKey::HOME;
86     case XKB_KEY_Left:
87     case XKB_KEY_KP_Left:
88       return DomKey::ARROW_LEFT;
89     case XKB_KEY_Up:
90     case XKB_KEY_KP_Up:
91       return DomKey::ARROW_UP;
92     case XKB_KEY_Right:
93     case XKB_KEY_KP_Right:
94       return DomKey::ARROW_RIGHT;
95     case XKB_KEY_Down:
96     case XKB_KEY_KP_Down:
97       return DomKey::ARROW_DOWN;
98     case XKB_KEY_Prior:
99     case XKB_KEY_KP_Prior:
100       return DomKey::PAGE_UP;
101     case XKB_KEY_Next:
102     case XKB_KEY_KP_Next:
103     case XKB_KEY_XF86ScrollDown:
104       return DomKey::PAGE_DOWN;
105     case XKB_KEY_End:
106     case XKB_KEY_KP_End:
107     case XKB_KEY_XF86ScrollUp:
108       return DomKey::END;
109     case XKB_KEY_Select:
110       return DomKey::SELECT;
111     // Treat Print/PrintScreen as PrintScreen https://crbug.com/683097.
112     case XKB_KEY_Print:
113     case XKB_KEY_3270_PrintScreen:
114       return DomKey::PRINT_SCREEN;
115     case XKB_KEY_Execute:
116       return DomKey::EXECUTE;
117     case XKB_KEY_Insert:
118     case XKB_KEY_KP_Insert:
119       return DomKey::INSERT;
120     case XKB_KEY_Undo:
121       return DomKey::UNDO;
122     case XKB_KEY_Redo:
123       return DomKey::REDO;
124     case XKB_KEY_Menu:
125       return DomKey::CONTEXT_MENU;
126     case XKB_KEY_Find:
127       return DomKey::FIND;
128     case XKB_KEY_Cancel:
129       return DomKey::CANCEL;
130     case XKB_KEY_Help:
131       return DomKey::HELP;
132     case XKB_KEY_Break:
133     case XKB_KEY_3270_Attn:
134       return DomKey::ATTN;
135     case XKB_KEY_Mode_switch:
136       return DomKey::MODE_CHANGE;
137     case XKB_KEY_Num_Lock:
138       return DomKey::NUM_LOCK;
139     case XKB_KEY_F1:
140     case XKB_KEY_KP_F1:
141       return DomKey::F1;
142     case XKB_KEY_F2:
143     case XKB_KEY_KP_F2:
144       return DomKey::F2;
145     case XKB_KEY_F3:
146     case XKB_KEY_KP_F3:
147       return DomKey::F3;
148     case XKB_KEY_F4:
149     case XKB_KEY_KP_F4:
150       return DomKey::F4;
151     case XKB_KEY_F5:
152       return DomKey::F5;
153     case XKB_KEY_F6:
154       return DomKey::F6;
155     case XKB_KEY_F7:
156       return DomKey::F7;
157     case XKB_KEY_F8:
158       return DomKey::F8;
159     case XKB_KEY_F9:
160       return DomKey::F9;
161     case XKB_KEY_F10:
162       return DomKey::F10;
163     case XKB_KEY_F11:
164       return DomKey::F11;
165     case XKB_KEY_F12:
166       return DomKey::F12;
167     case XKB_KEY_XF86Tools:  // XKB 'inet' mapping of F13
168     case XKB_KEY_F13:
169       return DomKey::F13;
170     case XKB_KEY_F14:
171     case XKB_KEY_XF86Launch5:  // XKB 'inet' mapping of F14
172       return DomKey::F14;
173     case XKB_KEY_F15:
174     case XKB_KEY_XF86Launch6:  // XKB 'inet' mapping of F15
175       return DomKey::F15;
176     case XKB_KEY_F16:
177     case XKB_KEY_XF86Launch7:  // XKB 'inet' mapping of F16
178       return DomKey::F16;
179     case XKB_KEY_F17:
180     case XKB_KEY_XF86Launch8:  // XKB 'inet' mapping of F17
181       return DomKey::F17;
182     case XKB_KEY_F18:
183     case XKB_KEY_XF86Launch9:  // XKB 'inet' mapping of F18
184       return DomKey::F18;
185     case XKB_KEY_F19:
186       return DomKey::F19;
187     case XKB_KEY_F20:
188       return DomKey::F20;
189     case XKB_KEY_F21:
190       return DomKey::F21;
191     case XKB_KEY_F22:
192       return DomKey::F22;
193     case XKB_KEY_F23:
194       return DomKey::F23;
195     case XKB_KEY_F24:
196       return DomKey::F24;
197     case XKB_KEY_Shift_L:
198     case XKB_KEY_Shift_R:
199       return DomKey::SHIFT;
200     case XKB_KEY_Control_L:
201     case XKB_KEY_Control_R:
202       return DomKey::CONTROL;
203     case XKB_KEY_Caps_Lock:
204       return DomKey::CAPS_LOCK;
205 #if defined(OS_CHROMEOS)
206     case XKB_KEY_Meta_L:
207     case XKB_KEY_Meta_R:
208     case XKB_KEY_Alt_L:
209     case XKB_KEY_Alt_R:
210       // The Shift+Alt generates a KeySym for the Meta key. On ChromeOS the Meta
211       // key is not used and we should still get the Alt key. crbug.com/541468.
212       return DomKey::ALT;
213 #else
214     case XKB_KEY_Meta_L:
215     case XKB_KEY_Meta_R:
216       return DomKey::META;
217     case XKB_KEY_Alt_L:
218     case XKB_KEY_Alt_R:
219       return DomKey::ALT;
220 #endif  // defined(OS_CHROMEOS)
221     case XKB_KEY_Super_L:
222     case XKB_KEY_Super_R:
223       return DomKey::META;
224     case XKB_KEY_Hyper_L:
225     case XKB_KEY_Hyper_R:
226       return DomKey::HYPER;
227     case XKB_KEY_Delete:
228       return DomKey::DEL;
229     case XKB_KEY_SunProps:
230       return DomKey::PROPS;
231     case XKB_KEY_XF86Next_VMode:
232       return DomKey::VIDEO_MODE_NEXT;
233     case XKB_KEY_XF86MonBrightnessUp:
234       return DomKey::BRIGHTNESS_UP;
235     case XKB_KEY_XF86MonBrightnessDown:
236       return DomKey::BRIGHTNESS_DOWN;
237     case XKB_KEY_XF86Standby:
238     case XKB_KEY_XF86Sleep:
239     case XKB_KEY_XF86Suspend:
240       return DomKey::STANDBY;
241     case XKB_KEY_XF86AudioLowerVolume:
242       return DomKey::AUDIO_VOLUME_DOWN;
243     case XKB_KEY_XF86AudioMute:
244       return DomKey::AUDIO_VOLUME_MUTE;
245     case XKB_KEY_XF86AudioRaiseVolume:
246       return DomKey::AUDIO_VOLUME_UP;
247     case XKB_KEY_XF86AudioPlay:
248       return DomKey::MEDIA_PLAY_PAUSE;
249     case XKB_KEY_XF86AudioStop:
250       return DomKey::MEDIA_STOP;
251     case XKB_KEY_XF86AudioPrev:
252       return DomKey::MEDIA_TRACK_PREVIOUS;
253     case XKB_KEY_XF86AudioNext:
254       return DomKey::MEDIA_TRACK_NEXT;
255     case XKB_KEY_XF86HomePage:
256       return DomKey::BROWSER_HOME;
257     case XKB_KEY_XF86Mail:
258       return DomKey::LAUNCH_MAIL;
259     case XKB_KEY_XF86Search:
260       return DomKey::BROWSER_SEARCH;
261     case XKB_KEY_XF86AudioRecord:
262       return DomKey::MEDIA_RECORD;
263     case XKB_KEY_XF86Calculator:
264       return DomKey::LAUNCH_CALCULATOR;
265     case XKB_KEY_XF86Calendar:
266       return DomKey::LAUNCH_CALENDAR;
267     case XKB_KEY_XF86Back:
268       return DomKey::BROWSER_BACK;
269     case XKB_KEY_XF86Forward:
270       return DomKey::BROWSER_FORWARD;
271     case XKB_KEY_XF86Stop:
272       return DomKey::BROWSER_STOP;
273     case XKB_KEY_XF86Refresh:
274     case XKB_KEY_XF86Reload:
275       return DomKey::BROWSER_REFRESH;
276     case XKB_KEY_XF86PowerOff:
277       return DomKey::POWER_OFF;
278     case XKB_KEY_XF86WakeUp:
279       return DomKey::WAKE_UP;
280     case XKB_KEY_XF86Eject:
281       return DomKey::EJECT;
282     case XKB_KEY_XF86ScreenSaver:
283       return DomKey::LAUNCH_SCREEN_SAVER;
284     case XKB_KEY_XF86WWW:
285       return DomKey::LAUNCH_WEB_BROWSER;
286     case XKB_KEY_XF86Favorites:
287       return DomKey::BROWSER_FAVORITES;
288     case XKB_KEY_XF86AudioPause:
289       return DomKey::MEDIA_PAUSE;
290     case XKB_KEY_XF86AudioMedia:
291     case XKB_KEY_XF86Music:
292       return DomKey::LAUNCH_MUSIC_PLAYER;
293     case XKB_KEY_XF86MyComputer:
294     case XKB_KEY_XF86Explorer:
295       return DomKey::LAUNCH_MY_COMPUTER;
296     case XKB_KEY_XF86AudioRewind:
297       return DomKey::MEDIA_REWIND;
298     case XKB_KEY_XF86CD:
299     case XKB_KEY_XF86Video:
300       return DomKey::LAUNCH_MEDIA_PLAYER;
301     case XKB_KEY_XF86Close:
302       return DomKey::CLOSE;
303     case XKB_KEY_XF86Copy:
304     case XKB_KEY_SunCopy:
305       return DomKey::COPY;
306     case XKB_KEY_XF86Cut:
307     case XKB_KEY_SunCut:
308       return DomKey::CUT;
309     case XKB_KEY_XF86Display:
310       return DomKey::DISPLAY_SWAP;
311     case XKB_KEY_XF86Excel:
312       return DomKey::LAUNCH_SPREADSHEET;
313     case XKB_KEY_XF86LogOff:
314       return DomKey::LOG_OFF;
315     case XKB_KEY_XF86New:
316       return DomKey::NEW;
317     case XKB_KEY_XF86Open:
318     case XKB_KEY_SunOpen:
319       return DomKey::OPEN;
320     case XKB_KEY_XF86Paste:
321     case XKB_KEY_SunPaste:
322       return DomKey::PASTE;
323     case XKB_KEY_XF86Reply:
324       return DomKey::MAIL_REPLY;
325     case XKB_KEY_XF86Save:
326       return DomKey::SAVE;
327     case XKB_KEY_XF86Send:
328       return DomKey::MAIL_SEND;
329     case XKB_KEY_XF86Spell:
330       return DomKey::SPELL_CHECK;
331     case XKB_KEY_XF86SplitScreen:
332       return DomKey::SPLIT_SCREEN_TOGGLE;
333     case XKB_KEY_XF86Word:
334     case XKB_KEY_XF86OfficeHome:
335       return DomKey::LAUNCH_WORD_PROCESSOR;
336     case XKB_KEY_XF86ZoomIn:
337       return DomKey::ZOOM_IN;
338     case XKB_KEY_XF86ZoomOut:
339       return DomKey::ZOOM_OUT;
340     case XKB_KEY_XF86WebCam:
341       return DomKey::LAUNCH_WEB_CAM;
342     case XKB_KEY_XF86MailForward:
343       return DomKey::MAIL_FORWARD;
344     case XKB_KEY_XF86AudioForward:
345       return DomKey::MEDIA_FAST_FORWARD;
346     case XKB_KEY_XF86AudioRandomPlay:
347       return DomKey::RANDOM_TOGGLE;
348     case XKB_KEY_XF86Subtitle:
349       return DomKey::SUBTITLE;
350     case XKB_KEY_XF86Hibernate:
351       return DomKey::HIBERNATE;
352     case XKB_KEY_3270_EraseEOF:
353       return DomKey::ERASE_EOF;
354     case XKB_KEY_3270_Play:
355       return DomKey::PLAY;
356     case XKB_KEY_3270_ExSelect:
357       return DomKey::EX_SEL;
358     case XKB_KEY_3270_CursorSelect:
359       return DomKey::CR_SEL;
360     case XKB_KEY_ISO_Level3_Shift:
361       return DomKey::ALT_GRAPH;
362     case XKB_KEY_ISO_Level3_Latch:
363       return DomKey::ALT_GRAPH_LATCH;
364     case XKB_KEY_ISO_Level5_Shift:
365       return DomKey::SHIFT_LEVEL5;
366     case XKB_KEY_ISO_Next_Group:
367       return DomKey::GROUP_NEXT;
368     case XKB_KEY_ISO_Prev_Group:
369       return DomKey::GROUP_PREVIOUS;
370     case XKB_KEY_ISO_First_Group:
371       return DomKey::GROUP_FIRST;
372     case XKB_KEY_ISO_Last_Group:
373       return DomKey::GROUP_LAST;
374     case XKB_KEY_dead_grave:
375       // combining grave accent
376       return DomKey::DeadKeyFromCombiningCharacter(0x0300);
377     case XKB_KEY_dead_acute:
378       // combining acute accent
379       return DomKey::DeadKeyFromCombiningCharacter(0x0301);
380     case XKB_KEY_dead_circumflex:
381       // combining circumflex accent
382       return DomKey::DeadKeyFromCombiningCharacter(0x0302);
383     case XKB_KEY_dead_tilde:
384       // combining tilde
385       return DomKey::DeadKeyFromCombiningCharacter(0x0303);
386     case XKB_KEY_dead_macron:
387       // combining macron
388       return DomKey::DeadKeyFromCombiningCharacter(0x0304);
389     case XKB_KEY_dead_breve:
390       // combining breve
391       return DomKey::DeadKeyFromCombiningCharacter(0x0306);
392     case XKB_KEY_dead_abovedot:
393       // combining dot above
394       return DomKey::DeadKeyFromCombiningCharacter(0x0307);
395     case XKB_KEY_dead_diaeresis:
396       // combining diaeresis
397       return DomKey::DeadKeyFromCombiningCharacter(0x0308);
398     case XKB_KEY_dead_abovering:
399       // combining ring above
400       return DomKey::DeadKeyFromCombiningCharacter(0x030A);
401     case XKB_KEY_dead_doubleacute:
402       // combining double acute accent
403       return DomKey::DeadKeyFromCombiningCharacter(0x030B);
404     case XKB_KEY_dead_caron:
405       // combining caron
406       return DomKey::DeadKeyFromCombiningCharacter(0x030C);
407     case XKB_KEY_dead_cedilla:
408       // combining cedilla
409       return DomKey::DeadKeyFromCombiningCharacter(0x0327);
410     case XKB_KEY_dead_ogonek:
411       // combining ogonek
412       return DomKey::DeadKeyFromCombiningCharacter(0x0328);
413     case XKB_KEY_dead_iota:
414       // combining greek ypogegrammeni
415       return DomKey::DeadKeyFromCombiningCharacter(0x0345);
416     case XKB_KEY_dead_voiced_sound:
417       // combining voiced sound mark
418       return DomKey::DeadKeyFromCombiningCharacter(0x3099);
419     case XKB_KEY_dead_semivoiced_sound:
420       // combining semi-voiced sound mark
421       return DomKey::DeadKeyFromCombiningCharacter(0x309A);
422     case XKB_KEY_dead_belowdot:
423       // combining dot below
424       return DomKey::DeadKeyFromCombiningCharacter(0x0323);
425     case XKB_KEY_dead_hook:
426       // combining hook above
427       return DomKey::DeadKeyFromCombiningCharacter(0x0309);
428     case XKB_KEY_dead_horn:
429       // combining horn
430       return DomKey::DeadKeyFromCombiningCharacter(0x031B);
431     case XKB_KEY_dead_stroke:
432       // combining long solidus overlay
433       return DomKey::DeadKeyFromCombiningCharacter(0x0338);
434     case XKB_KEY_dead_abovecomma:
435       // combining comma above
436       return DomKey::DeadKeyFromCombiningCharacter(0x0313);
437     case XKB_KEY_dead_abovereversedcomma:
438       // combining reversed comma above
439       return DomKey::DeadKeyFromCombiningCharacter(0x0314);
440     case XKB_KEY_dead_doublegrave:
441       // combining double grave accent
442       return DomKey::DeadKeyFromCombiningCharacter(0x030F);
443     case XKB_KEY_dead_belowring:
444       // combining ring below
445       return DomKey::DeadKeyFromCombiningCharacter(0x0325);
446     case XKB_KEY_dead_belowmacron:
447       // combining macron below
448       return DomKey::DeadKeyFromCombiningCharacter(0x0331);
449     case XKB_KEY_dead_belowcircumflex:
450       // combining circumflex accent below
451       return DomKey::DeadKeyFromCombiningCharacter(0x032D);
452     case XKB_KEY_dead_belowtilde:
453       // combining tilde below
454       return DomKey::DeadKeyFromCombiningCharacter(0x0330);
455     case XKB_KEY_dead_belowbreve:
456       // combining breve below
457       return DomKey::DeadKeyFromCombiningCharacter(0x032E);
458     case XKB_KEY_dead_belowdiaeresis:
459       // combining diaeresis below
460       return DomKey::DeadKeyFromCombiningCharacter(0x0324);
461     case XKB_KEY_dead_invertedbreve:
462       // combining inverted breve
463       return DomKey::DeadKeyFromCombiningCharacter(0x0311);
464     case XKB_KEY_dead_belowcomma:
465       // combining comma below
466       return DomKey::DeadKeyFromCombiningCharacter(0x0326);
467     case XKB_KEY_dead_currency:
468       // currency sign
469       return DomKey::DeadKeyFromCombiningCharacter(0x00A4);
470     case XKB_KEY_dead_greek:
471       // greek question mark
472       return DomKey::DeadKeyFromCombiningCharacter(0x037E);
473     default:
474       if (keysym & kDeadKeyFlag) {
475         int32_t character = keysym & ~kDeadKeyFlag;
476         if ((character >= 0) && (character <= kUnicodeMax)) {
477           return DomKey::DeadKeyFromCombiningCharacter(character);
478         }
479       }
480       return DomKey::NONE;
481   }
482 }
XKeySymToDomKey(xkb_keysym_t keysym,base::char16 character)483 DomKey XKeySymToDomKey(xkb_keysym_t keysym, base::char16 character) {
484   DomKey dom_key = NonPrintableXKeySymToDomKey(keysym);
485   if (dom_key != DomKey::NONE)
486     return dom_key;
487   return DomKey::FromCharacter(character);
488 }
489 
490 }  // namespace ui
491