1 // Copyright (c) 2012 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.
5 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
7 #define XK_3270 // for XK_3270_BackTab
8 #include <X11/keysym.h>
10 #include <X11/Xutil.h>
11 #include <X11/XF86keysym.h>
13 #include "base/basictypes.h"
14 #include "base/logging.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "ui/events/keycodes/dom4/keycode_converter.h"
21 // Get an ui::KeyboardCode from an X keyevent
22 KeyboardCode
KeyboardCodeFromXKeyEvent(XEvent
* xev
) {
23 // XLookupKeysym does not take into consideration the state of the lock/shift
24 // etc. keys. So it is necessary to use XLookupString instead.
26 XLookupString(&xev
->xkey
, NULL
, 0, &keysym
, NULL
);
27 KeyboardCode keycode
= KeyboardCodeFromXKeysym(keysym
);
28 if (keycode
== VKEY_UNKNOWN
) {
29 keysym
= DefaultXKeysymFromHardwareKeycode(xev
->xkey
.keycode
);
30 keycode
= KeyboardCodeFromXKeysym(keysym
);
36 KeyboardCode
KeyboardCodeFromXKeysym(unsigned int keysym
) {
37 // TODO(sad): Have |keysym| go through the X map list?
56 case XK_KP_Begin
: // NumPad 5 without Num Lock, for crosbug.com/29169.
68 case XK_KP_Page_Up
: // aka XK_KP_Prior
71 case XK_KP_Page_Down
: // aka XK_KP_Next
99 return VKEY_NONCONVERT
;
100 case XK_Zenkaku_Hankaku
:
101 return VKEY_DBE_DBCSCHAR
;
191 return static_cast<KeyboardCode
>(VKEY_0
+ (keysym
- XK_0
));
224 return static_cast<KeyboardCode
>(VKEY_NUMPAD0
+ (keysym
- XK_KP_0
));
228 return VKEY_MULTIPLY
;
231 case XK_KP_Separator
:
232 return VKEY_SEPARATOR
;
234 return VKEY_SUBTRACT
;
242 return VKEY_OEM_PLUS
;
245 return VKEY_OEM_COMMA
;
248 return VKEY_OEM_MINUS
;
251 return VKEY_OEM_PERIOD
;
267 case XK_bracketright
:
273 case XK_ISO_Level5_Shift
:
286 case XK_ISO_Level3_Shift
:
339 return static_cast<KeyboardCode
>(VKEY_F1
+ (keysym
- XK_F1
));
344 return static_cast<KeyboardCode
>(VKEY_F1
+ (keysym
- XK_KP_F1
));
346 case XK_guillemotleft
:
347 case XK_guillemotright
:
349 // In the case of canadian multilingual keyboard layout, VKEY_OEM_102 is
350 // assigned to ugrave key.
354 return VKEY_OEM_102
; // international backslash key in 102 keyboard.
356 // When evdev is in use, /usr/share/X11/xkb/symbols/inet maps F13-18 keys
357 // to the special XF86XK symbols to support Microsoft Ergonomic keyboards:
358 // https://bugs.freedesktop.org/show_bug.cgi?id=5783
359 // In Chrome, we map these X key symbols back to F13-18 since we don't have
360 // VKEYs for these XF86XK symbols.
374 // For supporting multimedia buttons on a USB keyboard.
376 return VKEY_BROWSER_BACK
;
378 return VKEY_BROWSER_FORWARD
;
380 return VKEY_BROWSER_REFRESH
;
382 return VKEY_BROWSER_STOP
;
384 return VKEY_BROWSER_SEARCH
;
385 case XF86XK_Favorites
:
386 return VKEY_BROWSER_FAVORITES
;
387 case XF86XK_HomePage
:
388 return VKEY_BROWSER_HOME
;
389 case XF86XK_AudioMute
:
390 return VKEY_VOLUME_MUTE
;
391 case XF86XK_AudioLowerVolume
:
392 return VKEY_VOLUME_DOWN
;
393 case XF86XK_AudioRaiseVolume
:
394 return VKEY_VOLUME_UP
;
395 case XF86XK_AudioNext
:
396 return VKEY_MEDIA_NEXT_TRACK
;
397 case XF86XK_AudioPrev
:
398 return VKEY_MEDIA_PREV_TRACK
;
399 case XF86XK_AudioStop
:
400 return VKEY_MEDIA_STOP
;
401 case XF86XK_AudioPlay
:
402 return VKEY_MEDIA_PLAY_PAUSE
;
404 return VKEY_MEDIA_LAUNCH_MAIL
;
405 case XF86XK_LaunchA
: // F3 on an Apple keyboard.
406 return VKEY_MEDIA_LAUNCH_APP1
;
407 case XF86XK_LaunchB
: // F4 on an Apple keyboard.
408 case XF86XK_Calculator
:
409 return VKEY_MEDIA_LAUNCH_APP2
;
412 case XF86XK_PowerOff
:
414 case XF86XK_MonBrightnessDown
:
415 return VKEY_BRIGHTNESS_DOWN
;
416 case XF86XK_MonBrightnessUp
:
417 return VKEY_BRIGHTNESS_UP
;
418 case XF86XK_KbdBrightnessDown
:
419 return VKEY_KBD_BRIGHTNESS_DOWN
;
420 case XF86XK_KbdBrightnessUp
:
421 return VKEY_KBD_BRIGHTNESS_UP
;
423 // TODO(sad): some keycodes are still missing.
425 DLOG(WARNING
) << "Unknown keysym: " << base::StringPrintf("0x%x", keysym
);
429 const char* CodeFromXEvent(XEvent
* xev
) {
430 return KeycodeConverter::GetInstance()->NativeKeycodeToCode(
434 uint16
GetCharacterFromXEvent(XEvent
* xev
) {
436 int bytes_written
= XLookupString(&xev
->xkey
, buf
, 6, NULL
, NULL
);
437 DCHECK_LE(bytes_written
, 6);
439 base::string16 result
;
440 return (bytes_written
> 0 && base::UTF8ToUTF16(buf
, bytes_written
, &result
) &&
441 result
.length() == 1) ? result
[0] : 0;
444 unsigned int DefaultXKeysymFromHardwareKeycode(unsigned int hardware_code
) {
445 // This function assumes that X11 is using evdev-based keycodes.
446 static const unsigned int kHardwareKeycodeMap
[] = {
447 // This table covers the core 105-key keyboard.
455 0, // XKB evdev (XKB - 8) X KeySym
456 0, // === =============== ======
457 XK_Escape
, // 0x09: KEY_ESC Escape
458 XK_1
, // 0x0A: KEY_1 1
459 XK_2
, // 0x0B: KEY_2 2
460 XK_3
, // 0x0C: KEY_3 3
461 XK_4
, // 0x0D: KEY_4 4
462 XK_5
, // 0x0E: KEY_5 5
463 XK_6
, // 0x0F: KEY_6 6
464 XK_7
, // 0x10: KEY_7 7
465 XK_8
, // 0x11: KEY_8 8
466 XK_9
, // 0x12: KEY_9 9
467 XK_0
, // 0x13: KEY_0 0
468 XK_minus
, // 0x14: KEY_MINUS minus
469 XK_equal
, // 0x15: KEY_EQUAL equal
470 XK_BackSpace
, // 0x16: KEY_BACKSPACE BackSpace
471 XK_Tab
, // 0x17: KEY_TAB Tab
472 XK_q
, // 0x18: KEY_Q q
473 XK_w
, // 0x19: KEY_W w
474 XK_e
, // 0x1A: KEY_E e
475 XK_r
, // 0x1B: KEY_R r
476 XK_t
, // 0x1C: KEY_T t
477 XK_y
, // 0x1D: KEY_Y y
478 XK_u
, // 0x1E: KEY_U u
479 XK_i
, // 0x1F: KEY_I i
480 XK_o
, // 0x20: KEY_O o
481 XK_p
, // 0x21: KEY_P p
482 XK_bracketleft
, // 0x22: KEY_LEFTBRACE bracketleft
483 XK_bracketright
, // 0x23: KEY_RIGHTBRACE bracketright
484 XK_Return
, // 0x24: KEY_ENTER Return
485 XK_Control_L
, // 0x25: KEY_LEFTCTRL Control_L
486 XK_a
, // 0x26: KEY_A a
487 XK_s
, // 0x27: KEY_S s
488 XK_d
, // 0x28: KEY_D d
489 XK_f
, // 0x29: KEY_F f
490 XK_g
, // 0x2A: KEY_G g
491 XK_h
, // 0x2B: KEY_H h
492 XK_j
, // 0x2C: KEY_J j
493 XK_k
, // 0x2D: KEY_K k
494 XK_l
, // 0x2E: KEY_L l
495 XK_semicolon
, // 0x2F: KEY_SEMICOLON semicolon
496 XK_apostrophe
, // 0x30: KEY_APOSTROPHE apostrophe
497 XK_grave
, // 0x31: KEY_GRAVE grave
498 XK_Shift_L
, // 0x32: KEY_LEFTSHIFT Shift_L
499 XK_backslash
, // 0x33: KEY_BACKSLASH backslash
500 XK_z
, // 0x34: KEY_Z z
501 XK_x
, // 0x35: KEY_X x
502 XK_c
, // 0x36: KEY_C c
503 XK_v
, // 0x37: KEY_V v
504 XK_b
, // 0x38: KEY_B b
505 XK_n
, // 0x39: KEY_N n
506 XK_m
, // 0x3A: KEY_M m
507 XK_comma
, // 0x3B: KEY_COMMA comma
508 XK_period
, // 0x3C: KEY_DOT period
509 XK_slash
, // 0x3D: KEY_SLASH slash
510 XK_Shift_R
, // 0x3E: KEY_RIGHTSHIFT Shift_R
511 0, // 0x3F: KEY_KPASTERISK KP_Multiply
512 XK_Alt_L
, // 0x40: KEY_LEFTALT Alt_L
513 XK_space
, // 0x41: KEY_SPACE space
514 XK_Caps_Lock
, // 0x42: KEY_CAPSLOCK Caps_Lock
515 XK_F1
, // 0x43: KEY_F1 F1
516 XK_F2
, // 0x44: KEY_F2 F2
517 XK_F3
, // 0x45: KEY_F3 F3
518 XK_F4
, // 0x46: KEY_F4 F4
519 XK_F5
, // 0x47: KEY_F5 F5
520 XK_F6
, // 0x48: KEY_F6 F6
521 XK_F7
, // 0x49: KEY_F7 F7
522 XK_F8
, // 0x4A: KEY_F8 F8
523 XK_F9
, // 0x4B: KEY_F9 F9
524 XK_F10
, // 0x4C: KEY_F10 F10
525 XK_Num_Lock
, // 0x4D: KEY_NUMLOCK Num_Lock
526 XK_Scroll_Lock
, // 0x4E: KEY_SCROLLLOCK Scroll_Lock
527 XK_KP_7
, // 0x4F: KEY_KP7 KP_7
528 XK_KP_8
, // 0x50: KEY_KP8 KP_8
529 XK_KP_9
, // 0x51: KEY_KP9 KP_9
530 XK_KP_Subtract
, // 0x52: KEY_KPMINUS KP_Subtract
531 XK_KP_4
, // 0x53: KEY_KP4 KP_4
532 XK_KP_5
, // 0x54: KEY_KP5 KP_5
533 XK_KP_6
, // 0x55: KEY_KP6 KP_6
534 XK_KP_Add
, // 0x56: KEY_KPPLUS KP_Add
535 XK_KP_1
, // 0x57: KEY_KP1 KP_1
536 XK_KP_2
, // 0x58: KEY_KP2 KP_2
537 XK_KP_3
, // 0x59: KEY_KP3 KP_3
538 XK_KP_0
, // 0x5A: KEY_KP0 KP_0
539 XK_KP_Decimal
, // 0x5B: KEY_KPDOT KP_Decimal
541 XK_Zenkaku_Hankaku
, // 0x5D: KEY_ZENKAKUHANKAKU Zenkaku_Hankaku
542 XK_backslash
, // 0x5E: KEY_102ND backslash
543 XK_F11
, // 0x5F: KEY_F11 F11
544 XK_F12
, // 0x60: KEY_F12 F12
545 XK_Romaji
, // 0x61: KEY_RO Romaji
546 XK_Katakana
, // 0x62: KEY_KATAKANA Katakana
547 XK_Hiragana
, // 0x63: KEY_HIRAGANA Hiragana
548 XK_Henkan
, // 0x64: KEY_HENKAN Henkan
549 XK_Hiragana_Katakana
, // 0x65: KEY_KATAKANAHIRAGANA Hiragana_Katakana
550 XK_Muhenkan
, // 0x66: KEY_MUHENKAN Muhenkan
551 XK_KP_Separator
, // 0x67: KEY_KPJPCOMMA KP_Separator
552 XK_KP_Enter
, // 0x68: KEY_KPENTER KP_Enter
553 XK_Control_R
, // 0x69: KEY_RIGHTCTRL Control_R
554 XK_KP_Divide
, // 0x6A: KEY_KPSLASH KP_Divide
555 XK_Print
, // 0x6B: KEY_SYSRQ Print
556 XK_Alt_R
, // 0x6C: KEY_RIGHTALT Alt_R
557 XK_Linefeed
, // 0x6D: KEY_LINEFEED Linefeed
558 XK_Home
, // 0x6E: KEY_HOME Home
559 XK_Up
, // 0x6F: KEY_UP Up
560 XK_Page_Up
, // 0x70: KEY_PAGEUP Page_Up
561 XK_Left
, // 0x71: KEY_LEFT Left
562 XK_Right
, // 0x72: KEY_RIGHT Right
563 XK_End
, // 0x73: KEY_END End
564 XK_Down
, // 0x74: KEY_DOWN Down
565 XK_Page_Down
, // 0x75: KEY_PAGEDOWN Page_Down
566 XK_Insert
, // 0x76: KEY_INSERT Insert
567 XK_Delete
, // 0x77: KEY_DELETE Delete
568 0, // 0x78: KEY_MACRO
569 XF86XK_AudioMute
, // 0x79: KEY_MUTE XF86AudioMute
570 XF86XK_AudioLowerVolume
, // 0x7A: KEY_VOLUMEDOWN XF86AudioLowerVolume
571 XF86XK_AudioRaiseVolume
, // 0x7B: KEY_VOLUMEUP XF86AudioRaiseVolume
572 XF86XK_PowerOff
, // 0x7C: KEY_POWER XF86PowerOff
573 XK_KP_Equal
, // 0x7D: KEY_KPEQUAL KP_Equal
574 XK_plusminus
, // 0x7E: KEY_KPPLUSMINUS plusminus
575 XK_Pause
, // 0x7F: KEY_PAUSE Pause
576 XF86XK_LaunchA
, // 0x80: KEY_SCALE XF86LaunchA
577 XK_KP_Decimal
, // 0x81: KEY_KPCOMMA KP_Decimal
578 XK_Hangul
, // 0x82: KEY_HANGUEL Hangul
579 XK_Hangul_Hanja
, // 0x83: KEY_HANJA Hangul_Hanja
580 XK_yen
, // 0x84: KEY_YEN yen
581 XK_Super_L
, // 0x85: KEY_LEFTMETA Super_L
582 XK_Super_R
, // 0x86: KEY_RIGHTMETA Super_R
583 XK_Menu
, // 0x87: KEY_COMPOSE Menu
586 if (hardware_code
>= arraysize(kHardwareKeycodeMap
)) {
587 // Additional keycodes used by the Chrome OS top row special function keys.
588 switch (hardware_code
) {
589 case 0xA6: // KEY_BACK
591 case 0xA7: // KEY_FORWARD
592 return XF86XK_Forward
;
593 case 0xB5: // KEY_REFRESH
594 return XF86XK_Reload
;
595 case 0xD4: // KEY_DASHBOARD
596 return XF86XK_LaunchB
;
597 case 0xE8: // KEY_BRIGHTNESSDOWN
598 return XF86XK_MonBrightnessDown
;
599 case 0xE9: // KEY_BRIGHTNESSUP
600 return XF86XK_MonBrightnessUp
;
604 return kHardwareKeycodeMap
[hardware_code
];
607 // TODO(jcampan): this method might be incomplete.
608 int XKeysymForWindowsKeyCode(KeyboardCode keycode
, bool shift
) {
631 return XK_KP_Multiply
;
635 return XK_KP_Subtract
;
637 return XK_KP_Decimal
;
644 return shift
? XK_ISO_Left_Tab
: XK_Tab
;
658 return XK_ISO_Level3_Shift
;
669 return XK_Hangul_Hanja
;
672 case VKEY_NONCONVERT
:
674 case VKEY_DBE_SBCSCHAR
:
675 return XK_Zenkaku_Hankaku
;
676 case VKEY_DBE_DBCSCHAR
:
677 return XK_Zenkaku_Hankaku
;
711 return shift
? XK_parenright
: XK_0
;
713 return shift
? XK_exclam
: XK_1
;
715 return shift
? XK_at
: XK_2
;
717 return shift
? XK_numbersign
: XK_3
;
719 return shift
? XK_dollar
: XK_4
;
721 return shift
? XK_percent
: XK_5
;
723 return shift
? XK_asciicircum
: XK_6
;
725 return shift
? XK_ampersand
: XK_7
;
727 return shift
? XK_asterisk
: XK_8
;
729 return shift
? XK_parenleft
: XK_9
;
757 return (shift
? XK_A
: XK_a
) + (keycode
- VKEY_A
);
768 return XK_Scroll_Lock
;
771 return shift
? XK_colon
: XK_semicolon
;
773 return shift
? XK_plus
: XK_equal
;
775 return shift
? XK_less
: XK_comma
;
777 return shift
? XK_underscore
: XK_minus
;
778 case VKEY_OEM_PERIOD
:
779 return shift
? XK_greater
: XK_period
;
781 return shift
? XK_question
: XK_slash
;
783 return shift
? XK_asciitilde
: XK_quoteleft
;
785 return shift
? XK_braceleft
: XK_bracketleft
;
787 return shift
? XK_bar
: XK_backslash
;
789 return shift
? XK_braceright
: XK_bracketright
;
791 return shift
? XK_quotedbl
: XK_quoteright
;
793 return XK_ISO_Level5_Shift
;
795 return shift
? XK_guillemotleft
: XK_guillemotright
;
821 return XK_F1
+ (keycode
- VKEY_F1
);
823 case VKEY_BROWSER_BACK
:
825 case VKEY_BROWSER_FORWARD
:
826 return XF86XK_Forward
;
827 case VKEY_BROWSER_REFRESH
:
828 return XF86XK_Reload
;
829 case VKEY_BROWSER_STOP
:
831 case VKEY_BROWSER_SEARCH
:
832 return XF86XK_Search
;
833 case VKEY_BROWSER_FAVORITES
:
834 return XF86XK_Favorites
;
835 case VKEY_BROWSER_HOME
:
836 return XF86XK_HomePage
;
837 case VKEY_VOLUME_MUTE
:
838 return XF86XK_AudioMute
;
839 case VKEY_VOLUME_DOWN
:
840 return XF86XK_AudioLowerVolume
;
842 return XF86XK_AudioRaiseVolume
;
843 case VKEY_MEDIA_NEXT_TRACK
:
844 return XF86XK_AudioNext
;
845 case VKEY_MEDIA_PREV_TRACK
:
846 return XF86XK_AudioPrev
;
847 case VKEY_MEDIA_STOP
:
848 return XF86XK_AudioStop
;
849 case VKEY_MEDIA_PLAY_PAUSE
:
850 return XF86XK_AudioPlay
;
851 case VKEY_MEDIA_LAUNCH_MAIL
:
853 case VKEY_MEDIA_LAUNCH_APP1
:
854 return XF86XK_LaunchA
;
855 case VKEY_MEDIA_LAUNCH_APP2
:
856 return XF86XK_LaunchB
;
860 return XF86XK_PowerOff
;
861 case VKEY_BRIGHTNESS_DOWN
:
862 return XF86XK_MonBrightnessDown
;
863 case VKEY_BRIGHTNESS_UP
:
864 return XF86XK_MonBrightnessUp
;
865 case VKEY_KBD_BRIGHTNESS_DOWN
:
866 return XF86XK_KbdBrightnessDown
;
867 case VKEY_KBD_BRIGHTNESS_UP
:
868 return XF86XK_KbdBrightnessUp
;
871 LOG(WARNING
) << "Unknown keycode:" << keycode
;