CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/KeyMap.cpp
Views: 1401
1
// Copyright (c) 2013- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include <algorithm>
19
#include <set>
20
#include <unordered_map>
21
#include <mutex>
22
23
#include "ppsspp_config.h"
24
25
#include "Common/System/NativeApp.h"
26
#include "Common/System/System.h"
27
#include "Common/Data/Format/IniFile.h"
28
#include "Common/Input/InputState.h"
29
#include "Common/VR/PPSSPPVR.h"
30
#include "Common/Log.h"
31
#include "Common/StringUtils.h"
32
#include "Core/HLE/sceUtility.h"
33
#include "Core/HLE/sceCtrl.h" // psp keys
34
#include "Core/Config.h"
35
#include "Core/KeyMap.h"
36
#include "Core/KeyMapDefaults.h"
37
38
namespace KeyMap {
39
40
// We actually need to lock g_controllerMap since it can be modified! Crashes will probably be rare though,
41
// but I've seen one. Let's just protect it with a mutex.
42
std::recursive_mutex g_controllerMapLock;
43
KeyMapping g_controllerMap;
44
45
// Incremented on modification, so we know when to update menus.
46
int g_controllerMapGeneration = 0;
47
std::set<std::string> g_seenPads;
48
std::map<InputDeviceID, std::string> g_padNames;
49
std::set<InputDeviceID> g_seenDeviceIds;
50
51
AxisType GetAxisType(InputAxis input) {
52
switch (input) {
53
case JOYSTICK_AXIS_GAS:
54
case JOYSTICK_AXIS_BRAKE:
55
case JOYSTICK_AXIS_LTRIGGER:
56
case JOYSTICK_AXIS_RTRIGGER:
57
return AxisType::TRIGGER;
58
case JOYSTICK_AXIS_X:
59
case JOYSTICK_AXIS_Y:
60
case JOYSTICK_AXIS_Z:
61
case JOYSTICK_AXIS_RX:
62
case JOYSTICK_AXIS_RY:
63
case JOYSTICK_AXIS_RZ:
64
return AxisType::STICK;
65
default:
66
return AxisType::OTHER;
67
}
68
}
69
70
// Utility for UI navigation
71
void SingleInputMappingFromPspButton(int btn, std::vector<InputMapping> *mappings, bool ignoreMouse) {
72
std::vector<MultiInputMapping> multiMappings;
73
InputMappingsFromPspButton(btn, &multiMappings, ignoreMouse);
74
mappings->clear();
75
for (auto &mapping : multiMappings) {
76
if (!mapping.empty()) {
77
mappings->push_back(mapping.mappings[0]);
78
} else {
79
WARN_LOG(Log::Common, "Encountered empty mapping in multi-mapping for button %d", btn);
80
}
81
}
82
}
83
84
// TODO: This is such a mess...
85
void UpdateNativeMenuKeys() {
86
std::vector<InputMapping> confirmKeys, cancelKeys;
87
std::vector<InputMapping> tabLeft, tabRight;
88
std::vector<InputMapping> upKeys, downKeys, leftKeys, rightKeys;
89
std::vector<InputMapping> infoKeys;
90
91
// Mouse mapping might be problematic in UI, so let's ignore mouse for UI
92
93
int confirmKey = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE;
94
int cancelKey = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CIRCLE : CTRL_CROSS;
95
96
SingleInputMappingFromPspButton(confirmKey, &confirmKeys, true);
97
SingleInputMappingFromPspButton(cancelKey, &cancelKeys, true);
98
SingleInputMappingFromPspButton(CTRL_TRIANGLE, &infoKeys, true);
99
SingleInputMappingFromPspButton(CTRL_LTRIGGER, &tabLeft, true);
100
SingleInputMappingFromPspButton(CTRL_RTRIGGER, &tabRight, true);
101
SingleInputMappingFromPspButton(CTRL_UP, &upKeys, true);
102
SingleInputMappingFromPspButton(CTRL_DOWN, &downKeys, true);
103
SingleInputMappingFromPspButton(CTRL_LEFT, &leftKeys, true);
104
SingleInputMappingFromPspButton(CTRL_RIGHT, &rightKeys, true);
105
106
#ifdef __ANDROID__
107
// Hardcode DPAD on Android
108
upKeys.push_back(InputMapping(DEVICE_ID_ANY, NKCODE_DPAD_UP));
109
downKeys.push_back(InputMapping(DEVICE_ID_ANY, NKCODE_DPAD_DOWN));
110
leftKeys.push_back(InputMapping(DEVICE_ID_ANY, NKCODE_DPAD_LEFT));
111
rightKeys.push_back(InputMapping(DEVICE_ID_ANY, NKCODE_DPAD_RIGHT));
112
#endif
113
114
// Push several hard-coded keys before submitting to native.
115
const InputMapping hardcodedConfirmKeys[] = {
116
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_SPACE),
117
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_ENTER),
118
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_NUMPAD_ENTER),
119
InputMapping(DEVICE_ID_ANY, NKCODE_BUTTON_A),
120
InputMapping(DEVICE_ID_PAD_0, NKCODE_DPAD_CENTER), // A number of Android devices.
121
};
122
123
// If they're not already bound, add them in.
124
for (size_t i = 0; i < ARRAY_SIZE(hardcodedConfirmKeys); i++) {
125
if (std::find(confirmKeys.begin(), confirmKeys.end(), hardcodedConfirmKeys[i]) == confirmKeys.end())
126
confirmKeys.push_back(hardcodedConfirmKeys[i]);
127
}
128
129
const InputMapping hardcodedCancelKeys[] = {
130
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE),
131
InputMapping(DEVICE_ID_ANY, NKCODE_BACK),
132
InputMapping(DEVICE_ID_ANY, NKCODE_BUTTON_B),
133
InputMapping(DEVICE_ID_MOUSE, NKCODE_EXT_MOUSEBUTTON_4),
134
};
135
136
for (size_t i = 0; i < ARRAY_SIZE(hardcodedCancelKeys); i++) {
137
if (std::find(cancelKeys.begin(), cancelKeys.end(), hardcodedCancelKeys[i]) == cancelKeys.end())
138
cancelKeys.push_back(hardcodedCancelKeys[i]);
139
}
140
141
const InputMapping hardcodedInfoKeys[] = {
142
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_S),
143
InputMapping(DEVICE_ID_KEYBOARD, NKCODE_NUMPAD_ADD),
144
InputMapping(DEVICE_ID_PAD_0, NKCODE_BUTTON_Y), // Also triangle
145
};
146
147
for (size_t i = 0; i < ARRAY_SIZE(hardcodedInfoKeys); i++) {
148
if (std::find(infoKeys.begin(), infoKeys.end(), hardcodedInfoKeys[i]) == infoKeys.end())
149
infoKeys.push_back(hardcodedInfoKeys[i]);
150
}
151
152
SetDPadKeys(upKeys, downKeys, leftKeys, rightKeys);
153
SetConfirmCancelKeys(confirmKeys, cancelKeys);
154
SetTabLeftRightKeys(tabLeft, tabRight);
155
SetInfoKeys(infoKeys);
156
157
std::unordered_map<InputDeviceID, int> flipYByDeviceId;
158
for (InputDeviceID deviceId : g_seenDeviceIds) {
159
auto analogs = MappedAxesForDevice(deviceId);
160
flipYByDeviceId[deviceId] = analogs.leftY.direction;
161
}
162
SetAnalogFlipY(flipYByDeviceId);
163
}
164
165
static const KeyMap_IntStrPair key_names[] = {
166
{NKCODE_A, "A"},
167
{NKCODE_B, "B"},
168
{NKCODE_C, "C"},
169
{NKCODE_D, "D"},
170
{NKCODE_E, "E"},
171
{NKCODE_F, "F"},
172
{NKCODE_G, "G"},
173
{NKCODE_H, "H"},
174
{NKCODE_I, "I"},
175
{NKCODE_J, "J"},
176
{NKCODE_K, "K"},
177
{NKCODE_L, "L"},
178
{NKCODE_M, "M"},
179
{NKCODE_N, "N"},
180
{NKCODE_O, "O"},
181
{NKCODE_P, "P"},
182
{NKCODE_Q, "Q"},
183
{NKCODE_R, "R"},
184
{NKCODE_S, "S"},
185
{NKCODE_T, "T"},
186
{NKCODE_U, "U"},
187
{NKCODE_V, "V"},
188
{NKCODE_W, "W"},
189
{NKCODE_X, "X"},
190
{NKCODE_Y, "Y"},
191
{NKCODE_Z, "Z"},
192
193
{NKCODE_0, "0"},
194
{NKCODE_1, "1"},
195
{NKCODE_2, "2"},
196
{NKCODE_3, "3"},
197
{NKCODE_4, "4"},
198
{NKCODE_5, "5"},
199
{NKCODE_6, "6"},
200
{NKCODE_7, "7"},
201
{NKCODE_8, "8"},
202
{NKCODE_9, "9"},
203
204
{NKCODE_F1, "F1"},
205
{NKCODE_F2, "F2"},
206
{NKCODE_F3, "F3"},
207
{NKCODE_F4, "F4"},
208
{NKCODE_F5, "F5"},
209
{NKCODE_F6, "F6"},
210
{NKCODE_F7, "F7"},
211
{NKCODE_F8, "F8"},
212
{NKCODE_F9, "F9"},
213
{NKCODE_F10, "F10"},
214
{NKCODE_F11, "F11"},
215
{NKCODE_F12, "F12"},
216
217
{NKCODE_GRAVE, "`"},
218
{NKCODE_SLASH, "/"},
219
{NKCODE_BACKSLASH, "\\"},
220
{NKCODE_SEMICOLON, ";"},
221
{NKCODE_COMMA, ","},
222
{NKCODE_PERIOD, "."},
223
{NKCODE_LEFT_BRACKET, "["},
224
{NKCODE_RIGHT_BRACKET, "]"},
225
{NKCODE_APOSTROPHE, "'"},
226
{NKCODE_MINUS, "-"},
227
{NKCODE_PLUS, "+"},
228
{NKCODE_SYSRQ, "Print"},
229
{NKCODE_SCROLL_LOCK, "ScrLock"},
230
{NKCODE_BREAK, "Pause"},
231
232
{NKCODE_BACK, "Back"},
233
{NKCODE_TAB, "Tab"},
234
{NKCODE_ENTER, "Enter"},
235
{NKCODE_SHIFT_LEFT, "LShift"},
236
{NKCODE_SHIFT_RIGHT, "RShift"},
237
{NKCODE_CTRL_LEFT, "LCtrl"},
238
{NKCODE_CTRL_RIGHT, "RCtrl"},
239
{NKCODE_ALT_LEFT, "LAlt"},
240
{NKCODE_ALT_RIGHT, "RAlt"},
241
{NKCODE_SPACE, "Space"},
242
{NKCODE_WINDOW, "Windows"},
243
{NKCODE_DEL, "Backspace"},
244
{NKCODE_FORWARD_DEL, "Delete"},
245
{NKCODE_MOVE_HOME, "Home"},
246
{NKCODE_MOVE_END, "End"},
247
{NKCODE_ESCAPE, "Esc"},
248
{NKCODE_CAPS_LOCK, "CapsLock"},
249
250
{NKCODE_VOLUME_UP, "Vol +"},
251
{NKCODE_VOLUME_DOWN, "Vol -"},
252
{NKCODE_HOME, "Home"},
253
{NKCODE_INSERT, "Ins"},
254
{NKCODE_PAGE_UP, "PgUp"},
255
{NKCODE_PAGE_DOWN, "PgDn"},
256
{NKCODE_CLEAR, "Clear"}, // 5 when numlock off
257
{NKCODE_CALL, "Call"},
258
{NKCODE_ENDCALL, "End Call"},
259
260
{NKCODE_DPAD_LEFT, "Left"},
261
{NKCODE_DPAD_UP, "Up"},
262
{NKCODE_DPAD_RIGHT, "Right"},
263
{NKCODE_DPAD_DOWN, "Down"},
264
265
{NKCODE_BUTTON_L1, "L1"},
266
{NKCODE_BUTTON_L2, "L2"},
267
{NKCODE_BUTTON_R1, "R1"},
268
{NKCODE_BUTTON_R2, "R2"},
269
270
{NKCODE_BUTTON_A, "[A]"},
271
{NKCODE_BUTTON_B, "[B]"},
272
{NKCODE_BUTTON_C, "[C]"},
273
{NKCODE_BUTTON_X, "[X]"},
274
{NKCODE_BUTTON_Y, "[Y]"},
275
{NKCODE_BUTTON_Z, "[Z]"},
276
{NKCODE_BUTTON_1, "b1"},
277
{NKCODE_BUTTON_2, "b2"},
278
{NKCODE_BUTTON_3, "b3"},
279
{NKCODE_BUTTON_4, "b4"},
280
{NKCODE_BUTTON_5, "b5"},
281
{NKCODE_BUTTON_6, "b6"},
282
{NKCODE_BUTTON_7, "b7"},
283
{NKCODE_BUTTON_8, "b8"},
284
{NKCODE_BUTTON_9, "b9"},
285
{NKCODE_BUTTON_10, "b10"},
286
{NKCODE_BUTTON_11, "b11"},
287
{NKCODE_BUTTON_12, "b12"},
288
{NKCODE_BUTTON_13, "b13"},
289
{NKCODE_BUTTON_14, "b14"},
290
{NKCODE_BUTTON_15, "b15"},
291
{NKCODE_BUTTON_16, "b16"},
292
{NKCODE_BUTTON_START, "Start"},
293
{NKCODE_BUTTON_SELECT, "Select"},
294
{NKCODE_BUTTON_CIRCLE, "Circle"},
295
{NKCODE_BUTTON_CIRCLE_PS3, "Circle3"},
296
{NKCODE_BUTTON_CROSS, "Cross"},
297
{NKCODE_BUTTON_CROSS_PS3, "Cross3"},
298
{NKCODE_BUTTON_TRIANGLE, "Triangle"},
299
{NKCODE_BUTTON_SQUARE, "Square"},
300
{NKCODE_BUTTON_THUMBL, "ThumbL"},
301
{NKCODE_BUTTON_THUMBR, "ThumbR"},
302
{NKCODE_BUTTON_MODE, "Mode"},
303
304
{NKCODE_EXT_PIPE, "|"},
305
{NKCODE_NUMPAD_DIVIDE, "Num/"},
306
{NKCODE_NUMPAD_MULTIPLY, "Num*"},
307
{NKCODE_NUMPAD_ADD, "Num+"},
308
{NKCODE_NUMPAD_SUBTRACT, "Num-"},
309
{NKCODE_NUMPAD_DOT, "Num."},
310
{NKCODE_NUMPAD_COMMA, "Num,"},
311
{NKCODE_NUMPAD_ENTER, "NumEnter"},
312
{NKCODE_NUMPAD_EQUALS, "Num="},
313
{NKCODE_NUMPAD_LEFT_PAREN, "Num("},
314
{NKCODE_NUMPAD_RIGHT_PAREN, "Num)"},
315
{NKCODE_NUMPAD_0, "Num0"},
316
{NKCODE_NUMPAD_1, "Num1"},
317
{NKCODE_NUMPAD_2, "Num2"},
318
{NKCODE_NUMPAD_3, "Num3"},
319
{NKCODE_NUMPAD_4, "Num4"},
320
{NKCODE_NUMPAD_5, "Num5"},
321
{NKCODE_NUMPAD_6, "Num6"},
322
{NKCODE_NUMPAD_7, "Num7"},
323
{NKCODE_NUMPAD_8, "Num8"},
324
{NKCODE_NUMPAD_9, "Num9"},
325
326
{NKCODE_LANGUAGE_SWITCH, "Language"},
327
{NKCODE_MANNER_MODE, "Manner"},
328
{NKCODE_3D_MODE, "3D Mode"},
329
{NKCODE_CONTACTS, "Contacts"},
330
{NKCODE_CALENDAR, "Calendar"},
331
{NKCODE_MUSIC, "Music"},
332
{NKCODE_CALCULATOR, "Calc"},
333
{NKCODE_ZENKAKU_HANKAKU, "Zenkaku"},
334
{NKCODE_EISU, "Eisu"},
335
{NKCODE_MUHENKAN, "Muhenkan"},
336
{NKCODE_HENKAN, "Henkan"},
337
{NKCODE_KATAKANA_HIRAGANA, "Katakana"},
338
{NKCODE_YEN, "Yen"},
339
{NKCODE_RO, "Ro"},
340
{NKCODE_KANA, "Kana"},
341
{NKCODE_ASSIST, "Assist"},
342
343
{NKCODE_EXT_MOUSEBUTTON_1, "MB1"},
344
{NKCODE_EXT_MOUSEBUTTON_2, "MB2"},
345
{NKCODE_EXT_MOUSEBUTTON_3, "MB3"},
346
{NKCODE_EXT_MOUSEBUTTON_4, "MB4"},
347
{NKCODE_EXT_MOUSEBUTTON_5, "MB5"},
348
{NKCODE_EXT_MOUSEWHEEL_UP, "MWheelU"},
349
{NKCODE_EXT_MOUSEWHEEL_DOWN, "MWheelD"},
350
351
{NKCODE_START_QUESTION, "¿"},
352
{NKCODE_LEFTBRACE, "{"},
353
{NKCODE_RIGHTBRACE, "}"},
354
355
{NKCODE_GUIDE, "Guide"},
356
{NKCODE_INFO, "Info"},
357
};
358
359
static const KeyMap_IntStrPair axis_names[] = {
360
{JOYSTICK_AXIS_X, "X Axis"},
361
{JOYSTICK_AXIS_Y, "Y Axis"},
362
{JOYSTICK_AXIS_PRESSURE, "Pressure"},
363
{JOYSTICK_AXIS_SIZE, "Size"},
364
{JOYSTICK_AXIS_TOUCH_MAJOR, "Touch Major"},
365
{JOYSTICK_AXIS_TOUCH_MINOR, "Touch Minor"},
366
{JOYSTICK_AXIS_TOOL_MAJOR, "Tool Major"},
367
{JOYSTICK_AXIS_TOOL_MINOR, "Tool Minor"},
368
{JOYSTICK_AXIS_ORIENTATION, "Orient"},
369
{JOYSTICK_AXIS_VSCROLL, "Vert Scroll"},
370
{JOYSTICK_AXIS_HSCROLL, "Horiz Scroll"},
371
{JOYSTICK_AXIS_Z, "Z Axis"}, // Also used as second stick X on many controllers - rename?
372
{JOYSTICK_AXIS_RX, "X Rotation"},
373
{JOYSTICK_AXIS_RY, "Y Rotation"},
374
{JOYSTICK_AXIS_RZ, "Z Rotation"}, // Also used as second stick Y on many controllers - rename?
375
{JOYSTICK_AXIS_HAT_X, "X HAT"},
376
{JOYSTICK_AXIS_HAT_Y, "Y HAT"},
377
{JOYSTICK_AXIS_LTRIGGER, "TriggerL"},
378
{JOYSTICK_AXIS_RTRIGGER, "TriggerR"},
379
{JOYSTICK_AXIS_THROTTLE, "Throttle"},
380
{JOYSTICK_AXIS_RUDDER, "Rudder"},
381
{JOYSTICK_AXIS_WHEEL, "Wheel"},
382
{JOYSTICK_AXIS_GAS, "Gas"},
383
{JOYSTICK_AXIS_BRAKE, "Brake"},
384
{JOYSTICK_AXIS_DISTANCE, "Distance"},
385
{JOYSTICK_AXIS_TILT, "Tilt"},
386
{JOYSTICK_AXIS_MOUSE_REL_X, "MouseDX"},
387
{JOYSTICK_AXIS_MOUSE_REL_Y, "MouseDY"},
388
{JOYSTICK_AXIS_ACCELEROMETER_X, "AccelX"},
389
{JOYSTICK_AXIS_ACCELEROMETER_Y, "AccelY"},
390
{JOYSTICK_AXIS_ACCELEROMETER_Z, "AccelZ"},
391
};
392
393
static std::string unknown_key_name = "??";
394
395
const KeyMap_IntStrPair psp_button_names[] = {
396
{CTRL_UP, "Up"},
397
{CTRL_DOWN, "Down"},
398
{CTRL_LEFT, "Left"},
399
{CTRL_RIGHT, "Right"},
400
{CTRL_CIRCLE, "Circle"},
401
{CTRL_CROSS, "Cross"},
402
{CTRL_SQUARE, "Square"},
403
{CTRL_TRIANGLE, "Triangle"},
404
{CTRL_START, "Start"},
405
{CTRL_SELECT, "Select"},
406
{CTRL_LTRIGGER, "L"},
407
{CTRL_RTRIGGER, "R"},
408
409
{VIRTKEY_AXIS_Y_MAX, "An.Up"},
410
{VIRTKEY_AXIS_Y_MIN, "An.Down"},
411
{VIRTKEY_AXIS_X_MIN, "An.Left"},
412
{VIRTKEY_AXIS_X_MAX, "An.Right"},
413
414
{VIRTKEY_ANALOG_ROTATE_CW, "Rotate Analog (CW)"},
415
{VIRTKEY_ANALOG_ROTATE_CCW, "Rotate Analog (CCW)"},
416
{VIRTKEY_ANALOG_LIGHTLY, "Analog limiter"},
417
{VIRTKEY_RAPID_FIRE, "RapidFire"},
418
{VIRTKEY_AXIS_SWAP, "AxisSwap"},
419
420
{VIRTKEY_FASTFORWARD, "Fast-forward"},
421
{VIRTKEY_SPEED_TOGGLE, "SpeedToggle"},
422
{VIRTKEY_SPEED_CUSTOM1, "Alt speed 1"},
423
{VIRTKEY_SPEED_CUSTOM2, "Alt speed 2"},
424
{VIRTKEY_SPEED_ANALOG, "Analog speed"},
425
{VIRTKEY_PAUSE, "Pause"},
426
{VIRTKEY_RESET_EMULATION, "Reset"},
427
{VIRTKEY_FRAME_ADVANCE, "Frame Advance"},
428
#if !defined(MOBILE_DEVICE)
429
{VIRTKEY_RECORD, "Audio/Video Recording" },
430
#endif
431
{VIRTKEY_REWIND, "Rewind"},
432
{VIRTKEY_SAVE_STATE, "Save State"},
433
{VIRTKEY_LOAD_STATE, "Load State"},
434
{VIRTKEY_PREVIOUS_SLOT, "Previous Slot"},
435
{VIRTKEY_NEXT_SLOT, "Next Slot"},
436
#if !defined(MOBILE_DEVICE)
437
{VIRTKEY_TOGGLE_FULLSCREEN, "Toggle Fullscreen"},
438
#endif
439
440
{VIRTKEY_OPENCHAT, "OpenChat" },
441
442
{VIRTKEY_DEVMENU, "DevMenu"},
443
{VIRTKEY_TEXTURE_DUMP, "Texture Dumping"},
444
{VIRTKEY_TEXTURE_REPLACE, "Texture Replacement"},
445
{VIRTKEY_SCREENSHOT, "Screenshot"},
446
{VIRTKEY_MUTE_TOGGLE, "Mute toggle"},
447
448
#ifdef OPENXR
449
{VIRTKEY_VR_CAMERA_ADJUST, "VR camera adjust"},
450
{VIRTKEY_VR_CAMERA_RESET, "VR camera reset"},
451
#else
452
{VIRTKEY_SCREEN_ROTATION_VERTICAL, "Display Portrait"},
453
{VIRTKEY_SCREEN_ROTATION_VERTICAL180, "Display Portrait Reversed"},
454
{VIRTKEY_SCREEN_ROTATION_HORIZONTAL, "Display Landscape"},
455
{VIRTKEY_SCREEN_ROTATION_HORIZONTAL180, "Display Landscape Reversed"},
456
#endif
457
458
{VIRTKEY_TOGGLE_WLAN, "Toggle WLAN"},
459
{VIRTKEY_EXIT_APP, "Exit App"},
460
461
{VIRTKEY_TOGGLE_MOUSE, "Toggle mouse input"},
462
{VIRTKEY_TOGGLE_TOUCH_CONTROLS, "Toggle touch controls"},
463
464
{VIRTKEY_AXIS_RIGHT_Y_MAX, "RightAn.Up"},
465
{VIRTKEY_AXIS_RIGHT_Y_MIN, "RightAn.Down"},
466
{VIRTKEY_AXIS_RIGHT_X_MIN, "RightAn.Left"},
467
{VIRTKEY_AXIS_RIGHT_X_MAX, "RightAn.Right"},
468
469
{CTRL_HOME, "Home"},
470
{CTRL_HOLD, "Hold"},
471
{CTRL_WLAN, "Wlan"},
472
{CTRL_REMOTE_HOLD, "Remote hold"},
473
{CTRL_VOL_UP, "Vol +"},
474
{CTRL_VOL_DOWN, "Vol -"},
475
{CTRL_SCREEN, "Screen"},
476
{CTRL_NOTE, "Note"},
477
{CTRL_L2, "Dev-kit L2"},
478
{CTRL_L3, "Dev-kit L3"},
479
{CTRL_R2, "Dev-kit R2"},
480
{CTRL_R3, "Dev-kit R3"},
481
};
482
483
// key here can be other things than InputKeyCode.
484
static std::string FindName(int key, const KeyMap_IntStrPair list[], size_t size) {
485
for (size_t i = 0; i < size; i++) {
486
if (list[i].key == key)
487
return list[i].name;
488
}
489
return StringFromFormat("%02x?", key);
490
}
491
492
std::string GetKeyName(InputKeyCode keyCode) {
493
return FindName(keyCode, key_names, ARRAY_SIZE(key_names));
494
}
495
496
std::string GetKeyOrAxisName(const InputMapping &mapping) {
497
if (mapping.IsAxis()) {
498
int direction;
499
int axis = mapping.Axis(&direction);
500
std::string temp = GetAxisName(axis);
501
if (direction == 1)
502
temp += "+";
503
else if (direction == -1)
504
temp += "-";
505
return temp;
506
} else {
507
return FindName(mapping.keyCode, key_names, ARRAY_SIZE(key_names));
508
}
509
}
510
511
std::string GetAxisName(int axisId) {
512
return FindName(axisId, axis_names, ARRAY_SIZE(axis_names));
513
}
514
515
std::string GetPspButtonName(int btn) {
516
return FindName(btn, psp_button_names, ARRAY_SIZE(psp_button_names));
517
}
518
519
const char* GetPspButtonNameCharPointer(int btn) {
520
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++)
521
if (psp_button_names[i].key == btn)
522
return psp_button_names[i].name;
523
return nullptr;
524
}
525
526
const KeyMap::KeyMap_IntStrPair *GetMappableKeys(size_t *count) {
527
*count = ARRAY_SIZE(psp_button_names);
528
return psp_button_names;
529
}
530
531
bool InputMappingToPspButton(const InputMapping &mapping, std::vector<int> *pspButtons) {
532
bool found = false;
533
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
534
for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) {
535
for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) {
536
if (iter2->EqualsSingleMapping(mapping)) {
537
if (pspButtons)
538
pspButtons->push_back(iter->first);
539
found = true;
540
}
541
}
542
}
543
return found;
544
}
545
546
// This is the main workhorse of the ControlMapper.
547
bool InputMappingsFromPspButtonNoLock(int btn, std::vector<MultiInputMapping> *mappings, bool ignoreMouse) {
548
auto iter = g_controllerMap.find(btn);
549
if (iter == g_controllerMap.end()) {
550
return false;
551
}
552
bool mapped = false;
553
if (mappings) {
554
mappings->clear();
555
}
556
for (auto &iter2 : iter->second) {
557
bool ignore = ignoreMouse && iter2.HasMouse();
558
if (!ignore) {
559
mapped = true;
560
if (mappings) {
561
mappings->push_back(iter2);
562
}
563
}
564
}
565
return mapped;
566
}
567
568
bool InputMappingsFromPspButton(int btn, std::vector<MultiInputMapping> *mappings, bool ignoreMouse) {
569
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
570
return InputMappingsFromPspButtonNoLock(btn, mappings, ignoreMouse);
571
}
572
573
void LockMappings() {
574
g_controllerMapLock.lock();
575
}
576
577
void UnlockMappings() {
578
g_controllerMapLock.unlock();
579
}
580
581
bool PspButtonHasMappings(int btn) {
582
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
583
auto iter = g_controllerMap.find(btn);
584
if (iter == g_controllerMap.end()) {
585
return false;
586
}
587
return !iter->second.empty();
588
}
589
590
MappedAnalogAxes MappedAxesForDevice(InputDeviceID deviceId) {
591
// Find the axisId mapped for a specific virtual button.
592
auto findAxisId = [&](int btn) -> MappedAnalogAxis {
593
MappedAnalogAxis info{ -1 };
594
for (const auto &key : g_controllerMap[btn]) {
595
// Only consider single mappings, combos don't make much sense for these.
596
if (key.mappings.empty()) continue;
597
auto &mapping = key.mappings[0];
598
if (mapping.deviceId == deviceId) {
599
info.axisId = TranslateKeyCodeToAxis(mapping.keyCode, &info.direction);
600
return info;
601
}
602
}
603
return info;
604
};
605
606
// Find the axisId of a pair of opposing buttons.
607
auto findAxisIdPair = [&](int minBtn, int maxBtn) -> MappedAnalogAxis {
608
MappedAnalogAxis foundMin = findAxisId(minBtn);
609
MappedAnalogAxis foundMax = findAxisId(maxBtn);
610
if (foundMin.axisId == foundMax.axisId) {
611
return foundMax;
612
}
613
return MappedAnalogAxis{ -1 };
614
};
615
616
MappedAnalogAxes result;
617
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
618
result.leftX = findAxisIdPair(VIRTKEY_AXIS_X_MIN, VIRTKEY_AXIS_X_MAX);
619
result.leftY = findAxisIdPair(VIRTKEY_AXIS_Y_MIN, VIRTKEY_AXIS_Y_MAX);
620
result.rightX = findAxisIdPair(VIRTKEY_AXIS_RIGHT_X_MIN, VIRTKEY_AXIS_RIGHT_X_MAX);
621
result.rightY = findAxisIdPair(VIRTKEY_AXIS_RIGHT_Y_MIN, VIRTKEY_AXIS_RIGHT_Y_MAX);
622
return result;
623
}
624
625
void RemoveButtonMapping(int btn) {
626
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
627
for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) {
628
if (iter->first == btn) {
629
g_controllerMap.erase(iter);
630
return;
631
}
632
}
633
}
634
635
bool IsKeyMapped(InputDeviceID device, int key) {
636
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
637
for (auto &iter : g_controllerMap) {
638
for (auto &mappedKey : iter.second) {
639
if (mappedKey.mappings.contains(InputMapping(device, key))) {
640
return true;
641
}
642
}
643
}
644
return false;
645
}
646
647
bool ReplaceSingleKeyMapping(int btn, int index, const MultiInputMapping &key) {
648
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
649
// Check for duplicate
650
for (int i = 0; i < (int)g_controllerMap[btn].size(); ++i) {
651
if (i != index && g_controllerMap[btn][i] == key) {
652
g_controllerMap[btn].erase(g_controllerMap[btn].begin()+index);
653
g_controllerMapGeneration++;
654
655
UpdateNativeMenuKeys();
656
return false;
657
}
658
}
659
660
if (key.empty()) {
661
return false;
662
}
663
664
KeyMap::g_controllerMap[btn][index] = key;
665
g_controllerMapGeneration++;
666
667
for (auto &mapping : key.mappings) {
668
g_seenDeviceIds.insert(mapping.deviceId);
669
}
670
UpdateNativeMenuKeys();
671
return true;
672
}
673
674
void DeleteNthMapping(int key, int number) {
675
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
676
auto iter = g_controllerMap.find(key);
677
if (iter != g_controllerMap.end()) {
678
if (number < iter->second.size()) {
679
iter->second.erase(iter->second.begin() + number);
680
g_controllerMapGeneration++;
681
}
682
}
683
}
684
685
void SetInputMapping(int btn, const MultiInputMapping &key, bool replace) {
686
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
687
if (key.empty()) {
688
g_controllerMap.erase(btn);
689
return;
690
}
691
if (replace) {
692
RemoveButtonMapping(btn);
693
g_controllerMap[btn].clear();
694
g_controllerMap[btn].push_back(key);
695
} else {
696
for (auto iter = g_controllerMap[btn].begin(); iter != g_controllerMap[btn].end(); ++iter) {
697
if (*iter == key)
698
return;
699
}
700
g_controllerMap[btn].push_back(key);
701
}
702
g_controllerMapGeneration++;
703
704
for (auto &mapping : key.mappings) {
705
g_seenDeviceIds.insert(mapping.deviceId);
706
}
707
}
708
709
void RestoreDefault() {
710
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
711
g_controllerMap.clear();
712
g_controllerMapGeneration++;
713
714
if (IsVREnabled()) {
715
SetDefaultKeyMap(DEFAULT_MAPPING_VR_HEADSET, false);
716
return;
717
}
718
719
#if PPSSPP_PLATFORM(WINDOWS)
720
SetDefaultKeyMap(DEFAULT_MAPPING_KEYBOARD, true);
721
SetDefaultKeyMap(DEFAULT_MAPPING_XINPUT, false);
722
SetDefaultKeyMap(DEFAULT_MAPPING_PAD, false);
723
#elif PPSSPP_PLATFORM(ANDROID)
724
// Autodetect a few common (and less common) devices
725
// Note that here we check the device name, not the controller name. We don't get
726
// the controller name until a button has been pressed so can't use it to set defaults.
727
std::string name = System_GetProperty(SYSPROP_NAME);
728
if (IsNvidiaShield(name)) {
729
SetDefaultKeyMap(DEFAULT_MAPPING_SHIELD, false);
730
} else if (IsOuya(name)) {
731
SetDefaultKeyMap(DEFAULT_MAPPING_OUYA, false);
732
} else if (IsXperiaPlay(name)) {
733
SetDefaultKeyMap(DEFAULT_MAPPING_XPERIA_PLAY, false);
734
} else if (IsMOQII7S(name)) {
735
SetDefaultKeyMap(DEFAULT_MAPPING_MOQI_I7S, false);
736
} else if (IsRetroid(name)) {
737
SetDefaultKeyMap(DEFAULT_MAPPING_RETRO_STATION_CONTROLLER, false);
738
} else {
739
SetDefaultKeyMap(DEFAULT_MAPPING_ANDROID_PAD, false);
740
}
741
#elif PPSSPP_PLATFORM(IOS)
742
SetDefaultKeyMap(DEFAULT_MAPPING_IOS_PAD, false);
743
#else
744
SetDefaultKeyMap(DEFAULT_MAPPING_KEYBOARD, true);
745
SetDefaultKeyMap(DEFAULT_MAPPING_PAD, false);
746
#endif
747
}
748
749
// TODO: Make the ini format nicer.
750
void LoadFromIni(IniFile &file) {
751
RestoreDefault();
752
if (!file.HasSection("ControlMapping")) {
753
return;
754
}
755
756
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
757
758
Section *controls = file.GetOrCreateSection("ControlMapping");
759
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
760
std::string value;
761
controls->Get(psp_button_names[i].name, &value, "");
762
763
// Erase default mapping
764
g_controllerMap.erase(psp_button_names[i].key);
765
if (value.empty())
766
continue;
767
768
std::vector<std::string> mappings;
769
SplitString(value, ',', mappings);
770
771
for (size_t j = 0; j < mappings.size(); j++) {
772
MultiInputMapping input = MultiInputMapping::FromConfigString(mappings[j]);
773
if (input.empty()) {
774
continue; // eat empty mappings, however they arose, so they can't keep haunting us.
775
}
776
SetInputMapping(psp_button_names[i].key, input, false);
777
for (auto mapping : input.mappings) {
778
g_seenDeviceIds.insert(mapping.deviceId);
779
}
780
}
781
}
782
783
UpdateNativeMenuKeys();
784
}
785
786
void SaveToIni(IniFile &file) {
787
Section *controls = file.GetOrCreateSection("ControlMapping");
788
789
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
790
791
for (size_t i = 0; i < ARRAY_SIZE(psp_button_names); i++) {
792
std::vector<MultiInputMapping> keys;
793
InputMappingsFromPspButton(psp_button_names[i].key, &keys, false);
794
795
std::string value;
796
for (size_t j = 0; j < keys.size(); j++) {
797
value += keys[j].ToConfigString();
798
if (j != keys.size() - 1)
799
value += ",";
800
}
801
802
controls->Set(psp_button_names[i].name, value, "");
803
}
804
}
805
806
void ClearAllMappings() {
807
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
808
g_controllerMap.clear();
809
g_controllerMapGeneration++;
810
}
811
812
bool IsOuya(const std::string &name) {
813
return name == "OUYA:OUYA Console";
814
}
815
816
bool IsNvidiaShield(const std::string &name) {
817
return name == "NVIDIA:SHIELD";
818
}
819
820
bool IsRetroid(const std::string &name) {
821
// TODO: Not sure if there are differences between different Retroid devices.
822
// The one I have is a "Retroid Pocket 2+".
823
return startsWith(name, "Retroid:");
824
}
825
826
bool IsNvidiaShieldTV(const std::string &name) {
827
return name == "NVIDIA:SHIELD Android TV";
828
}
829
830
bool IsXperiaPlay(const std::string &name) {
831
return name == "Sony Ericsson:R800a" || name == "Sony Ericsson:R800i" || name == "Sony Ericsson:R800x" || name == "Sony Ericsson:R800at" || name == "Sony Ericsson:SO-01D" || name == "Sony Ericsson:zeus";
832
}
833
834
bool IsMOQII7S(const std::string &name) {
835
return name == "MOQI:I7S";
836
}
837
838
bool HasBuiltinController(const std::string &name) {
839
return IsOuya(name) || IsXperiaPlay(name) || IsNvidiaShield(name) || IsMOQII7S(name) || IsRetroid(name);
840
}
841
842
void NotifyPadConnected(InputDeviceID deviceId, const std::string &name) {
843
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
844
g_seenPads.insert(name);
845
g_padNames[deviceId] = name;
846
}
847
848
void AutoConfForPad(const std::string &name) {
849
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
850
g_controllerMap.clear();
851
852
INFO_LOG(Log::System, "Autoconfiguring pad for '%s'", name.c_str());
853
854
#if PPSSPP_PLATFORM(ANDROID)
855
if (name.find("Xbox") != std::string::npos) {
856
SetDefaultKeyMap(DEFAULT_MAPPING_ANDROID_XBOX, false);
857
} else if (name == "Retro Station Controller") {
858
SetDefaultKeyMap(DEFAULT_MAPPING_RETRO_STATION_CONTROLLER, false);
859
} else {
860
SetDefaultKeyMap(DEFAULT_MAPPING_ANDROID_PAD, false);
861
}
862
#else
863
#if PPSSPP_PLATFORM(WINDOWS)
864
const bool platformSupportsXinput = true;
865
#else
866
const bool platformSupportsXinput = false;
867
#endif
868
if (platformSupportsXinput && name.find("Xbox") != std::string::npos) {
869
SetDefaultKeyMap(DEFAULT_MAPPING_XINPUT, false);
870
} else {
871
SetDefaultKeyMap(DEFAULT_MAPPING_PAD, false);
872
}
873
#endif
874
875
// Add a couple of convenient keyboard mappings by default, too.
876
g_controllerMap[VIRTKEY_PAUSE].push_back(MultiInputMapping(InputMapping(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE)));
877
g_controllerMap[VIRTKEY_FASTFORWARD].push_back(MultiInputMapping(InputMapping(DEVICE_ID_KEYBOARD, NKCODE_TAB)));
878
g_controllerMapGeneration++;
879
}
880
881
const std::set<std::string> &GetSeenPads() {
882
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
883
return g_seenPads;
884
}
885
886
std::string PadName(InputDeviceID deviceId) {
887
std::lock_guard<std::recursive_mutex> guard(g_controllerMapLock);
888
auto it = g_padNames.find(deviceId);
889
if (it != g_padNames.end())
890
return it->second;
891
return "";
892
}
893
894
bool HasChanged(int &prevGeneration) {
895
if (prevGeneration != g_controllerMapGeneration) {
896
prevGeneration = g_controllerMapGeneration;
897
return true;
898
}
899
return false;
900
}
901
902
static const char * const g_vKeyNames[] = {
903
"AXIS_X_MIN",
904
"AXIS_Y_MIN",
905
"AXIS_X_MAX",
906
"AXIS_Y_MAX",
907
"RAPID_FIRE",
908
"FASTFORWARD",
909
"PAUSE",
910
"SPEED_TOGGLE",
911
"AXIS_RIGHT_X_MIN",
912
"AXIS_RIGHT_Y_MIN",
913
"AXIS_RIGHT_X_MAX",
914
"AXIS_RIGHT_Y_MAX",
915
"REWIND",
916
"SAVE_STATE",
917
"LOAD_STATE",
918
"NEXT_SLOT",
919
"TOGGLE_FULLSCREEN",
920
"ANALOG_LIGHTLY",
921
"AXIS_SWAP",
922
"DEVMENU",
923
"FRAME_ADVANCE",
924
"RECORD",
925
"SPEED_CUSTOM1",
926
"SPEED_CUSTOM2",
927
"TEXTURE_DUMP",
928
"TEXTURE_REPLACE",
929
"SCREENSHOT",
930
"MUTE_TOGGLE",
931
"OPENCHAT",
932
"ANALOG_ROTATE_CW",
933
"ANALOG_ROTATE_CCW",
934
"SCREEN_ROTATION_VERTICAL",
935
"SCREEN_ROTATION_VERTICAL180",
936
"SCREEN_ROTATION_HORIZONTAL",
937
"SCREEN_ROTATION_HORIZONTAL180",
938
"SPEED_ANALOG",
939
"VR_CAMERA_ADJUST",
940
"VR_CAMERA_RESET",
941
};
942
943
const char *GetVirtKeyName(int vkey) {
944
int index = vkey - VIRTKEY_FIRST;
945
if (index < 0 || index >= ARRAY_SIZE(g_vKeyNames)) {
946
return "N/A";
947
}
948
return g_vKeyNames[index];
949
}
950
951
MultiInputMapping MultiInputMapping::FromConfigString(std::string_view str) {
952
MultiInputMapping out;
953
std::vector<std::string_view> parts;
954
SplitString(str, ':', parts);
955
for (auto iter : parts) {
956
out.mappings.push_back(InputMapping::FromConfigString(iter));
957
}
958
return out;
959
}
960
961
std::string MultiInputMapping::ToConfigString() const {
962
std::string out;
963
for (auto iter : mappings) {
964
out += iter.ToConfigString() + ":";
965
}
966
out.pop_back(); // remove the last ':'
967
return out;
968
}
969
970
std::string MultiInputMapping::ToVisualString() const {
971
std::string out;
972
for (auto iter : mappings) {
973
out += std::string(GetDeviceName(iter.deviceId)) + "." + GetKeyOrAxisName(iter) + " + ";
974
}
975
if (!out.empty()) {
976
// remove the last ' + '
977
out.pop_back();
978
out.pop_back();
979
out.pop_back();
980
}
981
return out;
982
}
983
984
} // KeyMap
985
986