2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "AndroidKey.h"
11 #include "ServiceBroker.h"
13 #include "input/keyboard/XBMC_keysym.h"
14 #include "windowing/android/WinSystemAndroid.h"
16 #include "platform/android/peripherals/AndroidJoystickTranslator.h"
18 #include <androidjni/KeyCharacterMap.h>
25 static KeyMap keyMap
[] = {
26 { AKEYCODE_UNKNOWN
, XBMCK_LAST
},
27 { AKEYCODE_SOFT_LEFT
, XBMCK_LEFT
},
28 { AKEYCODE_SOFT_RIGHT
, XBMCK_RIGHT
},
29 { AKEYCODE_HOME
, XBMCK_HOME
},
30 { AKEYCODE_BACK
, XBMCK_BACKSPACE
},
31 { AKEYCODE_CALL
, XBMCK_LAST
},
32 { AKEYCODE_ENDCALL
, XBMCK_LAST
},
33 { AKEYCODE_0
, XBMCK_0
},
34 { AKEYCODE_1
, XBMCK_1
},
35 { AKEYCODE_2
, XBMCK_2
},
36 { AKEYCODE_3
, XBMCK_3
},
37 { AKEYCODE_4
, XBMCK_4
},
38 { AKEYCODE_5
, XBMCK_5
},
39 { AKEYCODE_6
, XBMCK_6
},
40 { AKEYCODE_7
, XBMCK_7
},
41 { AKEYCODE_8
, XBMCK_8
},
42 { AKEYCODE_9
, XBMCK_9
},
43 { AKEYCODE_STAR
, XBMCK_ASTERISK
},
44 { AKEYCODE_POUND
, XBMCK_HASH
},
45 { AKEYCODE_DPAD_UP
, XBMCK_UP
},
46 { AKEYCODE_DPAD_DOWN
, XBMCK_DOWN
},
47 { AKEYCODE_DPAD_LEFT
, XBMCK_LEFT
},
48 { AKEYCODE_DPAD_RIGHT
, XBMCK_RIGHT
},
49 { AKEYCODE_DPAD_CENTER
, XBMCK_RETURN
},
50 { AKEYCODE_VOLUME_UP
, XBMCK_LAST
},
51 { AKEYCODE_VOLUME_DOWN
, XBMCK_LAST
},
52 { AKEYCODE_POWER
, XBMCK_LAST
},
53 { AKEYCODE_CAMERA
, XBMCK_LAST
},
54 { AKEYCODE_CLEAR
, XBMCK_LAST
},
55 { AKEYCODE_A
, XBMCK_a
},
56 { AKEYCODE_B
, XBMCK_b
},
57 { AKEYCODE_C
, XBMCK_c
},
58 { AKEYCODE_D
, XBMCK_d
},
59 { AKEYCODE_E
, XBMCK_e
},
60 { AKEYCODE_F
, XBMCK_f
},
61 { AKEYCODE_G
, XBMCK_g
},
62 { AKEYCODE_H
, XBMCK_h
},
63 { AKEYCODE_I
, XBMCK_i
},
64 { AKEYCODE_J
, XBMCK_j
},
65 { AKEYCODE_K
, XBMCK_k
},
66 { AKEYCODE_L
, XBMCK_l
},
67 { AKEYCODE_M
, XBMCK_m
},
68 { AKEYCODE_N
, XBMCK_n
},
69 { AKEYCODE_O
, XBMCK_o
},
70 { AKEYCODE_P
, XBMCK_p
},
71 { AKEYCODE_Q
, XBMCK_q
},
72 { AKEYCODE_R
, XBMCK_r
},
73 { AKEYCODE_S
, XBMCK_s
},
74 { AKEYCODE_T
, XBMCK_t
},
75 { AKEYCODE_U
, XBMCK_u
},
76 { AKEYCODE_V
, XBMCK_v
},
77 { AKEYCODE_W
, XBMCK_w
},
78 { AKEYCODE_X
, XBMCK_x
},
79 { AKEYCODE_Y
, XBMCK_y
},
80 { AKEYCODE_Z
, XBMCK_z
},
81 { AKEYCODE_COMMA
, XBMCK_COMMA
},
82 { AKEYCODE_PERIOD
, XBMCK_PERIOD
},
83 { AKEYCODE_ALT_LEFT
, XBMCK_LALT
},
84 { AKEYCODE_ALT_RIGHT
, XBMCK_RALT
},
85 { AKEYCODE_SHIFT_LEFT
, XBMCK_LSHIFT
},
86 { AKEYCODE_SHIFT_RIGHT
, XBMCK_RSHIFT
},
87 { AKEYCODE_TAB
, XBMCK_TAB
},
88 { AKEYCODE_SPACE
, XBMCK_SPACE
},
89 { AKEYCODE_SYM
, XBMCK_LAST
},
90 { AKEYCODE_EXPLORER
, XBMCK_LAST
},
91 { AKEYCODE_ENVELOPE
, XBMCK_LAST
},
92 { AKEYCODE_ENTER
, XBMCK_RETURN
},
93 { AKEYCODE_DEL
, XBMCK_BACKSPACE
},
94 { AKEYCODE_GRAVE
, XBMCK_BACKQUOTE
},
95 { AKEYCODE_MINUS
, XBMCK_MINUS
},
96 { AKEYCODE_EQUALS
, XBMCK_EQUALS
},
97 { AKEYCODE_LEFT_BRACKET
, XBMCK_LEFTBRACKET
},
98 { AKEYCODE_RIGHT_BRACKET
, XBMCK_RIGHTBRACKET
},
99 { AKEYCODE_BACKSLASH
, XBMCK_BACKSLASH
},
100 { AKEYCODE_SEMICOLON
, XBMCK_SEMICOLON
},
101 { AKEYCODE_APOSTROPHE
, XBMCK_QUOTE
},
102 { AKEYCODE_SLASH
, XBMCK_SLASH
},
103 { AKEYCODE_AT
, XBMCK_AT
},
104 { AKEYCODE_NUM
, XBMCK_NUMLOCK
},
105 { AKEYCODE_HEADSETHOOK
, XBMCK_LAST
},
106 { AKEYCODE_FOCUS
, XBMCK_LAST
}, // *Camera* focus
107 { AKEYCODE_PLUS
, XBMCK_PLUS
},
108 { AKEYCODE_MENU
, XBMCK_MENU
},
109 { AKEYCODE_NOTIFICATION
, XBMCK_LAST
},
110 { AKEYCODE_MUTE
, XBMCK_LAST
},
111 { AKEYCODE_PAGE_UP
, XBMCK_PAGEUP
},
112 { AKEYCODE_PAGE_DOWN
, XBMCK_PAGEDOWN
},
113 { AKEYCODE_MOVE_HOME
, XBMCK_HOME
},
114 { AKEYCODE_MOVE_END
, XBMCK_END
},
115 { AKEYCODE_PICTSYMBOLS
, XBMCK_LAST
},
116 { AKEYCODE_SWITCH_CHARSET
, XBMCK_LAST
},
117 { AKEYCODE_BUTTON_A
, XBMCK_LAST
},
118 { AKEYCODE_BUTTON_B
, XBMCK_LAST
},
119 { AKEYCODE_BUTTON_C
, XBMCK_LAST
},
120 { AKEYCODE_BUTTON_X
, XBMCK_LAST
},
121 { AKEYCODE_BUTTON_Y
, XBMCK_LAST
},
122 { AKEYCODE_BUTTON_Z
, XBMCK_LAST
},
123 { AKEYCODE_BUTTON_L1
, XBMCK_PAGEDOWN
},
124 { AKEYCODE_BUTTON_R1
, XBMCK_PAGEUP
},
125 { AKEYCODE_BUTTON_L2
, XBMCK_LAST
},
126 { AKEYCODE_BUTTON_R2
, XBMCK_LAST
},
127 { AKEYCODE_BUTTON_THUMBL
, XBMCK_LAST
},
128 { AKEYCODE_BUTTON_THUMBR
, XBMCK_LAST
},
129 { AKEYCODE_BUTTON_START
, XBMCK_LAST
},
130 { AKEYCODE_BUTTON_SELECT
, XBMCK_LAST
},
131 { AKEYCODE_BUTTON_MODE
, XBMCK_LAST
},
132 { AKEYCODE_ESCAPE
, XBMCK_ESCAPE
},
133 { AKEYCODE_FORWARD_DEL
, XBMCK_DELETE
},
134 { AKEYCODE_CTRL_LEFT
, XBMCK_LCTRL
},
135 { AKEYCODE_CTRL_RIGHT
, XBMCK_RCTRL
},
136 { AKEYCODE_CAPS_LOCK
, XBMCK_CAPSLOCK
},
137 { AKEYCODE_SCROLL_LOCK
, XBMCK_SCROLLOCK
},
138 { AKEYCODE_INSERT
, XBMCK_INSERT
},
139 { AKEYCODE_FORWARD
, XBMCK_MEDIA_FASTFORWARD
},
140 { AKEYCODE_GUIDE
, XBMCK_GUIDE
},
141 { AKEYCODE_SETTINGS
, XBMCK_SETTINGS
},
142 { AKEYCODE_INFO
, XBMCK_INFO
},
143 { AKEYCODE_PROG_RED
, XBMCK_RED
},
144 { AKEYCODE_PROG_GREEN
, XBMCK_GREEN
},
145 { AKEYCODE_PROG_YELLOW
, XBMCK_YELLOW
},
146 { AKEYCODE_PROG_BLUE
, XBMCK_BLUE
},
147 { AKEYCODE_CHANNEL_UP
, XBMCK_PAGEUP
},
148 { AKEYCODE_CHANNEL_DOWN
, XBMCK_PAGEDOWN
},
150 { AKEYCODE_F1
, XBMCK_F1
},
151 { AKEYCODE_F2
, XBMCK_F2
},
152 { AKEYCODE_F3
, XBMCK_F3
},
153 { AKEYCODE_F4
, XBMCK_F4
},
154 { AKEYCODE_F5
, XBMCK_F5
},
155 { AKEYCODE_F6
, XBMCK_F6
},
156 { AKEYCODE_F7
, XBMCK_F7
},
157 { AKEYCODE_F8
, XBMCK_F8
},
158 { AKEYCODE_F9
, XBMCK_F9
},
159 { AKEYCODE_F10
, XBMCK_F10
},
160 { AKEYCODE_F11
, XBMCK_F11
},
161 { AKEYCODE_F12
, XBMCK_F12
},
164 static KeyMap MediakeyMap
[] = {
165 { AKEYCODE_MEDIA_PLAY_PAUSE
, XBMCK_MEDIA_PLAY_PAUSE
},
166 { AKEYCODE_MEDIA_STOP
, XBMCK_MEDIA_STOP
},
167 { AKEYCODE_MEDIA_NEXT
, XBMCK_MEDIA_NEXT_TRACK
},
168 { AKEYCODE_MEDIA_PREVIOUS
, XBMCK_MEDIA_PREV_TRACK
},
169 { AKEYCODE_MEDIA_REWIND
, XBMCK_MEDIA_REWIND
},
170 { AKEYCODE_MEDIA_FAST_FORWARD
, XBMCK_MEDIA_FASTFORWARD
},
171 { AKEYCODE_MEDIA_PLAY
, XBMCK_MEDIA_PLAY_PAUSE
},
172 { AKEYCODE_MEDIA_PAUSE
, XBMCK_MEDIA_PLAY_PAUSE
},
173 { AKEYCODE_MEDIA_RECORD
, XBMCK_RECORD
},
174 { AKEYCODE_MEDIA_EJECT
, XBMCK_EJECT
},
177 static KeyMap SearchkeyMap
[] = {
178 { AKEYCODE_SEARCH
, XBMCK_BROWSER_SEARCH
},
181 bool CAndroidKey::m_handleMediaKeys
= true;
182 bool CAndroidKey::m_handleSearchKeys
= false;
184 bool CAndroidKey::onKeyboardEvent(AInputEvent
*event
)
191 int32_t flags
= AKeyEvent_getFlags(event
);
192 int32_t state
= AKeyEvent_getMetaState(event
);
193 int32_t action
= AKeyEvent_getAction(event
);
194 int32_t repeat
= AKeyEvent_getRepeatCount(event
);
195 int32_t keycode
= AKeyEvent_getKeyCode(event
);
196 int32_t source
= AInputEvent_getSource(event
);
198 int32_t deviceId
= AInputEvent_getDeviceId(event
);
199 uint16_t unicode
= 0;
200 CJNIKeyCharacterMap map
= CJNIKeyCharacterMap::load(deviceId
);
202 unicode
= map
.get(keycode
, state
);
204 // Check if we got some special key
205 uint16_t sym
= XBMCK_UNKNOWN
;
206 for (unsigned int index
= 0; index
< sizeof(keyMap
) / sizeof(KeyMap
); index
++)
208 if (keycode
== keyMap
[index
].nativeKey
)
210 sym
= keyMap
[index
].xbmcKey
;
214 if (sym
== XBMCK_UNKNOWN
&& m_handleMediaKeys
)
216 for (unsigned int index
= 0; index
< sizeof(MediakeyMap
) / sizeof(KeyMap
); index
++)
218 if (keycode
== MediakeyMap
[index
].nativeKey
)
220 sym
= MediakeyMap
[index
].xbmcKey
;
226 if (sym
== XBMCK_UNKNOWN
&& m_handleSearchKeys
)
228 for (unsigned int index
= 0; index
< sizeof(SearchkeyMap
) / sizeof(KeyMap
); index
++)
230 if (keycode
== SearchkeyMap
[index
].nativeKey
)
232 sym
= SearchkeyMap
[index
].xbmcKey
;
238 // check if this is a key we don't want to handle
239 if (sym
== XBMCK_LAST
|| sym
== XBMCK_UNKNOWN
)
241 CXBMCApp::android_printf("CAndroidKey: key ignored (code: %d)", keycode
);
245 uint16_t modifiers
= 0;
246 if (state
& AMETA_ALT_LEFT_ON
)
247 modifiers
|= XBMCKMOD_LALT
;
248 if (state
& AMETA_ALT_RIGHT_ON
)
249 modifiers
|= XBMCKMOD_RALT
;
250 if (state
& AMETA_SHIFT_LEFT_ON
)
251 modifiers
|= XBMCKMOD_LSHIFT
;
252 if (state
& AMETA_SHIFT_RIGHT_ON
)
253 modifiers
|= XBMCKMOD_RSHIFT
;
254 if (state
& AMETA_CTRL_LEFT_ON
)
255 modifiers
|= XBMCKMOD_LCTRL
;
256 if (state
& AMETA_CTRL_RIGHT_ON
)
257 modifiers
|= XBMCKMOD_RCTRL
;
260 if (state & AMETA_SYM_ON)
261 modifiers |= 0x000?;*/
265 case AKEY_EVENT_ACTION_DOWN
:
266 CXBMCApp::android_printf("CAndroidKey: key down (dev: %d; src: %d; code: %d (%s); repeat: "
267 "%d; flags: 0x%0X; alt: %s; shift: %s; sym: %s)",
268 deviceId
, source
, keycode
,
269 PERIPHERALS::CAndroidJoystickTranslator::TranslateKeyCode(keycode
),
270 repeat
, flags
, (state
& AMETA_ALT_ON
) ? "yes" : "no",
271 (state
& AMETA_SHIFT_ON
) ? "yes" : "no",
272 (state
& AMETA_SYM_ON
) ? "yes" : "no");
273 XBMC_Key((uint8_t)keycode
, sym
, modifiers
, unicode
, false);
276 case AKEY_EVENT_ACTION_UP
:
277 CXBMCApp::android_printf("CAndroidKey: key up (dev: %d; src: %d; code: %d (%s); repeat: %d; "
278 "flags: 0x%0X; alt: %s; shift: %s; sym: %s)",
279 deviceId
, source
, keycode
,
280 PERIPHERALS::CAndroidJoystickTranslator::TranslateKeyCode(keycode
),
281 repeat
, flags
, (state
& AMETA_ALT_ON
) ? "yes" : "no",
282 (state
& AMETA_SHIFT_ON
) ? "yes" : "no",
283 (state
& AMETA_SYM_ON
) ? "yes" : "no");
284 XBMC_Key((uint8_t)keycode
, sym
, modifiers
, unicode
, true);
287 case AKEY_EVENT_ACTION_MULTIPLE
:
288 CXBMCApp::android_printf("CAndroidKey: key multiple (dev: %d; src: %d; code: %d (%s); "
289 "repeat: %d; flags: 0x%0X; alt: %s; shift: %s; sym: %s)",
290 deviceId
, source
, keycode
,
291 PERIPHERALS::CAndroidJoystickTranslator::TranslateKeyCode(keycode
),
292 repeat
, flags
, (state
& AMETA_ALT_ON
) ? "yes" : "no",
293 (state
& AMETA_SHIFT_ON
) ? "yes" : "no",
294 (state
& AMETA_SYM_ON
) ? "yes" : "no");
299 CXBMCApp::android_printf("CAndroidKey: unknown key (dev: %d; src: %d; code: %d (%s); repeat: "
300 "%d; flags: 0x%0X; alt: %s; shift: %s; sym: %s)",
301 deviceId
, source
, keycode
,
302 PERIPHERALS::CAndroidJoystickTranslator::TranslateKeyCode(keycode
),
303 repeat
, flags
, (state
& AMETA_ALT_ON
) ? "yes" : "no",
304 (state
& AMETA_SHIFT_ON
) ? "yes" : "no",
305 (state
& AMETA_SYM_ON
) ? "yes" : "no");
313 void CAndroidKey::XBMC_Key(uint8_t code
, uint16_t key
, uint16_t modifiers
, uint16_t unicode
, bool up
)
315 CWinSystemAndroid
* winSystem(dynamic_cast<CWinSystemAndroid
*>(CServiceBroker::GetWinSystem()));
319 XBMC_Event newEvent
= {};
321 unsigned char type
= up
? XBMC_KEYUP
: XBMC_KEYDOWN
;
322 newEvent
.type
= type
;
323 newEvent
.key
.keysym
.scancode
= code
;
324 newEvent
.key
.keysym
.sym
= (XBMCKey
)key
;
325 newEvent
.key
.keysym
.unicode
= unicode
;
326 newEvent
.key
.keysym
.mod
= (XBMCMod
)modifiers
;
328 //CXBMCApp::android_printf("XBMC_Key(%u, %u, 0x%04X, %d)", code, key, modifiers, up);
329 winSystem
->MessagePush(&newEvent
);