diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp index 0ad3bdcd12..907f058823 100644 --- a/Common/KeyMap.cpp +++ b/Common/KeyMap.cpp @@ -329,7 +329,35 @@ const KeyMap_IntStrPair key_names[] = { {KEYCODE_NUMPAD_9, "Num9"}, }; -static int key_names_count = sizeof(key_names) / sizeof(key_names[0]); +const KeyMap_IntStrPair axis_names[] = { + {JOYSTICK_AXIS_X, "X Axis"}, + {JOYSTICK_AXIS_Y, "Y Axis"}, + {JOYSTICK_AXIS_PRESSURE, "Pressure"}, + {JOYSTICK_AXIS_SIZE, "Size"}, + {JOYSTICK_AXIS_TOUCH_MAJOR, "Touch Major"}, + {JOYSTICK_AXIS_TOUCH_MINOR, "Touch Minor"}, + {JOYSTICK_AXIS_TOOL_MAJOR, "Tool Major"}, + {JOYSTICK_AXIS_TOOL_MINOR, "Tool Minor"}, + {JOYSTICK_AXIS_ORIENTATION, "Orient"}, + {JOYSTICK_AXIS_VSCROLL, "Vert Scroll"}, + {JOYSTICK_AXIS_HSCROLL, "Horiz Scroll"}, + {JOYSTICK_AXIS_Z, "Z Axis"}, + {JOYSTICK_AXIS_RX, "X Rotation"}, + {JOYSTICK_AXIS_RY, "Y Rotation"}, + {JOYSTICK_AXIS_RZ, "Z Rotation"}, + {JOYSTICK_AXIS_HAT_X, "X HAT"}, + {JOYSTICK_AXIS_HAT_Y, "Y HAT"}, + {JOYSTICK_AXIS_LTRIGGER, "TriggerL"}, + {JOYSTICK_AXIS_RTRIGGER, "TriggerR"}, + {JOYSTICK_AXIS_THROTTLE, "Throttle"}, + {JOYSTICK_AXIS_RUDDER, "Rudder"}, + {JOYSTICK_AXIS_WHEEL, "Wheel"}, + {JOYSTICK_AXIS_GAS, "Gas"}, + {JOYSTICK_AXIS_BRAKE, "Brake"}, + {JOYSTICK_AXIS_DISTANCE, "Distance"}, + {JOYSTICK_AXIS_TILT, "Tilt"} +}; + static std::string unknown_key_name = "??"; const KeyMap_IntStrPair psp_button_names[] = { {CTRL_CIRCLE, "O"}, @@ -356,11 +384,11 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_PAUSE, "Pause"}, }; -static int psp_button_names_count = sizeof(psp_button_names) / sizeof(psp_button_names[0]); +const int AXIS_BIND_KEYCODE_START = 4000; -static std::string FindName(int key, const KeyMap_IntStrPair list[], int size) +static std::string FindName(int key, const KeyMap_IntStrPair list[], size_t size) { - for (int i = 0; i < size; i++) + for (size_t i = 0; i < size; i++) if (list[i].key == key) return list[i].name; @@ -369,12 +397,29 @@ static std::string FindName(int key, const KeyMap_IntStrPair list[], int size) std::string GetKeyName(int keyCode) { - return FindName(keyCode, key_names, key_names_count); + return FindName(keyCode, key_names, ARRAY_SIZE(key_names)); } std::string GetPspButtonName(int btn) { - return FindName(btn, psp_button_names, psp_button_names_count); + return FindName(btn, psp_button_names, ARRAY_SIZE(psp_button_names)); +} + +int TranslateKeyCodeToAxis(int keyCode, int &direction) +{ + if (keyCode < AXIS_BIND_KEYCODE_START) + return 0; + int v = keyCode - AXIS_BIND_KEYCODE_START; + + // Even/odd for direction. + direction = v & 1 ? -1 : 1; + return v / 2; +} + +int TranslateKeyCodeFromAxis(int axisId, int direction) +{ + direction = direction < 0 ? 1 : 0; + return AXIS_BIND_KEYCODE_START + axisId * 2 + direction; } static bool FindKeyMapping(int deviceId, int key, int *psp_button) @@ -417,9 +462,34 @@ bool KeyFromPspButton(int controllerMap, int btn, int *deviceId, int *keyCode) return false; } +int AxisToPspButton(int deviceId, int axisId, int direction) +{ + int key = TranslateKeyCodeFromAxis(axisId, direction); + return KeyToPspButton(deviceId, key); +} + +bool AxisFromPspButton(int controllerMap, int btn, int *deviceId, int *axisId, int *direction) +{ + int search_start_layer = 0; + + for (auto iter = controllerMaps[controllerMap].keys.begin(); iter != controllerMaps[controllerMap].keys.end(); ++iter) { + if (iter->second == btn && iter->first.keyCode >= AXIS_BIND_KEYCODE_START) { + *deviceId = iter->first.deviceId; + *axisId = TranslateKeyCodeToAxis(iter->first.keyCode, *direction); + return true; + } + } + return false; +} + std::string NameKeyFromPspButton(int controllerMap, int btn) { int deviceId; + int axisId; + int direction; int keyCode; + if (AxisFromPspButton(controllerMap, btn, &deviceId, &axisId, &direction)) { + return GetAxisName(axisId) + (direction < 0 ? "-" : "+"); + } if (KeyFromPspButton(controllerMap, btn, &deviceId, &keyCode)) { return GetKeyName(keyCode); } @@ -428,7 +498,12 @@ std::string NameKeyFromPspButton(int controllerMap, int btn) { std::string NameDeviceFromPspButton(int controllerMap, int btn) { int deviceId; + int axisId; + int direction; int keyCode; + if (AxisFromPspButton(controllerMap, btn, &deviceId, &axisId, &direction)) { + return GetDeviceName(deviceId); + } if (KeyFromPspButton(controllerMap, btn, &deviceId, &keyCode)) { return GetDeviceName(deviceId); } @@ -446,7 +521,7 @@ std::string NamePspButtonFromKey(int deviceId, int key) } void RemoveButtonMapping(int map, int btn) { - for (auto iter = controllerMaps[map].keys.begin(); iter != controllerMaps[map].keys.end(); ++iter) { + for (auto iter = controllerMaps[map].keys.begin(); iter != controllerMaps[map].keys.end(); ++iter) { if (iter->second == btn) { controllerMaps[map].keys.erase(iter); return; @@ -460,6 +535,29 @@ void SetKeyMapping(int map, int deviceId, int key, int btn) controllerMaps[map].keys[KeyDef(deviceId, key)] = btn; } +std::string GetAxisName(int axisId) +{ + return FindName(axisId, axis_names, ARRAY_SIZE(axis_names)); +} + +bool IsMappedAxis(int deviceId, int axisId, int direction) +{ + int key = TranslateKeyCodeFromAxis(axisId, direction); + return KeyToPspButton(deviceId, key) != KEYMAP_ERROR_UNKNOWN_KEY; +} + +std::string NamePspButtonFromAxis(int deviceId, int axisId, int direction) +{ + int key = TranslateKeyCodeFromAxis(axisId, direction); + return GetPspButtonName(KeyToPspButton(deviceId, key)); +} + +void SetAxisMapping(int map, int deviceId, int axisId, int direction, int btn) +{ + int key = TranslateKeyCodeFromAxis(axisId, direction); + SetKeyMapping(map, deviceId, key, btn); +} + void RestoreDefault() { controllerMaps = DefaultKeyMap::KeyMap; } diff --git a/Common/KeyMap.h b/Common/KeyMap.h index 9c2e2a6448..1f12a5bf2c 100644 --- a/Common/KeyMap.h +++ b/Common/KeyMap.h @@ -40,6 +40,8 @@ enum { VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; +const float AXIS_BIND_THRESHOLD = 0.75f; + class KeyDef { public: KeyDef(int devId, int k) : deviceId(devId), keyCode(k) {} @@ -115,6 +117,16 @@ namespace KeyMap { // Any configuration will be saved to the Core config. void SetKeyMapping(int map, int deviceId, int keyCode, int psp_key); + std::string GetAxisName(int axisId); + int AxisToPspButton(int deviceId, int axisId, int direction); + bool AxisFromPspButton(int controllerMap, int btn, int *deviceId, int *axisId, int *direction); + bool IsMappedAxis(int deviceId, int axisId, int direction); + std::string NamePspButtonFromAxis(int deviceId, int axisId, int direction); + + // Configure an axis mapping, saves the configuration. + // Direction is negative or positive. + void SetAxisMapping(int map, int deviceId, int axisId, int direction, int btn); + void LoadFromIni(IniFile &iniFile); void SaveToIni(IniFile &iniFile); void RestoreDefault(); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 9ea5a07588..7ff2abbb8c 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -219,31 +219,52 @@ void EmuScreen::key(const KeyInput &key) { if (result == KEYMAP_ERROR_UNKNOWN_KEY) return; - if (result >= VIRTKEY_FIRST) { - int vk = result - VIRTKEY_FIRST; - if (key.flags & KEY_DOWN) { + pspKey(result, key.flags); +} + +void EmuScreen::pspKey(int pspKeyCode, int flags) { + if (pspKeyCode >= VIRTKEY_FIRST) { + int vk = pspKeyCode - VIRTKEY_FIRST; + if (flags & KEY_DOWN) { virtKeys[vk] = true; - onVKeyDown(result); + onVKeyDown(pspKeyCode); } - if (key.flags & KEY_UP) { + if (flags & KEY_UP) { virtKeys[vk] = false; - onVKeyUp(result); + onVKeyUp(pspKeyCode); } } else { - if (key.flags & KEY_DOWN) - __CtrlButtonDown(result); - if (key.flags & KEY_UP) - __CtrlButtonUp(result); + if (flags & KEY_DOWN) + __CtrlButtonDown(pspKeyCode); + if (flags & KEY_UP) + __CtrlButtonUp(pspKeyCode); } } void EmuScreen::axis(const AxisInput &axis) { - // TODO: Apply some form of axis mapping - switch (axis.axisId) { - case JOYSTICK_AXIS_X: analog_[0].x = axis.value; break; - case JOYSTICK_AXIS_Y: analog_[0].y = axis.value; break; - case JOYSTICK_AXIS_Z: analog_[1].x = axis.value; break; - case JOYSTICK_AXIS_RZ: analog_[1].y = axis.value; break; + int result = KeyMap::AxisToPspButton(axis.deviceId, axis.axisId, axis.value >= 0 ? 1 : -1); + if (result == KEYMAP_ERROR_UNKNOWN_KEY) + return; + + switch (result) { + case VIRTKEY_AXIS_X_MIN: + case VIRTKEY_AXIS_X_MAX: + analog_[0].x = axis.value; + break; + + case VIRTKEY_AXIS_Y_MIN: + case VIRTKEY_AXIS_Y_MAX: + analog_[0].y = axis.value; + break; + + // TODO: right stick. + + default: + if (axis.value >= AXIS_BIND_THRESHOLD || axis.value <= -AXIS_BIND_THRESHOLD) { + pspKey(result, KEY_DOWN); + } else { + pspKey(result, KEY_UP); + } } } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 5ba91af12e..2c3a09910d 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -40,6 +40,7 @@ public: virtual void axis(const AxisInput &axis); private: + void pspKey(int pspKeyCode, int flags); void onVKeyDown(int virtualKeyCode); void onVKeyUp(int virtualKeyCode); diff --git a/UI/MenuScreens.cpp b/UI/MenuScreens.cpp index aa1d0c9d76..1186dda7b0 100644 --- a/UI/MenuScreens.cpp +++ b/UI/MenuScreens.cpp @@ -690,6 +690,22 @@ void KeyMappingNewKeyDialog::key(const KeyInput &key) { if (key.flags & KEY_DOWN) { last_kb_deviceid = key.deviceId; last_kb_key = key.keyCode; + last_axis_id = -1; + } +} + +void KeyMappingNewKeyDialog::axis(const AxisInput &axis) { + if (axis.value > AXIS_BIND_THRESHOLD) { + last_axis_deviceid = axis.deviceId; + last_axis_id = axis.axisId; + last_axis_direction = 1; + last_kb_key = 0; + } + if (axis.value < -AXIS_BIND_THRESHOLD) { + last_axis_deviceid = axis.deviceId; + last_axis_id = axis.axisId; + last_axis_direction = -1; + last_kb_key = 0; } } @@ -1682,16 +1698,29 @@ void KeyMappingNewKeyDialog::render() { KeyScale(1.4f); KeyText(right, top, keyI18N->T("New Key")); KeyScale(2.0f); - if (last_kb_key != 0) { + if (last_axis_id != -1) { + const std::string axis_direction_name = KeyMap::GetAxisName(last_axis_id) + (last_axis_direction < 0 ? "-" : "+"); + KeyText(right, top += stride, axis_direction_name.c_str()); + KeyScale(1.4f); + KeyText(right, top + stride, GetDeviceName(last_axis_deviceid)); + bool key_used = KeyMap::IsMappedAxis(last_axis_deviceid, last_axis_id, last_axis_direction); + if (key_used) { + KeyScale(1.0f); + KeyText(left + stride, top + 2*stride, + keyI18N->T("Warning: Key is already used by")); + KeyText(left + stride, top + 3*stride, + (KeyMap::NamePspButtonFromAxis(last_axis_deviceid, last_axis_id, last_axis_direction)).c_str()); + } + } else if (last_kb_key != 0) { KeyText(right, top += stride, KeyMap::GetKeyName(last_kb_key).c_str()); KeyScale(1.4f); KeyText(right, top + stride, GetDeviceName(last_kb_deviceid)); bool key_used = KeyMap::IsMappedKey(last_kb_deviceid, last_kb_key); if (key_used) { KeyScale(1.0f); - KeyText(left + stride, top + 2*stride, - keyI18N->T("Warning: Key is already used by")); - KeyText(left + stride, top + 3*stride, + KeyText(left + stride, top + 2*stride, + keyI18N->T("Warning: Key is already used by")); + KeyText(left + stride, top + 3*stride, (KeyMap::NamePspButtonFromKey(last_kb_deviceid, last_kb_key)).c_str()); } } @@ -1702,7 +1731,10 @@ void KeyMappingNewKeyDialog::render() { // Save & cancel buttons if (UIButton(GEN_ID, Pos(10, dp_yres - 10), LARGE_BUTTON_WIDTH, 0, keyI18N->T("Save Mapping"), ALIGN_LEFT | ALIGN_BOTTOM)) { - KeyMap::SetKeyMapping(currentMap_, last_kb_deviceid, last_kb_key, pspBtn); + if (last_axis_id != -1) + KeyMap::SetAxisMapping(currentMap_, last_axis_deviceid, last_axis_id, last_axis_direction, pspBtn); + else + KeyMap::SetKeyMapping(currentMap_, last_kb_deviceid, last_kb_key, pspBtn); g_Config.Save(); screenManager()->finishDialog(this, DR_OK); } diff --git a/UI/MenuScreens.h b/UI/MenuScreens.h index fa80e040a1..4276cf7570 100644 --- a/UI/MenuScreens.h +++ b/UI/MenuScreens.h @@ -150,16 +150,22 @@ public: pspBtn = btn; last_kb_deviceid = 0; last_kb_key = 0; + last_axis_deviceid = 0; + last_axis_id = -1; currentMap_ = currentMap; } void update(InputState &input); void render(); void key(const KeyInput &key); + void axis(const AxisInput &axis); private: int pspBtn; int last_kb_deviceid; int last_kb_key; + int last_axis_deviceid; + int last_axis_id; + int last_axis_direction; int currentMap_; };