Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / events / keycodes / keyboard_code_conversion_x.cc
index 4f277ec..adfebfd 100644 (file)
@@ -7,10 +7,11 @@
 #include <algorithm>
 
 #define XK_3270  // for XK_3270_BackTab
-#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
-#include <X11/XF86keysym.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/keysym.h>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
@@ -18,6 +19,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/events/keycodes/dom4/keycode_converter.h"
+#include "ui/events/x/keysym_to_unicode.h"
 
 #define VKEY_UNSUPPORTED VKEY_UNKNOWN
 
@@ -460,7 +462,7 @@ KeyboardCode FindVK(const T_MAP& key, const T_MAP* map, size_t size) {
 }  // namespace
 
 // Get an ui::KeyboardCode from an X keyevent
-KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
+KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
   // Gets correct VKEY code from XEvent is performed as the following steps:
   // 1. Gets the keysym without modifier states.
   // 2. For [a-z] & [0-9] cases, returns the VKEY code accordingly.
@@ -475,11 +477,19 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
   // 8. If not found, fallback to find with the hardware code in US layout.
 
   KeySym keysym = NoSymbol;
-  XKeyEvent xkey = xev->xkey;
-  xkey.state &= (~0xFF | Mod2Mask);  // Clears the xkey's state except numlock.
+  XEvent xkeyevent = {0};
+  if (xev->type == GenericEvent) {
+    // Convert the XI2 key event into a core key event so that we can
+    // continue to use XLookupString() until crbug.com/367732 is complete.
+    InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
+  } else {
+    xkeyevent.xkey = xev->xkey;
+  }
+  XKeyEvent* xkey = &xkeyevent.xkey;
+  xkey->state &= (~0xFF | Mod2Mask);  // Clears the xkey's state except numlock.
   // XLookupKeysym does not take into consideration the state of the lock/shift
   // etc. keys. So it is necessary to use XLookupString instead.
-  XLookupString(&xkey, NULL, 0, &keysym, NULL);
+  XLookupString(xkey, NULL, 0, &keysym, NULL);
 
   // [a-z] cases.
   if (keysym >= XK_a && keysym <= XK_z)
@@ -499,24 +509,24 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
     if (keycode != VKEY_UNKNOWN)
       return keycode;
 
-    MAP1 key1 = {keysym & 0xFFFF, xkey.keycode, 0};
+    MAP1 key1 = {keysym & 0xFFFF, xkey->keycode, 0};
     keycode = FindVK(key1, map1, arraysize(map1));
     if (keycode != VKEY_UNKNOWN)
       return keycode;
 
     KeySym keysym_shift = NoSymbol;
-    xkey.state |= ShiftMask;
-    XLookupString(&xkey, NULL, 0, &keysym_shift, NULL);
-    MAP2 key2 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0};
+    xkey->state |= ShiftMask;
+    XLookupString(xkey, NULL, 0, &keysym_shift, NULL);
+    MAP2 key2 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0};
     keycode = FindVK(key2, map2, arraysize(map2));
     if (keycode != VKEY_UNKNOWN)
       return keycode;
 
     KeySym keysym_altgr = NoSymbol;
-    xkey.state &= ~ShiftMask;
-    xkey.state |= Mod1Mask;
-    XLookupString(&xkey, NULL, 0, &keysym_altgr, NULL);
-    MAP3 key3 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF,
+    xkey->state &= ~ShiftMask;
+    xkey->state |= Mod1Mask;
+    XLookupString(xkey, NULL, 0, &keysym_altgr, NULL);
+    MAP3 key3 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF,
                  keysym_altgr & 0xFFFF, 0};
     keycode = FindVK(key3, map3, arraysize(map3));
     if (keycode != VKEY_UNKNOWN)
@@ -525,7 +535,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
     // On Linux some keys has AltGr char but not on Windows.
     // So if cannot find VKEY with (ch0+sc+ch1+ch2) in map3, tries to fallback
     // to just find VKEY with (ch0+sc+ch1). This is the best we could do.
-    MAP3 key4 = {keysym & 0xFFFF, xkey.keycode, keysym_shift & 0xFFFF, 0xFFFF,
+    MAP3 key4 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0xFFFF,
                  0};
     const MAP3* p =
         std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3());
@@ -536,7 +546,7 @@ KeyboardCode KeyboardCodeFromXKeyEvent(XEvent* xev) {
 
   keycode = KeyboardCodeFromXKeysym(keysym);
   if (keycode == VKEY_UNKNOWN)
-    keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey.keycode);
+    keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey->keycode);
 
   return keycode;
 }
@@ -681,6 +691,7 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
     case XK_Alt_R:
       return VKEY_MENU;
     case XK_ISO_Level3_Shift:
+    case XK_Mode_switch:
       return VKEY_ALTGR;
     case XK_Multi_key:
       return VKEY_COMPOSE;
@@ -823,21 +834,27 @@ KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
   return VKEY_UNKNOWN;
 }
 
-const char* CodeFromXEvent(XEvent* xev) {
-  return KeycodeConverter::GetInstance()->NativeKeycodeToCode(
-      xev->xkey.keycode);
+const char* CodeFromXEvent(const XEvent* xev) {
+  int keycode = (xev->type == GenericEvent)
+                    ? static_cast<XIDeviceEvent*>(xev->xcookie.data)->detail
+                    : xev->xkey.keycode;
+  return KeycodeConverter::GetInstance()->NativeKeycodeToCode(keycode);
 }
 
-uint16 GetCharacterFromXEvent(XEvent* xev) {
-  char buf[6];
-  int bytes_written = XLookupString(&xev->xkey, buf, 6, NULL, NULL);
-  DCHECK_LE(bytes_written, 6);
-
-  if (bytes_written <= 0)
-    return 0;
-  const base::string16& result = base::WideToUTF16(
-      base::SysNativeMBToWide(base::StringPiece(buf, bytes_written)));
-  return result.length() == 1 ? result[0] : 0;
+uint16 GetCharacterFromXEvent(const XEvent* xev) {
+  XEvent xkeyevent = {0};
+  const XKeyEvent* xkey = NULL;
+  if (xev->type == GenericEvent) {
+    // Convert the XI2 key event into a core key event so that we can
+    // continue to use XLookupString() until crbug.com/367732 is complete.
+    InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
+    xkey = &xkeyevent.xkey;
+  } else {
+    xkey = &xev->xkey;
+  }
+  KeySym keysym = XK_VoidSymbol;
+  XLookupString(const_cast<XKeyEvent*>(xkey), NULL, 0, &keysym, NULL);
+  return GetUnicodeCharacterFromXKeySym(keysym);
 }
 
 KeyboardCode DefaultKeyboardCodeFromHardwareKeycode(
@@ -1276,4 +1293,59 @@ int XKeysymForWindowsKeyCode(KeyboardCode keycode, bool shift) {
     }
 }
 
+void InitXKeyEventFromXIDeviceEvent(const XEvent& src, XEvent* xkeyevent) {
+  DCHECK(src.type == GenericEvent);
+  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(src.xcookie.data);
+  switch (xievent->evtype) {
+    case XI_KeyPress:
+      xkeyevent->type = KeyPress;
+      break;
+    case XI_KeyRelease:
+      xkeyevent->type = KeyRelease;
+      break;
+    default:
+      NOTREACHED();
+  }
+  xkeyevent->xkey.serial = xievent->serial;
+  xkeyevent->xkey.send_event = xievent->send_event;
+  xkeyevent->xkey.display = xievent->display;
+  xkeyevent->xkey.window = xievent->event;
+  xkeyevent->xkey.root = xievent->root;
+  xkeyevent->xkey.subwindow = xievent->child;
+  xkeyevent->xkey.time = xievent->time;
+  xkeyevent->xkey.x = xievent->event_x;
+  xkeyevent->xkey.y = xievent->event_y;
+  xkeyevent->xkey.x_root = xievent->root_x;
+  xkeyevent->xkey.y_root = xievent->root_y;
+  xkeyevent->xkey.state = xievent->mods.effective;
+  xkeyevent->xkey.keycode = xievent->detail;
+  xkeyevent->xkey.same_screen = 1;
+}
+
+unsigned int XKeyCodeForWindowsKeyCode(ui::KeyboardCode key_code,
+                                       int flags,
+                                       XDisplay* display) {
+  // SHIFT state is ignored in the call to XKeysymForWindowsKeyCode() here
+  // because we map the XKeysym back to a keycode, i.e. a physical key position.
+  // Using a SHIFT-modified XKeysym would sometimes yield X keycodes that,
+  // while technically valid, may be surprising in that they do not match
+  // the keycode of the original press, and conflict with assumptions in
+  // other code.
+  //
+  // For example, in a US layout, Shift-9 has the interpretation XK_parenleft,
+  // but the keycode KEY_9 alone does not map to XK_parenleft; instead,
+  // XKeysymToKeycode() returns KEY_KPLEFTPAREN (keypad left parenthesis)
+  // which does map to XK_parenleft -- notwithstanding that keyboards with
+  // dedicated number pad parenthesis keys are currently uncommon.
+  //
+  // Similarly, Shift-Comma has the interpretation XK_less, but KEY_COMMA
+  // alone does not map to XK_less; XKeysymToKeycode() returns KEY_102ND
+  // (the '<>' key between Shift and Z on 105-key keyboards) which does.
+  //
+  // crbug.com/386066 and crbug.com/390263 are examples of problems
+  // associated with this.
+  //
+  return XKeysymToKeycode(display, XKeysymForWindowsKeyCode(key_code, false));
+}
+
 }  // namespace ui