From 8ea13cd3edfd16e911b32ad13d569c0af211bd58 Mon Sep 17 00:00:00 2001 From: danieru Date: Fri, 19 Apr 2013 22:52:54 -0600 Subject: [PATCH] Add KeyMap key translation layer --- CMakeLists.txt | 2 + Common/KeyMap.cpp | 285 ++++++++++++++++++++++++++++++++++++++++++++++ Common/KeyMap.h | 188 ++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+) create mode 100644 Common/KeyMap.cpp create mode 100644 Common/KeyMap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bdbc68825..ceed216b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,8 @@ add_library(Common STATIC Common/FileUtil.h Common/Hash.cpp Common/Hash.h + Common/KeyMap.cpp + Common/KeyMap.h Common/LogManager.cpp Common/LogManager.h Common/MathUtil.cpp diff --git a/Common/KeyMap.cpp b/Common/KeyMap.cpp new file mode 100644 index 000000000..854411eda --- /dev/null +++ b/Common/KeyMap.cpp @@ -0,0 +1,285 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program 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 General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include + +#include "input/input_state.h" +#include "Core/Config.h" +#include "KeyMap.h" + +using namespace KeyMap; + +/* Platform specific + * default */ +std::map *platform_keymap = NULL; + +/* Default key mapping */ +/* Ugly, yet the cleanest way + * I could find to create a + * static map. + * Still nicer than what + * I once did in C. */ +struct DefaultKeyMap { + static std::map init() + // TODO: Fix this indentation, spaces to tabs + { + std::map m; + m[KEY_x] = PAD_BUTTON_A; + m[KEY_z] = PAD_BUTTON_B; + m[KEY_s] = PAD_BUTTON_X; + m[KEY_a] = PAD_BUTTON_Y; + m[KEY_q] = PAD_BUTTON_LBUMPER; + m[KEY_w] = PAD_BUTTON_RBUMPER; + m[KEY_SPACE] = PAD_BUTTON_START; + m[KEY_ENTER] = PAD_BUTTON_SELECT; + m[KEY_ARROW_UP] = PAD_BUTTON_UP; + m[KEY_ARROW_DOWN] = PAD_BUTTON_DOWN; + m[KEY_ARROW_LEFT] = PAD_BUTTON_LEFT; + m[KEY_ARROW_RIGHT] = PAD_BUTTON_RIGHT; + m[KEY_TAB] = PAD_BUTTON_MENU; + m[KEY_BACKSPACE] = PAD_BUTTON_BACK; + m[KEY_ANALOG_FAKE_UP] = PAD_BUTTON_JOY_UP; + m[KEY_ANALOG_FAKE_DOWN] = PAD_BUTTON_JOY_DOWN; + m[KEY_ANALOG_FAKE_LEFT] = PAD_BUTTON_JOY_LEFT; + m[KEY_ANALOG_FAKE_RIGHT] = PAD_BUTTON_JOY_RIGHT; + m[KEY_CTRL_LEFT] = PAD_BUTTON_LEFT_THUMB; + m[KEY_ALT_LEFT] = PAD_BUTTON_RIGHT_THUMB; + return m; + } + static std::map KeyMap; + +}; + +std::map DefaultKeyMap::KeyMap = DefaultKeyMap::init(); + +/* Key & Button names */ +struct KeyMap_IntStrPair { + int key; + std::string name; +}; +const KeyMap_IntStrPair key_names[] = { + {KEY_a, "a"}, + {KEY_b, "B"}, + {KEY_c, "c"}, + {KEY_d, "d"}, + {KEY_e, "e"}, + {KEY_f, "f"}, + {KEY_g, "g"}, + {KEY_h, "h"}, + {KEY_i, "i"}, + {KEY_j, "j"}, + {KEY_k, "k"}, + {KEY_l, "l"}, + {KEY_m, "m"}, + {KEY_n, "n"}, + {KEY_o, "o"}, + {KEY_p, "p"}, + {KEY_q, "q"}, + {KEY_r, "r"}, + {KEY_s, "s"}, + {KEY_t, "t"}, + {KEY_u, "u"}, + {KEY_v, "v"}, + {KEY_w, "w"}, + {KEY_x, "x"}, + {KEY_y, "y"}, + {KEY_z, "z"}, + {KEY_1, "1"}, + {KEY_2, "2"}, + {KEY_3, "3"}, + {KEY_4, "4"}, + {KEY_5, "5"}, + {KEY_6, "6"}, + {KEY_7, "7"}, + {KEY_8, "8"}, + {KEY_9, "9"}, + {KEY_0, "0"}, + + {KEY_BACKSPACE, "Backspace"}, + {KEY_TAB, "Tab"}, + {KEY_ENTER, "Enter"}, + {KEY_SHIFT_LEFT, "Shift"}, + {KEY_SHIFT_RIGHT, "Shift"}, + {KEY_CTRL_LEFT, "Ctrl"}, + {KEY_CTRL_RIGHT, "Ctrl"}, + {KEY_ALT_LEFT, "Alt"}, + {KEY_ALT_RIGHT, "Alt"}, + {KEY_SPACE, "Space"}, + {KEY_SUPER, "Super"}, + {KEY_SPACE, "Space"}, + + {KEY_VOLUME_UP, "Vol Up"}, + {KEY_VOLUME_DOWN, "Vol Down"}, + {KEY_HOME, "Home"}, + {KEY_CALL_START, "Start Call"}, + {KEY_CALL_END, "End Call"}, + + {KEY_ARROW_LEFT, "Left"}, + {KEY_ARROW_UP, "Up"}, + {KEY_ARROW_RIGHT, "Right"}, + {KEY_ARROW_DOWN, "Down"}, + + {KEY_EXTRA1, "Extra1"}, + {KEY_EXTRA2, "Extra2"}, + {KEY_EXTRA3, "Extra3"}, + {KEY_EXTRA4, "Extra4"}, + {KEY_EXTRA5, "Extra5"}, + {KEY_EXTRA6, "Extra6"}, + {KEY_EXTRA7, "Extra7"}, + {KEY_EXTRA8, "Extra8"}, + {KEY_EXTRA9, "Extra9"}, + {KEY_EXTRA0, "Extra0"}, +}; +static int key_names_count = sizeof(key_names) / sizeof(key_names[0]); +static std::string unknown_key_name = "Unknown"; +const KeyMap_IntStrPair psp_button_names[] = { + {PAD_BUTTON_A, "O"}, + {PAD_BUTTON_B, "X"}, + {PAD_BUTTON_X, "[]"}, // TODO: use proper unicode symbol + {PAD_BUTTON_Y, "^"}, + {PAD_BUTTON_LBUMPER, "L"}, + {PAD_BUTTON_RBUMPER, "R"}, + {PAD_BUTTON_START, "Start"}, + {PAD_BUTTON_SELECT, "Select"}, + {PAD_BUTTON_UP, "Up"}, + {PAD_BUTTON_DOWN, "Down"}, + {PAD_BUTTON_LEFT, "Left"}, + {PAD_BUTTON_RIGHT, "Right"}, + + {PAD_BUTTON_MENU, "Menu"}, + {PAD_BUTTON_BACK, "Back"}, + + {PAD_BUTTON_JOY_UP, "Analog Up"}, + {PAD_BUTTON_JOY_DOWN, "Analog Down"}, + {PAD_BUTTON_JOY_LEFT, "Analog Left"}, + {PAD_BUTTON_JOY_RIGHT, "Analog Right"}, + + {PAD_BUTTON_LEFT_THUMB, "Left analog click"}, + {PAD_BUTTON_RIGHT_THUMB, "Right analog click"}, +}; +static int psp_button_names_count = sizeof(psp_button_names) / sizeof(psp_button_names[0]); + + +static std::string FindName(int key, const KeyMap_IntStrPair list[], int size) +{ + for (int i = 0; i < size; i++) + if (list[i].key == key) + return list[i].name; + + return unknown_key_name; +} + +static std::string KeyMap::GetKeyName(KeyMap::Key key) +{ + return FindName((int)key, key_names, key_names_count); +} + +static std::string KeyMap::GetPspButtonName(int btn) +{ + return FindName(btn, key_names, key_names_count); +} + +static bool FindKeyMapping(int key, int *map_id, int *psp_button) +{ + std::map::iterator it; + if (*map_id >= 0) { + // check user configuration + std::map user_map = g_Config.iMappingMap; + it = user_map.find(key); + if (it != user_map.end()) { + *map_id = 0; + *psp_button = it->second; + return true; + } + } + + if (*map_id >= 1 && platform_keymap != NULL) { + // check optional platform specific keymap + std::map port_map = *platform_keymap; + it = port_map.find(key); + if (it != port_map.end()) { + *map_id = 1; + *psp_button = it->second; + return true; + } + } + + if (*map_id >= 2) { + // check default keymap + const std::map default_map = DefaultKeyMap::KeyMap; + const std::map::const_iterator it = default_map.find(key); + if (it != default_map.end()) { + *map_id = 2; + *psp_button = it->second; + return true; + } + } + + *map_id = -1; + return false; +} + + + +static int KeyMap::KeyToPspButton(const KeyMap::Key key) +{ + int search_start_layer = 0; + int psp_button; + + if (FindKeyMapping((int)key, &search_start_layer, &psp_button)) + return psp_button; + + return KEYMAP_ERROR_UNKNOWN_KEY; +} + +static bool KeyMap::IsMappedKey(Key key) +{ + return KeyMap::KeyToPspButton(key) != KEYMAP_ERROR_UNKNOWN_KEY; +} + + +static std::string KeyMap::NamePspButtonFromKey(KeyMap::Key key) +{ + return KeyMap::GetPspButtonName(KeyMap::KeyToPspButton(key)); +} + +static std::string KeyMap::NameKeyFromPspButton(int btn) +{ + // We drive our iteration + // with the list of key names. + for (int i = 0; i < key_names_count; i++) { + const struct KeyMap_IntStrPair *key_name = key_names + i; + if (btn == KeyMap::KeyToPspButton((KeyMap::Key)key_name->key)) + return key_name->name; + } + + // all psp buttons are mapped from some key + // but it appears we do not have a name + // for this key. + return unknown_key_name; +} + +static int KeyMap::SetKeyMapping(KeyMap::Key key, int btn) +{ + if (KeyMap::IsMappedKey(key)) + return KEYMAP_ERROR_KEY_ALREADY_USED; + + g_Config.iMappingMap[key] = btn; +} + +// TODO: implement RegisterPlatformDefaultKeyMap() diff --git a/Common/KeyMap.h b/Common/KeyMap.h new file mode 100644 index 000000000..01e476bfd --- /dev/null +++ b/Common/KeyMap.h @@ -0,0 +1,188 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program 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 General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include + +#define KEYMAP_ERROR_KEY_ALREADY_USED -1 +#define KEYMAP_ERROR_UNKNOWN_KEY 0 + +/* KeyMap + * A translation layer for + * key assignment. Provides + * integration with Core's + * config state. + * + * Does not handle input + * state managment. + * + * Platform ports should + * map their platform's + * keys to KeyMap's keys. + * Then have KeyMap transform + * those into psp buttons. + */ +namespace KeyMap { + enum Key { + /* Lower class latin */ + KEY_q = 1, // top row + KEY_w, + KEY_e, + KEY_r, + KEY_t, + KEY_y, + KEY_u, + KEY_i, + KEY_o, + KEY_p, + + KEY_a, // mid row + KEY_s, + KEY_d, + KEY_f, + KEY_g, + KEY_h, + KEY_j, + KEY_k, + KEY_l, + + KEY_z, // low row + KEY_x, + KEY_c, + KEY_v, + KEY_b, + KEY_n, + KEY_m, + + /* Numeric */ + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + + /* Special keys */ + KEY_ARROW_LEFT, + KEY_ARROW_RIGHT, + KEY_ARROW_UP, + KEY_ARROW_DOWN, + + KEY_ANALOG_FAKE_LEFT, + KEY_ANALOG_FAKE_RIGHT, + KEY_ANALOG_FAKE_UP, + KEY_ANALOG_FAKE_DOWN, + + KEY_SPACE, + KEY_ENTER, + KEY_CTRL_LEFT, + KEY_CTRL_RIGHT, + KEY_SHIFT_LEFT, + KEY_SHIFT_RIGHT, + KEY_ALT_LEFT, + KEY_ALT_RIGHT, + KEY_BACKSPACE, + KEY_SUPER, + KEY_TAB, + + /* Mobile Keys */ + KEY_VOLUME_UP, + KEY_VOLUME_DOWN, + KEY_HOME, + KEY_CALL_START, + KEY_CALL_END, + + /* Extra keys + * Use for platform specific keys. + * Example: android's back btn */ + KEY_EXTRA1, + KEY_EXTRA2, + KEY_EXTRA3, + KEY_EXTRA4, + KEY_EXTRA5, + KEY_EXTRA6, + KEY_EXTRA7, + KEY_EXTRA8, + KEY_EXTRA9, + KEY_EXTRA0, + + // TODO: Add fastforward key + // TODO: Add any missing keys. + // Many can be found in the + // window's port's keyboard + // files. + }; + + /* Use if you need to + * display the textual + * name + * These functions are not + * fast, do not call them + * a million times. */ + static std::string GetKeyName(Key); + static std::string GetPspButtonName(int); + + /* Use if to translate + * KeyMap Keys to PSP + * buttons. + * You should have + * already translated + * your platform's keys + * to KeyMap keys. + * + * Returns KEYMAP_ERROR_UNKNOWN_KEY + * for any unmapped key */ + static int KeyToPspButton(Key); + + static bool IsMappedKey(Key); + + /* Might be usful if you want + * to provide hints to users + * upon mapping conflicts */ + static std::string NamePspButtonFromKey(Key); + + /* Use for showing the existing + * key mapping. */ + static std::string NameKeyFromPspButton(int); + + /* Configure the key mapping. + * Any configuration will + * be saved to the Core + * config. + * + * Returns KEYMAP_ERROR_KEY_ALREADY_USED + * for mapping conflicts. 0 otherwise. */ + static int SetKeyMapping(Key, int); + + /* Platform specific keymaps + * override KeyMap's defaults. + * They do not override user's + * configuration. + * A platform default keymap + * does not need to cover + * all psp buttons. + * Any buttons missing will + * fallback to KeyMap's keymap. */ + static int RegisterPlatformDefaultKeyMap(std::map *); +} +