| /* |
| * Keyboard related functions |
| * |
| * Copyright 1993 Bob Amstadt |
| * Copyright 1996 Albrecht Kleine |
| * Copyright 1997 David Faure |
| * Copyright 1998 Morten Welinder |
| * Copyright 1998 Ulrich Weigand |
| * Copyright 1999 Ove Kåven |
| * Copyright 2011, 2012, 2013 Ken Thomases for CodeWeavers Inc. |
| * Copyright 2013 Alexandre Julliard |
| * Copyright 2015 Josh DuBois for CodeWeavers Inc. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define NONAMELESSUNION |
| #define NONAMELESSSTRUCT |
| |
| #include "config.h" |
| |
| #include "android.h" |
| #include "wine/unicode.h" |
| #include "wine/server.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(keyboard); |
| WINE_DECLARE_DEBUG_CHANNEL(key); |
| |
| static const UINT keycode_to_vkey[] = |
| { |
| 0, /* AKEYCODE_UNKNOWN */ |
| 0, /* AKEYCODE_SOFT_LEFT */ |
| 0, /* AKEYCODE_SOFT_RIGHT */ |
| 0, /* AKEYCODE_HOME */ |
| 0, /* AKEYCODE_BACK */ |
| 0, /* AKEYCODE_CALL */ |
| 0, /* AKEYCODE_ENDCALL */ |
| '0', /* AKEYCODE_0 */ |
| '1', /* AKEYCODE_1 */ |
| '2', /* AKEYCODE_2 */ |
| '3', /* AKEYCODE_3 */ |
| '4', /* AKEYCODE_4 */ |
| '5', /* AKEYCODE_5 */ |
| '6', /* AKEYCODE_6 */ |
| '7', /* AKEYCODE_7 */ |
| '8', /* AKEYCODE_8 */ |
| '9', /* AKEYCODE_9 */ |
| 0, /* AKEYCODE_STAR */ |
| 0, /* AKEYCODE_POUND */ |
| VK_UP, /* AKEYCODE_DPAD_UP */ |
| VK_DOWN, /* AKEYCODE_DPAD_DOWN */ |
| VK_LEFT, /* AKEYCODE_DPAD_LEFT */ |
| VK_RIGHT, /* AKEYCODE_DPAD_RIGHT */ |
| 0, /* AKEYCODE_DPAD_CENTER */ |
| 0, /* AKEYCODE_VOLUME_UP */ |
| 0, /* AKEYCODE_VOLUME_DOWN */ |
| 0, /* AKEYCODE_POWER */ |
| 0, /* AKEYCODE_CAMERA */ |
| 0, /* AKEYCODE_CLEAR */ |
| 'A', /* AKEYCODE_A */ |
| 'B', /* AKEYCODE_B */ |
| 'C', /* AKEYCODE_C */ |
| 'D', /* AKEYCODE_D */ |
| 'E', /* AKEYCODE_E */ |
| 'F', /* AKEYCODE_F */ |
| 'G', /* AKEYCODE_G */ |
| 'H', /* AKEYCODE_H */ |
| 'I', /* AKEYCODE_I */ |
| 'J', /* AKEYCODE_J */ |
| 'K', /* AKEYCODE_K */ |
| 'L', /* AKEYCODE_L */ |
| 'M', /* AKEYCODE_M */ |
| 'N', /* AKEYCODE_N */ |
| 'O', /* AKEYCODE_O */ |
| 'P', /* AKEYCODE_P */ |
| 'Q', /* AKEYCODE_Q */ |
| 'R', /* AKEYCODE_R */ |
| 'S', /* AKEYCODE_S */ |
| 'T', /* AKEYCODE_T */ |
| 'U', /* AKEYCODE_U */ |
| 'V', /* AKEYCODE_V */ |
| 'W', /* AKEYCODE_W */ |
| 'X', /* AKEYCODE_X */ |
| 'Y', /* AKEYCODE_Y */ |
| 'Z', /* AKEYCODE_Z */ |
| VK_OEM_COMMA, /* AKEYCODE_COMMA */ |
| VK_OEM_PERIOD, /* AKEYCODE_PERIOD */ |
| VK_LMENU, /* AKEYCODE_ALT_LEFT */ |
| VK_RMENU, /* AKEYCODE_ALT_RIGHT */ |
| VK_LSHIFT, /* AKEYCODE_SHIFT_LEFT */ |
| VK_RSHIFT, /* AKEYCODE_SHIFT_RIGHT */ |
| VK_TAB, /* AKEYCODE_TAB */ |
| VK_SPACE, /* AKEYCODE_SPACE */ |
| 0, /* AKEYCODE_SYM */ |
| 0, /* AKEYCODE_EXPLORER */ |
| 0, /* AKEYCODE_ENVELOPE */ |
| VK_RETURN, /* AKEYCODE_ENTER */ |
| VK_BACK, /* AKEYCODE_DEL */ |
| VK_OEM_3, /* AKEYCODE_GRAVE */ |
| VK_OEM_MINUS, /* AKEYCODE_MINUS */ |
| VK_OEM_PLUS, /* AKEYCODE_EQUALS */ |
| VK_OEM_4, /* AKEYCODE_LEFT_BRACKET */ |
| VK_OEM_6, /* AKEYCODE_RIGHT_BRACKET */ |
| VK_OEM_5, /* AKEYCODE_BACKSLASH */ |
| VK_OEM_1, /* AKEYCODE_SEMICOLON */ |
| VK_OEM_7, /* AKEYCODE_APOSTROPHE */ |
| VK_OEM_2, /* AKEYCODE_SLASH */ |
| 0, /* AKEYCODE_AT */ |
| 0, /* AKEYCODE_NUM */ |
| 0, /* AKEYCODE_HEADSETHOOK */ |
| 0, /* AKEYCODE_FOCUS */ |
| 0, /* AKEYCODE_PLUS */ |
| 0, /* AKEYCODE_MENU */ |
| 0, /* AKEYCODE_NOTIFICATION */ |
| 0, /* AKEYCODE_SEARCH */ |
| VK_MEDIA_PLAY_PAUSE, /* AKEYCODE_MEDIA_PLAY_PAUSE */ |
| VK_MEDIA_STOP, /* AKEYCODE_MEDIA_STOP */ |
| VK_MEDIA_NEXT_TRACK, /* AKEYCODE_MEDIA_NEXT */ |
| VK_MEDIA_PREV_TRACK, /* AKEYCODE_MEDIA_PREVIOUS */ |
| 0, /* AKEYCODE_MEDIA_REWIND */ |
| 0, /* AKEYCODE_MEDIA_FAST_FORWARD */ |
| 0, /* AKEYCODE_MUTE */ |
| VK_PRIOR, /* AKEYCODE_PAGE_UP */ |
| VK_NEXT, /* AKEYCODE_PAGE_DOWN */ |
| 0, /* AKEYCODE_PICTSYMBOLS */ |
| 0, /* AKEYCODE_SWITCH_CHARSET */ |
| 0, /* AKEYCODE_BUTTON_A */ |
| 0, /* AKEYCODE_BUTTON_B */ |
| 0, /* AKEYCODE_BUTTON_C */ |
| 0, /* AKEYCODE_BUTTON_X */ |
| 0, /* AKEYCODE_BUTTON_Y */ |
| 0, /* AKEYCODE_BUTTON_Z */ |
| 0, /* AKEYCODE_BUTTON_L1 */ |
| 0, /* AKEYCODE_BUTTON_R1 */ |
| 0, /* AKEYCODE_BUTTON_L2 */ |
| 0, /* AKEYCODE_BUTTON_R2 */ |
| 0, /* AKEYCODE_BUTTON_THUMBL */ |
| 0, /* AKEYCODE_BUTTON_THUMBR */ |
| 0, /* AKEYCODE_BUTTON_START */ |
| 0, /* AKEYCODE_BUTTON_SELECT */ |
| 0, /* AKEYCODE_BUTTON_MODE */ |
| VK_ESCAPE, /* AKEYCODE_ESCAPE */ |
| VK_DELETE, /* AKEYCODE_FORWARD_DEL */ |
| VK_LCONTROL, /* AKEYCODE_CTRL_LEFT */ |
| VK_RCONTROL, /* AKEYCODE_CTRL_RIGHT */ |
| VK_CAPITAL, /* AKEYCODE_CAPS_LOCK */ |
| VK_SCROLL, /* AKEYCODE_SCROLL_LOCK */ |
| VK_LWIN, /* AKEYCODE_META_LEFT */ |
| VK_RWIN, /* AKEYCODE_META_RIGHT */ |
| 0, /* AKEYCODE_FUNCTION */ |
| 0, /* AKEYCODE_SYSRQ */ |
| 0, /* AKEYCODE_BREAK */ |
| VK_HOME, /* AKEYCODE_MOVE_HOME */ |
| VK_END, /* AKEYCODE_MOVE_END */ |
| VK_INSERT, /* AKEYCODE_INSERT */ |
| 0, /* AKEYCODE_FORWARD */ |
| 0, /* AKEYCODE_MEDIA_PLAY */ |
| 0, /* AKEYCODE_MEDIA_PAUSE */ |
| 0, /* AKEYCODE_MEDIA_CLOSE */ |
| 0, /* AKEYCODE_MEDIA_EJECT */ |
| 0, /* AKEYCODE_MEDIA_RECORD */ |
| VK_F1, /* AKEYCODE_F1 */ |
| VK_F2, /* AKEYCODE_F2 */ |
| VK_F3, /* AKEYCODE_F3 */ |
| VK_F4, /* AKEYCODE_F4 */ |
| VK_F5, /* AKEYCODE_F5 */ |
| VK_F6, /* AKEYCODE_F6 */ |
| VK_F7, /* AKEYCODE_F7 */ |
| VK_F8, /* AKEYCODE_F8 */ |
| VK_F9, /* AKEYCODE_F9 */ |
| VK_F10, /* AKEYCODE_F10 */ |
| VK_F11, /* AKEYCODE_F11 */ |
| VK_F12, /* AKEYCODE_F12 */ |
| VK_NUMLOCK, /* AKEYCODE_NUM_LOCK */ |
| VK_NUMPAD0, /* AKEYCODE_NUMPAD_0 */ |
| VK_NUMPAD1, /* AKEYCODE_NUMPAD_1 */ |
| VK_NUMPAD2, /* AKEYCODE_NUMPAD_2 */ |
| VK_NUMPAD3, /* AKEYCODE_NUMPAD_3 */ |
| VK_NUMPAD4, /* AKEYCODE_NUMPAD_4 */ |
| VK_NUMPAD5, /* AKEYCODE_NUMPAD_5 */ |
| VK_NUMPAD6, /* AKEYCODE_NUMPAD_6 */ |
| VK_NUMPAD7, /* AKEYCODE_NUMPAD_7 */ |
| VK_NUMPAD8, /* AKEYCODE_NUMPAD_8 */ |
| VK_NUMPAD9, /* AKEYCODE_NUMPAD_9 */ |
| VK_DIVIDE, /* AKEYCODE_NUMPAD_DIVIDE */ |
| VK_MULTIPLY, /* AKEYCODE_NUMPAD_MULTIPLY */ |
| VK_SUBTRACT, /* AKEYCODE_NUMPAD_SUBTRACT */ |
| VK_ADD, /* AKEYCODE_NUMPAD_ADD */ |
| VK_DECIMAL, /* AKEYCODE_NUMPAD_DOT */ |
| 0, /* AKEYCODE_NUMPAD_COMMA */ |
| 0, /* AKEYCODE_NUMPAD_ENTER */ |
| 0, /* AKEYCODE_NUMPAD_EQUALS */ |
| 0, /* AKEYCODE_NUMPAD_LEFT_PAREN */ |
| 0, /* AKEYCODE_NUMPAD_RIGHT_PAREN */ |
| 0, /* AKEYCODE_VOLUME_MUTE */ |
| 0, /* AKEYCODE_INFO */ |
| 0, /* AKEYCODE_CHANNEL_UP */ |
| 0, /* AKEYCODE_CHANNEL_DOWN */ |
| 0, /* AKEYCODE_ZOOM_IN */ |
| 0, /* AKEYCODE_ZOOM_OUT */ |
| 0, /* AKEYCODE_TV */ |
| 0, /* AKEYCODE_WINDOW */ |
| 0, /* AKEYCODE_GUIDE */ |
| 0, /* AKEYCODE_DVR */ |
| 0, /* AKEYCODE_BOOKMARK */ |
| 0, /* AKEYCODE_CAPTIONS */ |
| 0, /* AKEYCODE_SETTINGS */ |
| 0, /* AKEYCODE_TV_POWER */ |
| 0, /* AKEYCODE_TV_INPUT */ |
| 0, /* AKEYCODE_STB_POWER */ |
| 0, /* AKEYCODE_STB_INPUT */ |
| 0, /* AKEYCODE_AVR_POWER */ |
| 0, /* AKEYCODE_AVR_INPUT */ |
| 0, /* AKEYCODE_PROG_RED */ |
| 0, /* AKEYCODE_PROG_GREEN */ |
| 0, /* AKEYCODE_PROG_YELLOW */ |
| 0, /* AKEYCODE_PROG_BLUE */ |
| 0, /* AKEYCODE_APP_SWITCH */ |
| 0, /* AKEYCODE_BUTTON_1 */ |
| 0, /* AKEYCODE_BUTTON_2 */ |
| 0, /* AKEYCODE_BUTTON_3 */ |
| 0, /* AKEYCODE_BUTTON_4 */ |
| 0, /* AKEYCODE_BUTTON_5 */ |
| 0, /* AKEYCODE_BUTTON_6 */ |
| 0, /* AKEYCODE_BUTTON_7 */ |
| 0, /* AKEYCODE_BUTTON_8 */ |
| 0, /* AKEYCODE_BUTTON_9 */ |
| 0, /* AKEYCODE_BUTTON_10 */ |
| 0, /* AKEYCODE_BUTTON_11 */ |
| 0, /* AKEYCODE_BUTTON_12 */ |
| 0, /* AKEYCODE_BUTTON_13 */ |
| 0, /* AKEYCODE_BUTTON_14 */ |
| 0, /* AKEYCODE_BUTTON_15 */ |
| 0, /* AKEYCODE_BUTTON_16 */ |
| 0, /* AKEYCODE_LANGUAGE_SWITCH */ |
| 0, /* AKEYCODE_MANNER_MODE */ |
| 0, /* AKEYCODE_3D_MODE */ |
| 0, /* AKEYCODE_CONTACTS */ |
| 0, /* AKEYCODE_CALENDAR */ |
| 0, /* AKEYCODE_MUSIC */ |
| 0, /* AKEYCODE_CALCULATOR */ |
| 0, /* AKEYCODE_ZENKAKU_HANKAKU */ |
| 0, /* AKEYCODE_EISU */ |
| 0, /* AKEYCODE_MUHENKAN */ |
| 0, /* AKEYCODE_HENKAN */ |
| 0, /* AKEYCODE_KATAKANA_HIRAGANA */ |
| 0, /* AKEYCODE_YEN */ |
| 0, /* AKEYCODE_RO */ |
| VK_KANA, /* AKEYCODE_KANA */ |
| 0, /* AKEYCODE_ASSIST */ |
| }; |
| |
| static const WORD vkey_to_scancode[] = |
| { |
| 0, /* 0x00 undefined */ |
| 0, /* VK_LBUTTON */ |
| 0, /* VK_RBUTTON */ |
| 0, /* VK_CANCEL */ |
| 0, /* VK_MBUTTON */ |
| 0, /* VK_XBUTTON1 */ |
| 0, /* VK_XBUTTON2 */ |
| 0, /* 0x07 undefined */ |
| 0x0e, /* VK_BACK */ |
| 0x0f, /* VK_TAB */ |
| 0, /* 0x0a undefined */ |
| 0, /* 0x0b undefined */ |
| 0, /* VK_CLEAR */ |
| 0x1c, /* VK_RETURN */ |
| 0, /* 0x0e undefined */ |
| 0, /* 0x0f undefined */ |
| 0x2a, /* VK_SHIFT */ |
| 0x1d, /* VK_CONTROL */ |
| 0x38, /* VK_MENU */ |
| 0, /* VK_PAUSE */ |
| 0x3a, /* VK_CAPITAL */ |
| 0, /* VK_KANA */ |
| 0, /* 0x16 undefined */ |
| 0, /* VK_JUNJA */ |
| 0, /* VK_FINAL */ |
| 0, /* VK_HANJA */ |
| 0, /* 0x1a undefined */ |
| 0x01, /* VK_ESCAPE */ |
| 0, /* VK_CONVERT */ |
| 0, /* VK_NONCONVERT */ |
| 0, /* VK_ACCEPT */ |
| 0, /* VK_MODECHANGE */ |
| 0x39, /* VK_SPACE */ |
| 0x149, /* VK_PRIOR */ |
| 0x151, /* VK_NEXT */ |
| 0x14f, /* VK_END */ |
| 0x147, /* VK_HOME */ |
| 0x14b, /* VK_LEFT */ |
| 0x148, /* VK_UP */ |
| 0x14d, /* VK_RIGHT */ |
| 0x150, /* VK_DOWN */ |
| 0, /* VK_SELECT */ |
| 0, /* VK_PRINT */ |
| 0, /* VK_EXECUTE */ |
| 0, /* VK_SNAPSHOT */ |
| 0x152, /* VK_INSERT */ |
| 0x153, /* VK_DELETE */ |
| 0, /* VK_HELP */ |
| 0x0b, /* VK_0 */ |
| 0x02, /* VK_1 */ |
| 0x03, /* VK_2 */ |
| 0x04, /* VK_3 */ |
| 0x05, /* VK_4 */ |
| 0x06, /* VK_5 */ |
| 0x07, /* VK_6 */ |
| 0x08, /* VK_7 */ |
| 0x09, /* VK_8 */ |
| 0x0a, /* VK_9 */ |
| 0, /* 0x3a undefined */ |
| 0, /* 0x3b undefined */ |
| 0, /* 0x3c undefined */ |
| 0, /* 0x3d undefined */ |
| 0, /* 0x3e undefined */ |
| 0, /* 0x3f undefined */ |
| 0, /* 0x40 undefined */ |
| 0x1e, /* VK_A */ |
| 0x30, /* VK_B */ |
| 0x2e, /* VK_C */ |
| 0x20, /* VK_D */ |
| 0x12, /* VK_E */ |
| 0x21, /* VK_F */ |
| 0x22, /* VK_G */ |
| 0x23, /* VK_H */ |
| 0x17, /* VK_I */ |
| 0x24, /* VK_J */ |
| 0x25, /* VK_K */ |
| 0x26, /* VK_L */ |
| 0x32, /* VK_M */ |
| 0x31, /* VK_N */ |
| 0x18, /* VK_O */ |
| 0x19, /* VK_P */ |
| 0x10, /* VK_Q */ |
| 0x13, /* VK_R */ |
| 0x1f, /* VK_S */ |
| 0x14, /* VK_T */ |
| 0x16, /* VK_U */ |
| 0x2f, /* VK_V */ |
| 0x11, /* VK_W */ |
| 0x2d, /* VK_X */ |
| 0x15, /* VK_Y */ |
| 0x2c, /* VK_Z */ |
| 0, /* VK_LWIN */ |
| 0, /* VK_RWIN */ |
| 0, /* VK_APPS */ |
| 0, /* 0x5e undefined */ |
| 0, /* VK_SLEEP */ |
| 0x52, /* VK_NUMPAD0 */ |
| 0x4f, /* VK_NUMPAD1 */ |
| 0x50, /* VK_NUMPAD2 */ |
| 0x51, /* VK_NUMPAD3 */ |
| 0x4b, /* VK_NUMPAD4 */ |
| 0x4c, /* VK_NUMPAD5 */ |
| 0x4d, /* VK_NUMPAD6 */ |
| 0x47, /* VK_NUMPAD7 */ |
| 0x48, /* VK_NUMPAD8 */ |
| 0x49, /* VK_NUMPAD9 */ |
| 0x37, /* VK_MULTIPLY */ |
| 0x4e, /* VK_ADD */ |
| 0x7e, /* VK_SEPARATOR */ |
| 0x4a, /* VK_SUBTRACT */ |
| 0x53, /* VK_DECIMAL */ |
| 0135, /* VK_DIVIDE */ |
| 0x3b, /* VK_F1 */ |
| 0x3c, /* VK_F2 */ |
| 0x3d, /* VK_F3 */ |
| 0x3e, /* VK_F4 */ |
| 0x3f, /* VK_F5 */ |
| 0x40, /* VK_F6 */ |
| 0x41, /* VK_F7 */ |
| 0x42, /* VK_F8 */ |
| 0x43, /* VK_F9 */ |
| 0x44, /* VK_F10 */ |
| 0x57, /* VK_F11 */ |
| 0x58, /* VK_F12 */ |
| 0x64, /* VK_F13 */ |
| 0x65, /* VK_F14 */ |
| 0x66, /* VK_F15 */ |
| 0x67, /* VK_F16 */ |
| 0x68, /* VK_F17 */ |
| 0x69, /* VK_F18 */ |
| 0x6a, /* VK_F19 */ |
| 0x6b, /* VK_F20 */ |
| 0, /* VK_F21 */ |
| 0, /* VK_F22 */ |
| 0, /* VK_F23 */ |
| 0, /* VK_F24 */ |
| 0, /* 0x88 undefined */ |
| 0, /* 0x89 undefined */ |
| 0, /* 0x8a undefined */ |
| 0, /* 0x8b undefined */ |
| 0, /* 0x8c undefined */ |
| 0, /* 0x8d undefined */ |
| 0, /* 0x8e undefined */ |
| 0, /* 0x8f undefined */ |
| 0, /* VK_NUMLOCK */ |
| 0, /* VK_SCROLL */ |
| 0x10d, /* VK_OEM_NEC_EQUAL */ |
| 0, /* VK_OEM_FJ_JISHO */ |
| 0, /* VK_OEM_FJ_MASSHOU */ |
| 0, /* VK_OEM_FJ_TOUROKU */ |
| 0, /* VK_OEM_FJ_LOYA */ |
| 0, /* VK_OEM_FJ_ROYA */ |
| 0, /* 0x97 undefined */ |
| 0, /* 0x98 undefined */ |
| 0, /* 0x99 undefined */ |
| 0, /* 0x9a undefined */ |
| 0, /* 0x9b undefined */ |
| 0, /* 0x9c undefined */ |
| 0, /* 0x9d undefined */ |
| 0, /* 0x9e undefined */ |
| 0, /* 0x9f undefined */ |
| 0x2a, /* VK_LSHIFT */ |
| 0x36, /* VK_RSHIFT */ |
| 0x1d, /* VK_LCONTROL */ |
| 0x11d, /* VK_RCONTROL */ |
| 0x38, /* VK_LMENU */ |
| 0x138, /* VK_RMENU */ |
| 0, /* VK_BROWSER_BACK */ |
| 0, /* VK_BROWSER_FORWARD */ |
| 0, /* VK_BROWSER_REFRESH */ |
| 0, /* VK_BROWSER_STOP */ |
| 0, /* VK_BROWSER_SEARCH */ |
| 0, /* VK_BROWSER_FAVORITES */ |
| 0, /* VK_BROWSER_HOME */ |
| 0x100, /* VK_VOLUME_MUTE */ |
| 0x100, /* VK_VOLUME_DOWN */ |
| 0x100, /* VK_VOLUME_UP */ |
| 0, /* VK_MEDIA_NEXT_TRACK */ |
| 0, /* VK_MEDIA_PREV_TRACK */ |
| 0, /* VK_MEDIA_STOP */ |
| 0, /* VK_MEDIA_PLAY_PAUSE */ |
| 0, /* VK_LAUNCH_MAIL */ |
| 0, /* VK_LAUNCH_MEDIA_SELECT */ |
| 0, /* VK_LAUNCH_APP1 */ |
| 0, /* VK_LAUNCH_APP2 */ |
| 0, /* 0xb8 undefined */ |
| 0, /* 0xb9 undefined */ |
| 0x27, /* VK_OEM_1 */ |
| 0x0d, /* VK_OEM_PLUS */ |
| 0x33, /* VK_OEM_COMMA */ |
| 0x0c, /* VK_OEM_MINUS */ |
| 0x34, /* VK_OEM_PERIOD */ |
| 0x35, /* VK_OEM_2 */ |
| 0x29, /* VK_OEM_3 */ |
| 0, /* 0xc1 undefined */ |
| 0, /* 0xc2 undefined */ |
| 0, /* 0xc3 undefined */ |
| 0, /* 0xc4 undefined */ |
| 0, /* 0xc5 undefined */ |
| 0, /* 0xc6 undefined */ |
| 0, /* 0xc7 undefined */ |
| 0, /* 0xc8 undefined */ |
| 0, /* 0xc9 undefined */ |
| 0, /* 0xca undefined */ |
| 0, /* 0xcb undefined */ |
| 0, /* 0xcc undefined */ |
| 0, /* 0xcd undefined */ |
| 0, /* 0xce undefined */ |
| 0, /* 0xcf undefined */ |
| 0, /* 0xd0 undefined */ |
| 0, /* 0xd1 undefined */ |
| 0, /* 0xd2 undefined */ |
| 0, /* 0xd3 undefined */ |
| 0, /* 0xd4 undefined */ |
| 0, /* 0xd5 undefined */ |
| 0, /* 0xd6 undefined */ |
| 0, /* 0xd7 undefined */ |
| 0, /* 0xd8 undefined */ |
| 0, /* 0xd9 undefined */ |
| 0, /* 0xda undefined */ |
| 0x1a, /* VK_OEM_4 */ |
| 0x2b, /* VK_OEM_5 */ |
| 0x1b, /* VK_OEM_6 */ |
| 0x28, /* VK_OEM_7 */ |
| 0, /* VK_OEM_8 */ |
| 0, /* 0xe0 undefined */ |
| 0, /* VK_OEM_AX */ |
| 0x56, /* VK_OEM_102 */ |
| 0, /* VK_ICO_HELP */ |
| 0, /* VK_ICO_00 */ |
| 0, /* VK_PROCESSKEY */ |
| 0, /* VK_ICO_CLEAR */ |
| 0, /* VK_PACKET */ |
| 0, /* 0xe8 undefined */ |
| 0x71, /* VK_OEM_RESET */ |
| 0, /* VK_OEM_JUMP */ |
| 0, /* VK_OEM_PA1 */ |
| 0, /* VK_OEM_PA2 */ |
| 0, /* VK_OEM_PA3 */ |
| 0, /* VK_OEM_WSCTRL */ |
| 0, /* VK_OEM_CUSEL */ |
| 0, /* VK_OEM_ATTN */ |
| 0, /* VK_OEM_FINISH */ |
| 0, /* VK_OEM_COPY */ |
| 0, /* VK_OEM_AUTO */ |
| 0, /* VK_OEM_ENLW */ |
| 0, /* VK_OEM_BACKTAB */ |
| 0, /* VK_ATTN */ |
| 0, /* VK_CRSEL */ |
| 0, /* VK_EXSEL */ |
| 0, /* VK_EREOF */ |
| 0, /* VK_PLAY */ |
| 0, /* VK_ZOOM */ |
| 0, /* VK_NONAME */ |
| 0, /* VK_PA1 */ |
| 0x59, /* VK_OEM_CLEAR */ |
| 0, /* 0xff undefined */ |
| }; |
| |
| static const struct |
| { |
| DWORD vkey; |
| const char *name; |
| } vkey_names[] = { |
| { VK_ADD, "Num +" }, |
| { VK_BACK, "Backspace" }, |
| { VK_CAPITAL, "Caps Lock" }, |
| { VK_CONTROL, "Ctrl" }, |
| { VK_DECIMAL, "Num Del" }, |
| { VK_DELETE | 0x100, "Delete" }, |
| { VK_DIVIDE | 0x100, "Num /" }, |
| { VK_DOWN | 0x100, "Down" }, |
| { VK_END | 0x100, "End" }, |
| { VK_ESCAPE, "Esc" }, |
| { VK_F1, "F1" }, |
| { VK_F2, "F2" }, |
| { VK_F3, "F3" }, |
| { VK_F4, "F4" }, |
| { VK_F5, "F5" }, |
| { VK_F6, "F6" }, |
| { VK_F7, "F7" }, |
| { VK_F8, "F8" }, |
| { VK_F9, "F9" }, |
| { VK_F10, "F10" }, |
| { VK_F11, "F11" }, |
| { VK_F12, "F12" }, |
| { VK_F13, "F13" }, |
| { VK_F14, "F14" }, |
| { VK_F15, "F15" }, |
| { VK_F16, "F16" }, |
| { VK_F17, "F17" }, |
| { VK_F18, "F18" }, |
| { VK_F19, "F19" }, |
| { VK_F20, "F20" }, |
| { VK_F21, "F21" }, |
| { VK_F22, "F22" }, |
| { VK_F23, "F23" }, |
| { VK_F24, "F24" }, |
| { VK_HELP | 0x100, "Help" }, |
| { VK_HOME | 0x100, "Home" }, |
| { VK_INSERT | 0x100, "Insert" }, |
| { VK_LCONTROL, "Ctrl" }, |
| { VK_LEFT | 0x100, "Left" }, |
| { VK_LMENU, "Alt" }, |
| { VK_LSHIFT, "Shift" }, |
| { VK_LWIN | 0x100, "Win" }, |
| { VK_MENU, "Alt" }, |
| { VK_MULTIPLY, "Num *" }, |
| { VK_NEXT | 0x100, "Page Down" }, |
| { VK_NUMLOCK | 0x100, "Num Lock" }, |
| { VK_NUMPAD0, "Num 0" }, |
| { VK_NUMPAD1, "Num 1" }, |
| { VK_NUMPAD2, "Num 2" }, |
| { VK_NUMPAD3, "Num 3" }, |
| { VK_NUMPAD4, "Num 4" }, |
| { VK_NUMPAD5, "Num 5" }, |
| { VK_NUMPAD6, "Num 6" }, |
| { VK_NUMPAD7, "Num 7" }, |
| { VK_NUMPAD8, "Num 8" }, |
| { VK_NUMPAD9, "Num 9" }, |
| { VK_OEM_CLEAR, "Num Clear" }, |
| { VK_OEM_NEC_EQUAL | 0x100, "Num =" }, |
| { VK_PRIOR | 0x100, "Page Up" }, |
| { VK_RCONTROL | 0x100, "Right Ctrl" }, |
| { VK_RETURN, "Return" }, |
| { VK_RETURN | 0x100, "Num Enter" }, |
| { VK_RIGHT | 0x100, "Right" }, |
| { VK_RMENU | 0x100, "Right Alt" }, |
| { VK_RSHIFT, "Right Shift" }, |
| { VK_RWIN | 0x100, "Right Win" }, |
| { VK_SEPARATOR, "Num ," }, |
| { VK_SHIFT, "Shift" }, |
| { VK_SPACE, "Space" }, |
| { VK_SUBTRACT, "Num -" }, |
| { VK_TAB, "Tab" }, |
| { VK_UP | 0x100, "Up" }, |
| { VK_VOLUME_DOWN | 0x100, "Volume Down" }, |
| { VK_VOLUME_MUTE | 0x100, "Mute" }, |
| { VK_VOLUME_UP | 0x100, "Volume Up" }, |
| { VK_OEM_MINUS, "-" }, |
| { VK_OEM_PLUS, "=" }, |
| { VK_OEM_1, ";" }, |
| { VK_OEM_2, "/" }, |
| { VK_OEM_3, "`" }, |
| { VK_OEM_4, "[" }, |
| { VK_OEM_5, "\\" }, |
| { VK_OEM_6, "]" }, |
| { VK_OEM_7, "'" }, |
| { VK_OEM_COMMA, "," }, |
| { VK_OEM_PERIOD, "." }, |
| }; |
| |
| static const SHORT char_vkey_map[] = |
| { |
| 0x332, 0x241, 0x242, 0x003, 0x244, 0x245, 0x246, 0x247, 0x008, 0x009, |
| 0x20d, 0x24b, 0x24c, 0x00d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, |
| 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x01b, 0x2dc, 0x2dd, |
| 0x336, 0x3bd, 0x020, 0x131, 0x1de, 0x133, 0x134, 0x135, 0x137, 0x0de, |
| 0x139, 0x130, 0x138, 0x1bb, 0x0bc, 0x0bd, 0x0be, 0x0bf, 0x030, 0x031, |
| 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x1ba, 0x0ba, |
| 0x1bc, 0x0bb, 0x1be, 0x1bf, 0x132, 0x141, 0x142, 0x143, 0x144, 0x145, |
| 0x146, 0x147, 0x148, 0x149, 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, |
| 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, |
| 0x15a, 0x0db, 0x0dc, 0x0dd, 0x136, 0x1bd, 0x0c0, 0x041, 0x042, 0x043, |
| 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04a, 0x04b, 0x04c, 0x04d, |
| 0x04e, 0x04f, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, |
| 0x058, 0x059, 0x05a, 0x1db, 0x1dc, 0x1dd, 0x1c0, 0x208 |
| }; |
| |
| static UINT scancode_to_vkey( UINT scan ) |
| { |
| UINT j; |
| |
| for (j = 0; j < sizeof(vkey_to_scancode)/sizeof(vkey_to_scancode[0]); j++) |
| if (vkey_to_scancode[j] == scan) |
| return j; |
| return 0; |
| } |
| |
| static const char* vkey_to_name( UINT vkey ) |
| { |
| UINT j; |
| |
| for (j = 0; j < sizeof(vkey_names)/sizeof(vkey_names[0]); j++) |
| if (vkey_names[j].vkey == vkey) |
| return vkey_names[j].name; |
| return NULL; |
| } |
| |
| static BOOL get_async_key_state( BYTE state[256] ) |
| { |
| BOOL ret; |
| |
| SERVER_START_REQ( get_key_state ) |
| { |
| req->tid = 0; |
| req->key = -1; |
| wine_server_set_reply( req, state, 256 ); |
| ret = !wine_server_call( req ); |
| } |
| SERVER_END_REQ; |
| return ret; |
| } |
| |
| static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) |
| { |
| INPUT input; |
| |
| input.type = INPUT_KEYBOARD; |
| input.u.ki.wVk = vkey; |
| input.u.ki.wScan = scan; |
| input.u.ki.dwFlags = flags; |
| input.u.ki.time = 0; |
| input.u.ki.dwExtraInfo = 0; |
| |
| __wine_send_input( hwnd, &input ); |
| } |
| |
| /*********************************************************************** |
| * update_keyboard_lock_state |
| */ |
| void update_keyboard_lock_state( WORD vkey, UINT state ) |
| { |
| BYTE keystate[256]; |
| |
| if (!get_async_key_state( keystate )) return; |
| |
| if (!(keystate[VK_CAPITAL] & 0x01) != !(state & AMETA_CAPS_LOCK_ON) && vkey != VK_CAPITAL) |
| { |
| TRACE( "adjusting CapsLock state (%02x)\n", keystate[VK_CAPITAL] ); |
| send_keyboard_input( 0, VK_CAPITAL, 0x3a, 0 ); |
| send_keyboard_input( 0, VK_CAPITAL, 0x3a, KEYEVENTF_KEYUP ); |
| } |
| |
| if (!(keystate[VK_NUMLOCK] & 0x01) != !(state & AMETA_NUM_LOCK_ON) && (vkey & 0xff) != VK_NUMLOCK) |
| { |
| TRACE( "adjusting NumLock state (%02x)\n", keystate[VK_NUMLOCK] ); |
| send_keyboard_input( 0, VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY ); |
| send_keyboard_input( 0, VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP ); |
| } |
| |
| if (!(keystate[VK_SCROLL] & 0x01) != !(state & AMETA_SCROLL_LOCK_ON) && vkey != VK_SCROLL) |
| { |
| TRACE( "adjusting ScrollLock state (%02x)\n", keystate[VK_SCROLL] ); |
| send_keyboard_input( 0, VK_SCROLL, 0x46, 0 ); |
| send_keyboard_input( 0, VK_SCROLL, 0x46, KEYEVENTF_KEYUP ); |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * keyboard_event |
| * |
| * JNI callback, runs in the context of the Java thread. |
| */ |
| jboolean keyboard_event( JNIEnv *env, jobject obj, jint win, jint action, jint keycode, jint state ) |
| { |
| union event_data data; |
| |
| if ((unsigned int)keycode >= sizeof(keycode_to_vkey)/sizeof(keycode_to_vkey[0]) || |
| !keycode_to_vkey[keycode]) |
| { |
| p__android_log_print( ANDROID_LOG_WARN, "wine", |
| "keyboard_event: win %x code %u unmapped key, ignoring", win, keycode ); |
| return JNI_FALSE; |
| } |
| data.type = KEYBOARD_EVENT; |
| data.kbd.hwnd = LongToHandle( win ); |
| data.kbd.lock_state = state; |
| data.kbd.input.type = INPUT_KEYBOARD; |
| data.kbd.input.u.ki.wVk = keycode_to_vkey[keycode]; |
| data.kbd.input.u.ki.wScan = vkey_to_scancode[data.kbd.input.u.ki.wVk]; |
| data.kbd.input.u.ki.time = 0; |
| data.kbd.input.u.ki.dwExtraInfo = 0; |
| data.kbd.input.u.ki.dwFlags = (data.kbd.input.u.ki.wScan & 0x100) ? KEYEVENTF_EXTENDEDKEY : 0; |
| if (action == AKEY_EVENT_ACTION_UP) data.kbd.input.u.ki.dwFlags |= KEYEVENTF_KEYUP; |
| |
| p__android_log_print( ANDROID_LOG_INFO, "wine", |
| "keyboard_event: win %x code %u vkey %x scan %x meta %x", |
| win, keycode, data.kbd.input.u.ki.wVk, data.kbd.input.u.ki.wScan, state ); |
| send_event( &data ); |
| return JNI_TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * ANDROID_ToUnicodeEx |
| */ |
| INT CDECL ANDROID_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, |
| LPWSTR buf, int size, UINT flags, HKL hkl ) |
| { |
| WCHAR buffer[2]; |
| BOOL shift = state[VK_SHIFT] & 0x80; |
| BOOL ctrl = state[VK_CONTROL] & 0x80; |
| BOOL numlock = state[VK_NUMLOCK] & 0x01; |
| |
| buffer[0] = buffer[1] = 0; |
| |
| if (scan & 0x8000) return 0; /* key up */ |
| |
| /* FIXME: hardcoded layout */ |
| |
| if (!ctrl) |
| { |
| switch (virt) |
| { |
| case VK_BACK: buffer[0] = '\b'; break; |
| case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break; |
| case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break; |
| case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break; |
| case VK_OEM_4: buffer[0] = shift ? '{' : '['; break; |
| case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break; |
| case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break; |
| case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break; |
| case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break; |
| case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break; |
| case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break; |
| case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break; |
| case VK_RETURN: buffer[0] = '\r'; break; |
| case VK_SPACE: buffer[0] = ' '; break; |
| case VK_TAB: buffer[0] = '\t'; break; |
| case VK_MULTIPLY: buffer[0] = '*'; break; |
| case VK_ADD: buffer[0] = '+'; break; |
| case VK_SUBTRACT: buffer[0] = '-'; break; |
| case VK_DIVIDE: buffer[0] = '/'; break; |
| default: |
| if (virt >= '0' && virt <= '9') |
| { |
| buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt; |
| break; |
| } |
| if (virt >= 'A' && virt <= 'Z') |
| { |
| buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A'; |
| break; |
| } |
| if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift) |
| { |
| buffer[0] = '0' + virt - VK_NUMPAD0; |
| break; |
| } |
| if (virt == VK_DECIMAL && numlock && !shift) |
| { |
| buffer[0] = '.'; |
| break; |
| } |
| break; |
| } |
| } |
| else /* Control codes */ |
| { |
| if (virt >= 'A' && virt <= 'Z') |
| buffer[0] = virt - 'A' + 1; |
| else |
| { |
| switch (virt) |
| { |
| case VK_OEM_4: |
| buffer[0] = 0x1b; |
| break; |
| case VK_OEM_5: |
| buffer[0] = 0x1c; |
| break; |
| case VK_OEM_6: |
| buffer[0] = 0x1d; |
| break; |
| case VK_SUBTRACT: |
| buffer[0] = 0x1e; |
| break; |
| } |
| } |
| } |
| |
| lstrcpynW( buf, buffer, size ); |
| TRACE( "returning %d / %s\n", strlenW( buffer ), debugstr_wn(buf, strlenW( buffer ))); |
| return strlenW( buffer ); |
| } |
| |
| |
| /*********************************************************************** |
| * ANDROID_GetKeyNameText |
| */ |
| INT CDECL ANDROID_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) |
| { |
| int scancode, vkey, len; |
| const char *name; |
| char key[2]; |
| |
| scancode = (lparam >> 16) & 0x1FF; |
| vkey = scancode_to_vkey( scancode ); |
| |
| if (lparam & (1 << 25)) |
| { |
| /* Caller doesn't care about distinctions between left and |
| right keys. */ |
| switch (vkey) |
| { |
| case VK_LSHIFT: |
| case VK_RSHIFT: |
| vkey = VK_SHIFT; break; |
| case VK_LCONTROL: |
| case VK_RCONTROL: |
| vkey = VK_CONTROL; break; |
| case VK_LMENU: |
| case VK_RMENU: |
| vkey = VK_MENU; break; |
| } |
| } |
| |
| if (scancode & 0x100) vkey |= 0x100; |
| |
| if ((vkey >= 0x30 && vkey <= 0x39) || (vkey >= 0x41 && vkey <= 0x5a)) |
| { |
| key[0] = vkey; |
| if (vkey >= 0x41) |
| key[0] += 0x20; |
| key[1] = 0; |
| name = key; |
| } |
| else |
| { |
| name = vkey_to_name( vkey ); |
| } |
| |
| len = MultiByteToWideChar( CP_UTF8, 0, name, -1, buffer, size ); |
| if (len) len--; |
| |
| if (!len) |
| { |
| static const WCHAR format[] = {'K','e','y',' ','0','x','%','0','2','x',0}; |
| snprintfW( buffer, size, format, vkey ); |
| len = strlenW( buffer ); |
| } |
| |
| TRACE( "lparam 0x%08x -> %s\n", lparam, debugstr_w( buffer )); |
| return len; |
| } |
| |
| |
| /*********************************************************************** |
| * ANDROID_MapVirtualKeyEx |
| */ |
| UINT CDECL ANDROID_MapVirtualKeyEx( UINT code, UINT maptype, HKL hkl ) |
| { |
| UINT ret = 0; |
| const char *s; |
| |
| TRACE_(key)( "code=0x%x, maptype=%d, hkl %p\n", code, maptype, hkl ); |
| |
| switch (maptype) |
| { |
| case MAPVK_VK_TO_VSC_EX: |
| case MAPVK_VK_TO_VSC: |
| /* vkey to scancode */ |
| switch (code) |
| { |
| case VK_SHIFT: |
| code = VK_LSHIFT; |
| break; |
| case VK_CONTROL: |
| code = VK_LCONTROL; |
| break; |
| case VK_MENU: |
| code = VK_LMENU; |
| break; |
| } |
| if (code < sizeof(vkey_to_scancode) / sizeof(vkey_to_scancode[0])) ret = vkey_to_scancode[code]; |
| break; |
| case MAPVK_VSC_TO_VK: |
| case MAPVK_VSC_TO_VK_EX: |
| /* scancode to vkey */ |
| ret = scancode_to_vkey( code ); |
| if (maptype == MAPVK_VSC_TO_VK) |
| switch (ret) |
| { |
| case VK_LSHIFT: |
| case VK_RSHIFT: |
| ret = VK_SHIFT; break; |
| case VK_LCONTROL: |
| case VK_RCONTROL: |
| ret = VK_CONTROL; break; |
| case VK_LMENU: |
| case VK_RMENU: |
| ret = VK_MENU; break; |
| } |
| break; |
| case MAPVK_VK_TO_CHAR: |
| s = vkey_to_name( code ); |
| if (s && (strlen( s ) == 1)) |
| ret = s[0]; |
| else |
| ret = 0; |
| break; |
| default: |
| FIXME( "Unknown maptype %d\n", maptype ); |
| break; |
| } |
| TRACE_(key)( "returning 0x%04x\n", ret ); |
| return ret; |
| } |
| |
| |
| /*********************************************************************** |
| * ANDROID_GetKeyboardLayout |
| */ |
| HKL CDECL ANDROID_GetKeyboardLayout( DWORD thread_id ) |
| { |
| ULONG_PTR layout = GetUserDefaultLCID(); |
| LANGID langid; |
| |
| langid = PRIMARYLANGID(LANGIDFROMLCID( layout )); |
| if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) |
| layout = MAKELONG( layout, 0xe001 ); /* IME */ |
| else |
| layout |= layout << 16; |
| |
| FIXME( "returning %lx\n", layout ); |
| return (HKL)layout; |
| } |
| |
| |
| /*********************************************************************** |
| * ANDROID_VkKeyScanEx |
| */ |
| SHORT CDECL ANDROID_VkKeyScanEx( WCHAR ch, HKL hkl ) |
| { |
| SHORT ret = -1; |
| if (ch < sizeof(char_vkey_map) / sizeof(char_vkey_map[0])) ret = char_vkey_map[ch]; |
| TRACE_(key)( "ch %04x hkl %p -> %04x\n", ch, hkl, ret ); |
| return ret; |
| } |