diff options
Diffstat (limited to 'backends/keymapper')
-rw-r--r-- | backends/keymapper/action.cpp | 20 | ||||
-rw-r--r-- | backends/keymapper/action.h | 58 | ||||
-rw-r--r-- | backends/keymapper/hardware-input.cpp | 273 | ||||
-rw-r--r-- | backends/keymapper/hardware-input.h | 131 | ||||
-rw-r--r-- | backends/keymapper/hardware-key.h | 136 | ||||
-rw-r--r-- | backends/keymapper/keymap.cpp | 253 | ||||
-rw-r--r-- | backends/keymapper/keymap.h | 37 | ||||
-rw-r--r-- | backends/keymapper/keymapper-defaults.h | 56 | ||||
-rw-r--r-- | backends/keymapper/keymapper.cpp | 114 | ||||
-rw-r--r-- | backends/keymapper/keymapper.h | 65 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.cpp | 170 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.h | 6 | ||||
-rw-r--r-- | backends/keymapper/types.h | 74 |
13 files changed, 798 insertions, 595 deletions
diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp index 6ee506e7c3..33f5c423b0 100644 --- a/backends/keymapper/action.cpp +++ b/backends/keymapper/action.cpp @@ -28,10 +28,8 @@ namespace Common { -Action::Action(Keymap *boss, const char *i, String des, ActionType typ, - KeyType prefKey, int pri, int flg) - : _boss(boss), description(des), type(typ), preferredKey(prefKey), - priority(pri), flags(flg), _hwKey(0) { +Action::Action(Keymap *boss, const char *i, String des) + : _boss(boss), description(des), _hwInput(0) { assert(i); assert(_boss); @@ -40,18 +38,18 @@ Action::Action(Keymap *boss, const char *i, String des, ActionType typ, _boss->addAction(this); } -void Action::mapKey(const HardwareKey *key) { - if (_hwKey) +void Action::mapInput(const HardwareInput *input) { + if (_hwInput) _boss->unregisterMapping(this); - _hwKey = key; + _hwInput = input; - if (_hwKey) - _boss->registerMapping(this, _hwKey); + if (_hwInput) + _boss->registerMapping(this, _hwInput); } -const HardwareKey *Action::getMappedKey() const { - return _hwKey; +const HardwareInput *Action::getMappedInput() const { + return _hwInput; } } // End of namespace Common diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h index b15b3aaaad..5e69ed3918 100644 --- a/backends/keymapper/action.h +++ b/backends/keymapper/action.h @@ -27,7 +27,6 @@ #ifdef ENABLE_KEYMAPPER -#include "backends/keymapper/types.h" #include "common/events.h" #include "common/func.h" #include "common/list.h" @@ -35,11 +34,17 @@ namespace Common { -struct HardwareKey; +struct HardwareInput; class Keymap; #define ACTION_ID_SIZE (4) +struct KeyActionEntry { + const KeyState ks; + const char *id; + const char *description; +}; + struct Action { /** unique id used for saving/loading to config */ char id[ACTION_ID_SIZE]; @@ -48,27 +53,26 @@ struct Action { /** Events to be sent when mapped key is pressed */ List<Event> events; - ActionType type; - KeyType preferredKey; - int priority; - int group; - int flags; private: - /** Hardware key that is mapped to this Action */ - const HardwareKey *_hwKey; + /** Hardware input that is mapped to this Action */ + const HardwareInput *_hwInput; Keymap *_boss; public: - Action(Keymap *boss, const char *id, String des = "", - ActionType typ = kGenericActionType, - KeyType prefKey = kGenericKeyType, - int pri = 0, int flg = 0 ); + Action(Keymap *boss, const char *id, String des = ""); void addEvent(const Event &evt) { events.push_back(evt); } + void addEvent(const EventType evtType) { + Event evt; + + evt.type = evtType; + events.push_back(evt); + } + void addKeyEvent(const KeyState &ks) { Event evt; @@ -78,42 +82,24 @@ public: } void addLeftClickEvent() { - Event evt; - - evt.type = EVENT_LBUTTONDOWN; - addEvent(evt); + addEvent(EVENT_LBUTTONDOWN); } void addMiddleClickEvent() { - Event evt; - - evt.type = EVENT_MBUTTONDOWN; - addEvent(evt); + addEvent(EVENT_MBUTTONDOWN); } void addRightClickEvent() { - Event evt; - - evt.type = EVENT_RBUTTONDOWN; - addEvent(evt); + addEvent(EVENT_RBUTTONDOWN); } Keymap *getParent() { return _boss; } - void mapKey(const HardwareKey *key); - const HardwareKey *getMappedKey() const; - -}; + void mapInput(const HardwareInput *input); + const HardwareInput *getMappedInput() const; -struct ActionPriorityComp : public BinaryFunction<Action, Action, bool> { - bool operator()(const Action *x, const Action *y) const { - return x->priority > y->priority; - } - bool operator()(const Action &x, const Action &y) const { - return x.priority > y.priority; - } }; } // End of namespace Common diff --git a/backends/keymapper/hardware-input.cpp b/backends/keymapper/hardware-input.cpp new file mode 100644 index 0000000000..a09f0b54fc --- /dev/null +++ b/backends/keymapper/hardware-input.cpp @@ -0,0 +1,273 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* 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; either version 2 +* of the License, or (at your option) any later version. +* +* 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 for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "backends/keymapper/hardware-input.h" + +#ifdef ENABLE_KEYMAPPER + +#include "backends/keymapper/keymapper.h" + +namespace Common { + +static const KeyTableEntry defaultKeys[] = { + {"BACKSPACE", KEYCODE_BACKSPACE, ASCII_BACKSPACE, "Backspace", false}, + {"TAB", KEYCODE_TAB, ASCII_TAB, "Tab", false}, + {"CLEAR", KEYCODE_CLEAR, 0, "Clear", false}, + {"RETURN", KEYCODE_RETURN, ASCII_RETURN, "Return", false}, + {"PAUSE", KEYCODE_PAUSE, 0, "Pause", false}, + {"ESCAPE", KEYCODE_ESCAPE, ASCII_ESCAPE, "Esc", false}, + {"SPACE", KEYCODE_SPACE, ASCII_SPACE, "Space", false}, + {"EXCLAIM", KEYCODE_EXCLAIM, '!', "!", false}, + {"QUOTEDBL", KEYCODE_QUOTEDBL, '"', "\"", false}, + {"HASH", KEYCODE_HASH, '#', "#", false}, + {"DOLLAR", KEYCODE_DOLLAR, '$', "$", false}, + {"AMPERSAND", KEYCODE_AMPERSAND, '&', "&", false}, + {"QUOTE", KEYCODE_QUOTE, '\'', "'", false}, + {"LEFTPAREN", KEYCODE_LEFTPAREN, '(', "(", false}, + {"RIGHTPAREN", KEYCODE_RIGHTPAREN, ')', ")", false}, + {"ASTERISK", KEYCODE_ASTERISK, '*', "*", false}, + {"PLUS", KEYCODE_PLUS, '+', "+", false}, + {"COMMA", KEYCODE_COMMA, ',', ",", false}, + {"MINUS", KEYCODE_MINUS, '-', "-", false}, + {"PERIOD", KEYCODE_PERIOD, '.', ".", false}, + {"SLASH", KEYCODE_SLASH, '/', "/", false}, + {"0", KEYCODE_0, '0', "0", false}, + {"1", KEYCODE_1, '1', "1", false}, + {"2", KEYCODE_2, '2', "2", false}, + {"3", KEYCODE_3, '3', "3", false}, + {"4", KEYCODE_4, '4', "4", false}, + {"5", KEYCODE_5, '5', "5", false}, + {"6", KEYCODE_6, '6', "6", false}, + {"7", KEYCODE_7, '7', "7", false}, + {"8", KEYCODE_8, '8', "8", false}, + {"9", KEYCODE_9, '9', "9", false}, + {"COLON", KEYCODE_COLON, ':', ":", false}, + {"SEMICOLON", KEYCODE_SEMICOLON, ';', ";", false}, + {"LESS", KEYCODE_LESS, '<', "<", false}, + {"EQUALS", KEYCODE_EQUALS, '=', "=", false}, + {"GREATER", KEYCODE_GREATER, '>', ">", false}, + {"QUESTION", KEYCODE_QUESTION, '?', "?", false}, + {"AT", KEYCODE_AT, '@', "@", false}, + + {"LEFTBRACKET", KEYCODE_LEFTBRACKET, '[', "[", false}, + {"BACKSLASH", KEYCODE_BACKSLASH, '\\', "\\", false}, + {"RIGHTBRACKET", KEYCODE_RIGHTBRACKET, ']', "]", false}, + {"CARET", KEYCODE_CARET, '^', "^", false}, + {"UNDERSCORE", KEYCODE_UNDERSCORE, '_', "_", false}, + {"BACKQUOTE", KEYCODE_BACKQUOTE, '`', "`", false}, + {"a", KEYCODE_a, 'a', "a", true}, + {"b", KEYCODE_b, 'b', "b", true}, + {"c", KEYCODE_c, 'c', "c", true}, + {"d", KEYCODE_d, 'd', "d", true}, + {"e", KEYCODE_e, 'e', "e", true}, + {"f", KEYCODE_f, 'f', "f", true}, + {"g", KEYCODE_g, 'g', "g", true}, + {"h", KEYCODE_h, 'h', "h", true}, + {"i", KEYCODE_i, 'i', "i", true}, + {"j", KEYCODE_j, 'j', "j", true}, + {"k", KEYCODE_k, 'k', "k", true}, + {"l", KEYCODE_l, 'l', "l", true}, + {"m", KEYCODE_m, 'm', "m", true}, + {"n", KEYCODE_n, 'n', "n", true}, + {"o", KEYCODE_o, 'o', "o", true}, + {"p", KEYCODE_p, 'p', "p", true}, + {"q", KEYCODE_q, 'q', "q", true}, + {"r", KEYCODE_r, 'r', "r", true}, + {"s", KEYCODE_s, 's', "s", true}, + {"t", KEYCODE_t, 't', "t", true}, + {"u", KEYCODE_u, 'u', "u", true}, + {"v", KEYCODE_v, 'v', "v", true}, + {"w", KEYCODE_w, 'w', "w", true}, + {"x", KEYCODE_x, 'x', "x", true}, + {"y", KEYCODE_y, 'y', "y", true}, + {"z", KEYCODE_z, 'z', "z", true}, + {"DELETE", KEYCODE_DELETE, 0, "Del", false}, + + // Numeric keypad + {"KP0", KEYCODE_KP0, 0, "KP0", false}, + {"KP1", KEYCODE_KP1, 0, "KP1", false}, + {"KP2", KEYCODE_KP2, 0, "KP2", false}, + {"KP3", KEYCODE_KP3, 0, "KP3", false}, + {"KP4", KEYCODE_KP4, 0, "KP4", false}, + {"KP5", KEYCODE_KP5, 0, "KP5", false}, + {"KP6", KEYCODE_KP6, 0, "KP6", false}, + {"KP7", KEYCODE_KP7, 0, "KP7", false}, + {"KP8", KEYCODE_KP8, 0, "KP8", false}, + {"KP9", KEYCODE_KP9, 0, "KP9", false}, + {"KP_PERIOD", KEYCODE_KP_PERIOD, 0, "KP.", false}, + {"KP_DIVIDE", KEYCODE_KP_DIVIDE, 0, "KP/", false}, + {"KP_MULTIPLY", KEYCODE_KP_MULTIPLY, 0, "KP*", false}, + {"KP_MINUS", KEYCODE_KP_MINUS, 0, "KP-", false}, + {"KP_PLUS", KEYCODE_KP_PLUS, 0, "KP+", false}, + {"KP_ENTER", KEYCODE_KP_ENTER, 0, "KP Enter", false}, + {"KP_EQUALS", KEYCODE_KP_EQUALS, 0, "KP=", false}, + + // Arrows + Home/End pad + {"UP", KEYCODE_UP, 0, "Up", false}, + {"DOWN", KEYCODE_DOWN, 0, "Down", false}, + {"RIGHT", KEYCODE_RIGHT, 0, "Right", false}, + {"LEFT", KEYCODE_LEFT, 0, "Left", false}, + {"INSERT", KEYCODE_INSERT, 0, "Insert", false}, + {"HOME", KEYCODE_HOME, 0, "Home", false}, + {"END", KEYCODE_END, 0, "End", false}, + {"PAGEUP", KEYCODE_PAGEUP, 0, "PgUp", false}, + {"PAGEDOWN", KEYCODE_PAGEDOWN, 0, "PgDn", false}, + + // Function keys + {"F1", KEYCODE_F1, ASCII_F1, "F1", false}, + {"F2", KEYCODE_F2, ASCII_F2, "F2", false}, + {"F3", KEYCODE_F3, ASCII_F3, "F3", false}, + {"F4", KEYCODE_F4, ASCII_F4, "F4", false}, + {"F5", KEYCODE_F5, ASCII_F5, "F5", false}, + {"F6", KEYCODE_F6, ASCII_F6, "F6", false}, + {"F7", KEYCODE_F7, ASCII_F7, "F7", false}, + {"F8", KEYCODE_F8, ASCII_F8, "F8", false}, + {"F9", KEYCODE_F9, ASCII_F9, "F9", false}, + {"F10", KEYCODE_F10, ASCII_F10, "F10", false}, + {"F11", KEYCODE_F11, ASCII_F11, "F11", false}, + {"F12", KEYCODE_F12, ASCII_F12, "F12", false}, + {"F13", KEYCODE_F13, 0, "F13", false}, + {"F14", KEYCODE_F14, 0, "F14", false}, + {"F15", KEYCODE_F15, 0, "F15", false}, + + // Miscellaneous function keys + {"HELP", KEYCODE_HELP, 0, "Help", false}, + {"PRINT", KEYCODE_PRINT, 0, "Print", false}, + {"SYSREQ", KEYCODE_SYSREQ, 0, "SysRq", false}, + {"BREAK", KEYCODE_BREAK, 0, "Break", false}, + {"MENU", KEYCODE_MENU, 0, "Menu", false}, + // Power Macintosh power key + {"POWER", KEYCODE_POWER, 0, "Power", false}, + // Some european keyboards + {"EURO", KEYCODE_EURO, 0, "Euro", false}, + // Atari keyboard has Undo + {"UNDO", KEYCODE_UNDO, 0, "Undo", false}, + {0, KEYCODE_INVALID, 0, 0, false} +}; + +static const ModifierTableEntry defaultModifiers[] = { + { 0, "", "", false }, + { KBD_CTRL, "C+", "Ctrl+", false }, + { KBD_ALT, "A+", "Alt+", false }, + { KBD_SHIFT, "", "", true }, + { KBD_CTRL | KBD_ALT, "C+A+", "Ctrl+Alt+", false }, + { KBD_SHIFT | KBD_CTRL, "S+C+", "Shift+Ctrl+", true }, + { KBD_SHIFT | KBD_CTRL | KBD_ALT, "C+A+", "Ctrl+Alt+", true }, + { 0, 0, 0, false } +}; + +HardwareInputSet::HardwareInputSet(bool useDefault, const KeyTableEntry *keys, const ModifierTableEntry *modifiers) { + if (useDefault) + addHardwareInputs(defaultKeys, defaultModifiers); + if (keys) + addHardwareInputs(keys, modifiers ? modifiers : defaultModifiers); +} + +HardwareInputSet::~HardwareInputSet() { + List<const HardwareInput *>::const_iterator it; + + for (it = _inputs.begin(); it != _inputs.end(); ++it) + delete *it; +} + +void HardwareInputSet::addHardwareInput(const HardwareInput *input) { + assert(input); + + debug(8, "Adding hardware input [%s][%s]", input->id.c_str(), input->description.c_str()); + + removeHardwareInput(input); + + _inputs.push_back(input); +} + +const HardwareInput *HardwareInputSet::findHardwareInput(String id) const { + List<const HardwareInput *>::const_iterator it; + + for (it = _inputs.begin(); it != _inputs.end(); ++it) { + if ((*it)->id == id) + return (*it); + } + return 0; +} + +const HardwareInput *HardwareInputSet::findHardwareInput(const KeyState& keystate) const { + List<const HardwareInput *>::const_iterator it; + + for (it = _inputs.begin(); it != _inputs.end(); ++it) { + if ((*it)->key == keystate) + return (*it); + } + return 0; +} + +void HardwareInputSet::addHardwareInputs(const KeyTableEntry keys[], const ModifierTableEntry modifiers[]) { + const KeyTableEntry *key; + const ModifierTableEntry *mod; + char fullKeyId[50]; + char fullKeyDesc[100]; + uint16 ascii; + + for (mod = modifiers; mod->id; mod++) { + for (key = keys; key->hwId; key++) { + ascii = key->ascii; + + if (mod->shiftable && key->shiftable) { + snprintf(fullKeyId, 50, "%s%c", mod->id, toupper(key->hwId[0])); + snprintf(fullKeyDesc, 100, "%s%c", mod->desc, toupper(key->desc[0])); + ascii = toupper(key->ascii); + } else if (mod->shiftable) { + snprintf(fullKeyId, 50, "S+%s%s", mod->id, key->hwId); + snprintf(fullKeyDesc, 100, "Shift+%s%s", mod->desc, key->desc); + } else { + snprintf(fullKeyId, 50, "%s%s", mod->id, key->hwId); + snprintf(fullKeyDesc, 100, "%s%s", mod->desc, key->desc); + } + + addHardwareInput(new HardwareInput(fullKeyId, KeyState(key->keycode, ascii, mod->flag), fullKeyDesc)); + } + } +} + +void HardwareInputSet::addHardwareInputs(const KeyTableEntry keys[]) { + addHardwareInputs(keys, defaultModifiers); +} + +void HardwareInputSet::removeHardwareInput(const HardwareInput *input) { + if (!input) + return; + + List<const HardwareInput *>::iterator it; + + for (it = _inputs.begin(); it != _inputs.end(); ++it) { + const HardwareInput *entry = (*it); + if (entry->id == input->id || entry->key == input->key) { + debug(7, "Removing hardware input [%s] (%s) because it matches [%s] (%s)", entry->id.c_str(), entry->description.c_str(), input->id.c_str(), input->description.c_str()); + delete entry; + _inputs.erase(it); + } + } +} + +} //namespace Common + +#endif // #ifdef ENABLE_KEYMAPPER + diff --git a/backends/keymapper/hardware-input.h b/backends/keymapper/hardware-input.h new file mode 100644 index 0000000000..9396765bbe --- /dev/null +++ b/backends/keymapper/hardware-input.h @@ -0,0 +1,131 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* 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; either version 2 +* of the License, or (at your option) any later version. +* +* 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 for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef COMMON_HARDWARE_KEY_H +#define COMMON_HARDWARE_KEY_H + +#include "common/scummsys.h" + +#ifdef ENABLE_KEYMAPPER + +#include "common/keyboard.h" +#include "common/list.h" +#include "common/str.h" +#include "common/textconsole.h" + +namespace Common { + +/** +* Describes an available hardware input +*/ +struct HardwareInput { + /** unique id used for saving/loading to config */ + String id; + + /** Human readable description */ + String description; + + /** + * The KeyState that is generated by the back-end + * when this hardware key is pressed. + */ + KeyState key; + + HardwareInput(String i, KeyState ky = KeyState(), String desc = "") + : id(i), key(ky), description(desc) { } +}; + +/** + * Entry in a static table of available non-modifier keys + */ +struct KeyTableEntry { + const char *hwId; + KeyCode keycode; + uint16 ascii; + const char *desc; + bool shiftable; +}; + +/** + * Entry in a static table of available key modifiers + */ +struct ModifierTableEntry { + byte flag; + const char *id; + const char *desc; + bool shiftable; +}; + +/** + * Simple class to encapsulate a device's set of HardwareInputs. + * Each device should instantiate this and call addHardwareInput a number of times + * in its constructor to define the device's available keys. + */ +class HardwareInputSet { +public: + + /** + * Add hardware input keys to the set out of key and modifier tables. + * @param useDefault auto-add the built-in default inputs + * @param keys table of available keys + * @param modifiers table of available modifiers + */ + HardwareInputSet(bool useDefault = false, const KeyTableEntry keys[] = 0, const ModifierTableEntry modifiers[] = 0); + + virtual ~HardwareInputSet(); + + void addHardwareInput(const HardwareInput *input); + + const HardwareInput *findHardwareInput(String id) const; + + const HardwareInput *findHardwareInput(const KeyState& keystate) const; + + const List<const HardwareInput *> &getHardwareInputs() const { return _inputs; } + + uint size() const { return _inputs.size(); } + + /** + * Add hardware inputs to the set out of key and modifier tables. + * @param keys table of available keys + * @param modifiers table of available modifiers + */ + void addHardwareInputs(const KeyTableEntry keys[], const ModifierTableEntry modifiers[]); + + /** + * Add hardware inputs to the set out of a key table. + * The default modifiers are applied to the key entries + * @param keys table of available keys + */ + void addHardwareInputs(const KeyTableEntry keys[]); + + void removeHardwareInput(const HardwareInput *input); + +private: + + List<const HardwareInput *> _inputs; +}; + +} // End of namespace Common + +#endif // #ifdef ENABLE_KEYMAPPER + +#endif // #ifndef COMMON_HARDWARE_KEY_H diff --git a/backends/keymapper/hardware-key.h b/backends/keymapper/hardware-key.h deleted file mode 100644 index 32df042525..0000000000 --- a/backends/keymapper/hardware-key.h +++ /dev/null @@ -1,136 +0,0 @@ -/* ScummVM - Graphic Adventure Engine -* -* ScummVM is the legal property of its developers, whose names -* are too numerous to list here. Please refer to the COPYRIGHT -* file distributed with this source distribution. -* -* 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; either version 2 -* of the License, or (at your option) any later version. -* -* 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 for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -*/ - -#ifndef COMMON_HARDWARE_KEY_H -#define COMMON_HARDWARE_KEY_H - -#include "common/scummsys.h" - -#ifdef ENABLE_KEYMAPPER - -#include "backends/keymapper/types.h" -#include "common/textconsole.h" - -namespace Common { - - -#define HWKEY_ID_SIZE (30) - -/** -* Describes an available hardware key -*/ -struct HardwareKey { - /** unique id used for saving/loading to config */ - char hwKeyId[HWKEY_ID_SIZE]; - - /** Human readable description */ - String description; - - /** - * The KeyState that is generated by the back-end - * when this hardware key is pressed. - */ - KeyState key; - - KeyType type; - ActionType preferredAction; - - HardwareKey(const char *i, KeyState ky = KeyState(), String desc = "", - KeyType typ = kGenericKeyType, ActionType prefAct = kGenericActionType) - : key(ky), description(desc), type(typ), preferredAction(prefAct) { - assert(i); - Common::strlcpy(hwKeyId, i, HWKEY_ID_SIZE); - } -}; - - -/** - * Simple class to encapsulate a device's set of HardwareKeys. - * Each device should instantiate this and call addHardwareKey a number of times - * in its constructor to define the device's available keys. - */ -class HardwareKeySet { -public: - - virtual ~HardwareKeySet() { - List<const HardwareKey*>::const_iterator it; - - for (it = _keys.begin(); it != _keys.end(); it++) - delete *it; - } - - void addHardwareKey(HardwareKey *key) { - checkForKey(key); - _keys.push_back(key); - } - - const HardwareKey *findHardwareKey(const char *id) const { - List<const HardwareKey*>::const_iterator it; - - for (it = _keys.begin(); it != _keys.end(); it++) { - if (strncmp((*it)->hwKeyId, id, HWKEY_ID_SIZE) == 0) - return (*it); - } - return 0; - } - - const HardwareKey *findHardwareKey(const KeyState& keystate) const { - List<const HardwareKey*>::const_iterator it; - - for (it = _keys.begin(); it != _keys.end(); it++) { - if ((*it)->key == keystate) - return (*it); - } - return 0; - } - - const List<const HardwareKey*> &getHardwareKeys() const { - return _keys; - } - - uint size() const { - return _keys.size(); - } - - -private: - - void checkForKey(HardwareKey *key) { - List<const HardwareKey*>::iterator it; - - for (it = _keys.begin(); it != _keys.end(); it++) { - if (strncmp((*it)->hwKeyId, key->hwKeyId, HWKEY_ID_SIZE) == 0) - error("Error adding HardwareKey '%s' - id of %s already in use!", key->description.c_str(), key->hwKeyId); - else if ((*it)->key == key->key) - error("Error adding HardwareKey '%s' - key already in use!", key->description.c_str()); - } - } - - List<const HardwareKey*> _keys; -}; - - -} // End of namespace Common - -#endif // #ifdef ENABLE_KEYMAPPER - -#endif // #ifndef COMMON_HARDWARE_KEY_H diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp index 1518cba693..8ea975c927 100644 --- a/backends/keymapper/keymap.cpp +++ b/backends/keymapper/keymap.cpp @@ -24,26 +24,29 @@ #ifdef ENABLE_KEYMAPPER -#include "backends/keymapper/hardware-key.h" +#include "common/system.h" + +#include "backends/keymapper/hardware-input.h" +#include "backends/keymapper/keymapper-defaults.h" #define KEYMAP_KEY_PREFIX "keymap_" namespace Common { Keymap::Keymap(const Keymap& km) : _actions(km._actions), _keymap(), _configDomain(0) { - List<Action*>::iterator it; + List<Action *>::iterator it; for (it = _actions.begin(); it != _actions.end(); ++it) { - const HardwareKey *hwKey = (*it)->getMappedKey(); + const HardwareInput *hwInput = (*it)->getMappedInput(); - if (hwKey) { - _keymap[hwKey->key] = *it; + if (hwInput) { + _keymap[hwInput->key] = *it; } } } Keymap::~Keymap() { - List<Action*>::iterator it; + List<Action *>::iterator it; for (it = _actions.begin(); it != _actions.end(); ++it) delete *it; @@ -56,24 +59,24 @@ void Keymap::addAction(Action *action) { _actions.push_back(action); } -void Keymap::registerMapping(Action *action, const HardwareKey *hwKey) { - HashMap<KeyState, Action*>::iterator it; +void Keymap::registerMapping(Action *action, const HardwareInput *hwInput) { + HashMap<KeyState, Action *>::iterator it; - it = _keymap.find(hwKey->key); + it = _keymap.find(hwInput->key); // if key is already mapped to a different action then un-map it if (it != _keymap.end() && action != it->_value) { - it->_value->mapKey(0); + it->_value->mapInput(0); } - _keymap[hwKey->key] = action; + _keymap[hwInput->key] = action; } void Keymap::unregisterMapping(Action *action) { - const HardwareKey *hwKey = action->getMappedKey(); + const HardwareInput *hwInput = action->getMappedInput(); - if (hwKey) { - _keymap.erase(hwKey->key); + if (hwInput) { + _keymap.erase(hwInput->key); } } @@ -82,7 +85,7 @@ Action *Keymap::getAction(const char *id) { } Action *Keymap::findAction(const char *id) { - List<Action*>::iterator it; + List<Action *>::iterator it; for (it = _actions.begin(); it != _actions.end(); ++it) { if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0) @@ -92,7 +95,7 @@ Action *Keymap::findAction(const char *id) { } const Action *Keymap::findAction(const char *id) const { - List<Action*>::const_iterator it; + List<Action *>::const_iterator it; for (it = _actions.begin(); it != _actions.end(); ++it) { if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0) @@ -103,7 +106,7 @@ const Action *Keymap::findAction(const char *id) const { } Action *Keymap::getMappedAction(const KeyState& ks) const { - HashMap<KeyState, Action*>::iterator it; + HashMap<KeyState, Action *>::iterator it; it = _keymap.find(ks); @@ -117,40 +120,55 @@ void Keymap::setConfigDomain(ConfigManager::Domain *dom) { _configDomain = dom; } -void Keymap::loadMappings(const HardwareKeySet *hwKeys) { +void Keymap::loadMappings(const HardwareInputSet *hwKeys) { if (!_configDomain) return; - ConfigManager::Domain::iterator it; - String prefix = KEYMAP_KEY_PREFIX + _name + "_"; + if (_actions.empty()) + return; - for (it = _configDomain->begin(); it != _configDomain->end(); ++it) { - const String& key = it->_key; + Common::KeymapperDefaultBindings *defaults = g_system->getKeymapperDefaultBindings(); - if (!key.hasPrefix(prefix.c_str())) - continue; + HashMap<String, const HardwareInput *> mappedInputs; + List<Action*>::iterator it; + String prefix = KEYMAP_KEY_PREFIX + _name + "_"; - // parse Action ID - const char *actionId = key.c_str() + prefix.size(); - Action *ua = getAction(actionId); + for (it = _actions.begin(); it != _actions.end(); ++it) { + Action* ua = *it; + String actionId(ua->id); + String confKey = prefix + actionId; + + String hwInputId = _configDomain->getVal(confKey); + + bool defaulted = false; + // fall back to the platform-specific defaults + if (hwInputId.empty() && defaults) { + hwInputId = defaults->getDefaultBinding(_name, actionId); + if (!hwInputId.empty()) + defaulted = true; + } + // there's no mapping + if (hwInputId.empty()) + continue; - if (!ua) { - warning("'%s' keymap does not contain Action with ID %s", - _name.c_str(), actionId); - _configDomain->erase(key); + const HardwareInput *hwInput = hwKeys->findHardwareInput(hwInputId.c_str()); + if (!hwInput) { + warning("HardwareInput with ID '%s' not known", hwInputId.c_str()); continue; } - const HardwareKey *hwKey = hwKeys->findHardwareKey(it->_value.c_str()); - - if (!hwKey) { - warning("HardwareKey with ID %s not known", it->_value.c_str()); - _configDomain->erase(key); - continue; + if (defaulted) { + if (mappedInputs.contains(hwInputId)) { + debug(1, "Action [%s] not falling back to hardcoded default value [%s] because the hardware input is in use", confKey.c_str(), hwInputId.c_str()); + continue; + } + warning("Action [%s] fell back to hardcoded default value [%s]", confKey.c_str(), hwInputId.c_str()); } - ua->mapKey(hwKey); + mappedInputs.setVal(hwInputId, hwInput); + // map the key + ua->mapInput(hwInput); } } @@ -158,7 +176,7 @@ void Keymap::saveMappings() { if (!_configDomain) return; - List<Action*>::const_iterator it; + List<Action *>::const_iterator it; String prefix = KEYMAP_KEY_PREFIX + _name + "_"; for (it = _actions.begin(); it != _actions.end(); ++it) { @@ -167,170 +185,29 @@ void Keymap::saveMappings() { actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen; String actId((*it)->id, (*it)->id + actIdLen); - char hwId[HWKEY_ID_SIZE+1]; - - memset(hwId, 0, HWKEY_ID_SIZE+1); + String hwId = ""; - if ((*it)->getMappedKey()) { - memcpy(hwId, (*it)->getMappedKey()->hwKeyId, HWKEY_ID_SIZE); + if ((*it)->getMappedInput()) { + hwId = (*it)->getMappedInput()->id; } _configDomain->setVal(prefix + actId, hwId); } } -bool Keymap::isComplete(const HardwareKeySet *hwKeys) { - List<Action*>::iterator it; +bool Keymap::isComplete(const HardwareInputSet *hwInputs) { + List<Action *>::iterator it; bool allMapped = true; uint numberMapped = 0; for (it = _actions.begin(); it != _actions.end(); ++it) { - if ((*it)->getMappedKey()) { - numberMapped++; + if ((*it)->getMappedInput()) { + ++numberMapped; } else { allMapped = false; } } - return allMapped || (numberMapped == hwKeys->size()); -} - -// TODO: -// - current weakness: -// - if an action finds a key with required type but a parent action with -// higher priority is using it, that key is never used -void Keymap::automaticMapping(HardwareKeySet *hwKeys) { - // Create copies of action and key lists. - List<Action*> actions(_actions); - List<const HardwareKey*> keys(hwKeys->getHardwareKeys()); - - List<Action*>::iterator actIt; - List<const HardwareKey*>::iterator keyIt, selectedKey; - - // Remove actions and keys from local lists that have already been mapped. - actIt = actions.begin(); - - while (actIt != actions.end()) { - Action *act = *actIt; - const HardwareKey *key = act->getMappedKey(); - - if (key) { - keys.remove(key); - actIt = actions.erase(actIt); - } else { - ++actIt; - } - } - - // Sort remaining actions by priority. - ActionPriorityComp priorityComp; - sort(actions.begin(), actions.end(), priorityComp); - - // First mapping pass: - // - Match if a key's preferred action type is the same as the action's - // type, or vice versa. - // - Priority is given to: - // - keys that match action types over key types. - // - keys that have not been used by parent maps. - // - If a key has been used by a parent map the new action must have a - // higher priority than the parent action. - // - As soon as the number of skipped actions equals the number of keys - // remaining we stop matching. This means that the second pass will assign keys - // to these higher priority skipped actions. - uint skipped = 0; - actIt = actions.begin(); - - while (actIt != actions.end() && skipped < keys.size()) { - selectedKey = keys.end(); - int matchRank = 0; - Action *act = *actIt; - - for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) { - if ((*keyIt)->preferredAction == act->type && act->type != kGenericActionType) { - Action *parentAct = getParentMappedAction((*keyIt)->key); - - if (!parentAct) { - selectedKey = keyIt; - break; - } else if (parentAct->priority <= act->priority && matchRank < 3) { - selectedKey = keyIt; - matchRank = 3; - } - } else if ((*keyIt)->type == act->preferredKey && act->preferredKey != kGenericKeyType && matchRank < 2) { - Action *parentAct = getParentMappedAction((*keyIt)->key); - - if (!parentAct) { - selectedKey = keyIt; - matchRank = 2; - } else if (parentAct->priority <= act->priority && matchRank < 1) { - selectedKey = keyIt; - matchRank = 1; - } - } - } - if (selectedKey != keys.end()) { - // Map action and delete action & key from local lists. - act->mapKey(*selectedKey); - keys.erase(selectedKey); - actIt = actions.erase(actIt); - } else { - // Skip action (will be mapped in next pass). - ++actIt; - ++skipped; - } - } - - // Second mapping pass: - // - Maps any remaining actions to keys - // - priority given to: - // - keys that have no parent action - // - keys whose parent action has lower priority than the new action - // - keys whose parent action has the lowest priority - // - is guaranteed to match a key if they are not all used up - for (actIt = actions.begin(); actIt != actions.end(); ++actIt) { - selectedKey = keys.end(); - - int matchRank = 0; - int lowestPriority = 0; - Action *act = *actIt; - - for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) { - Action *parentAct = getParentMappedAction((*keyIt)->key); - - if (!parentAct) { - selectedKey = keyIt; - break; - } else if (matchRank < 2) { - if (parentAct->priority <= act->priority) { - matchRank = 2; - selectedKey = keyIt; - } else if (parentAct->priority < lowestPriority || matchRank == 0) { - matchRank = 1; - lowestPriority = parentAct->priority; - selectedKey = keyIt; - } - } - } - - if (selectedKey != keys.end()) { - act->mapKey(*selectedKey); - keys.erase(selectedKey); - } else {// no match = no keys left - break; - } - } -} - -Action *Keymap::getParentMappedAction(KeyState key) { - if (_parent) { - Action *act = _parent->getMappedAction(key); - - if (act) - return act; - else - return _parent->getParentMappedAction(key); - } else { - return 0; - } + return allMapped || (numberMapped == hwInputs->size()); } } // End of namespace Common diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h index 73f2293653..4c3e89700f 100644 --- a/backends/keymapper/keymap.h +++ b/backends/keymapper/keymap.h @@ -36,8 +36,8 @@ namespace Common { -struct HardwareKey; -class HardwareKeySet; +struct HardwareInput; +class HardwareInputSet; /** * Hash function for KeyState @@ -52,7 +52,7 @@ template<> struct Hash<KeyState> class Keymap { public: - Keymap(const String& name, Keymap *parent = 0) : _name(name), _parent(parent) {} + Keymap(const String& name) : _name(name) {} Keymap(const Keymap& km); ~Keymap(); @@ -67,7 +67,7 @@ public: /** * Get the list of all the Actions contained in this Keymap */ - List<Action*>& getActions() { return _actions; } + List<Action *>& getActions() { return _actions; } /** * Find the Action that a key is mapped to @@ -80,9 +80,9 @@ public: /** * Load this keymap's mappings from the config manager. - * @param hwKeys the set to retrieve hardware key pointers from + * @param hwInputs the set to retrieve hardware input pointers from */ - void loadMappings(const HardwareKeySet *hwKeys); + void loadMappings(const HardwareInputSet *hwInputs); /** * Save this keymap's mappings to the config manager @@ -91,17 +91,13 @@ public: */ void saveMappings(); - - void automaticMapping(HardwareKeySet *hwKeys); - /** * Returns true if all UserAction's in Keymap are mapped, or, - * all HardwareKey's from the given set have been used up. + * all HardwareInputs from the given set have been used up. */ - bool isComplete(const HardwareKeySet *hwKeys); + bool isComplete(const HardwareInputSet *hwInputs); const String& getName() { return _name; } - Keymap *getParent() { return _parent; } private: friend struct Action; @@ -114,15 +110,15 @@ private: void addAction(Action *action); /** - * Registers a HardwareKey to the given Action + * Registers a HardwareInput to the given Action * @param action Action in this Keymap - * @param key pointer to HardwareKey to map + * @param key pointer to HardwareInput to map * @see Action::mapKey */ - void registerMapping(Action *action, const HardwareKey *key); + void registerMapping(Action *action, const HardwareInput *input); /** - * Unregisters a HardwareKey from the given Action (if one is mapped) + * Unregisters a HardwareInput from the given Action (if one is mapped) * @param action Action in this Keymap * @see Action::mapKey */ @@ -131,14 +127,9 @@ private: Action *findAction(const char *id); const Action *findAction(const char *id) const; - void internalMapKey(Action *action, HardwareKey *hwKey); - - Action *getParentMappedAction(KeyState key); - String _name; - Keymap *_parent; - List<Action*> _actions; - HashMap<KeyState, Action*> _keymap; + List<Action *> _actions; + HashMap<KeyState, Action *> _keymap; ConfigManager::Domain *_configDomain; }; diff --git a/backends/keymapper/keymapper-defaults.h b/backends/keymapper/keymapper-defaults.h new file mode 100644 index 0000000000..bd4afd4e3a --- /dev/null +++ b/backends/keymapper/keymapper-defaults.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* 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; either version 2 +* of the License, or (at your option) any later version. +* +* 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 for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifdef ENABLE_KEYMAPPER + +#ifndef KEYMAPPER_DEFAULTS_H +#define KEYMAPPER_DEFAULTS_H + +#include "common/scummsys.h" +#include "common/hashmap.h" +#include "common/str.h" +#include "common/hash-str.h" + +namespace Common { + +class KeymapperDefaultBindings : HashMap<String, String> { +public: + /** + * This sets a default hwInput for a given Keymap Action + * @param keymapId String representing Keymap id (Keymap.name) + * @param actionId String representing Action id (Action.id) + * @param hwInputId String representing the HardwareInput id (HardwareInput.id) + */ + void setDefaultBinding(String keymapId, String actionId, String hwInputId) { setVal(keymapId + "_" + actionId, hwInputId); } + /** + * This retrieves the assigned default hwKey for a given Keymap Action + * @param keymapId String representing Keymap id (Keymap.name) + * @param actionId String representing Action id (Action.id) + * @return String representing the HardwareInput id (HardwareInput.id) + */ + String getDefaultBinding(String keymapId, String actionId) { return getVal(keymapId + "_" + actionId); } +}; + +} //namespace Common + +#endif // #ifndef KEYMAPPER_DEFAULTS_H +#endif // #ifdef ENABLE_KEYMAPPER diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp index f5f29a2940..bda4cd47da 100644 --- a/backends/keymapper/keymapper.cpp +++ b/backends/keymapper/keymapper.cpp @@ -54,26 +54,26 @@ Keymap *Keymapper::Domain::getKeymap(const String& name) { } Keymapper::Keymapper(EventManager *evtMgr) - : _eventMan(evtMgr), _enabled(true), _hardwareKeys(0) { + : _eventMan(evtMgr), _enabled(true), _hardwareInputs(0) { ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain); _globalDomain.setConfigDomain(confDom); } Keymapper::~Keymapper() { - delete _hardwareKeys; + delete _hardwareInputs; } -void Keymapper::registerHardwareKeySet(HardwareKeySet *keys) { - if (_hardwareKeys) - error("Hardware key set already registered"); +void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) { + if (_hardwareInputs) + error("Hardware input set already registered"); - if (!keys) { - warning("No hardware keys are supplied"); - return; + if (!inputs) { + warning("No hardware input were defined, using defaults"); + inputs = new HardwareInputSet(true); } - _hardwareKeys = keys; + _hardwareInputs = inputs; } void Keymapper::addGlobalKeymap(Keymap *keymap) { @@ -95,16 +95,15 @@ void Keymapper::addGameKeymap(Keymap *keymap) { } void Keymapper::initKeymap(Domain &domain, Keymap *map) { - if (!_hardwareKeys) { - warning("No hardware keys were registered yet (%s)", map->getName().c_str()); + if (!_hardwareInputs) { + warning("No hardware inputs were registered yet (%s)", map->getName().c_str()); return; } map->setConfigDomain(domain.getConfigDomain()); - map->loadMappings(_hardwareKeys); + map->loadMappings(_hardwareInputs); - if (map->isComplete(_hardwareKeys) == false) { - map->automaticMapping(_hardwareKeys); + if (map->isComplete(_hardwareInputs) == false) { map->saveMappings(); ConfMan.flushToDisk(); } @@ -120,7 +119,7 @@ void Keymapper::cleanupGameKeymaps() { // the game specific (=deleted) ones. Stack<MapRecord> newStack; - for (int i = 0; i < _activeMaps.size(); i++) { + for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) { if (_activeMaps[i].global) newStack.push(_activeMaps[i]); } @@ -128,63 +127,87 @@ void Keymapper::cleanupGameKeymaps() { _activeMaps = newStack; } -Keymap *Keymapper::getKeymap(const String& name, bool &global) { +Keymap *Keymapper::getKeymap(const String& name, bool *globalReturn) { Keymap *keymap = _gameDomain.getKeymap(name); - global = false; + bool global = false; if (!keymap) { keymap = _globalDomain.getKeymap(name); global = true; } + if (globalReturn) + *globalReturn = global; + return keymap; } -bool Keymapper::pushKeymap(const String& name, bool inherit) { +bool Keymapper::pushKeymap(const String& name, bool transparent) { bool global; - Keymap *newMap = getKeymap(name, global); + + assert(!name.empty()); + Keymap *newMap = getKeymap(name, &global); if (!newMap) { warning("Keymap '%s' not registered", name.c_str()); return false; } - pushKeymap(newMap, inherit, global); + pushKeymap(newMap, transparent, global); return true; } -void Keymapper::pushKeymap(Keymap *newMap, bool inherit, bool global) { - MapRecord mr = {newMap, inherit, global}; +void Keymapper::pushKeymap(Keymap *newMap, bool transparent, bool global) { + MapRecord mr = {newMap, transparent, global}; _activeMaps.push(mr); } -void Keymapper::popKeymap() { - if (!_activeMaps.empty()) - _activeMaps.pop(); +void Keymapper::popKeymap(const char *name) { + if (!_activeMaps.empty()) { + if (name) { + String topKeymapName = _activeMaps.top().keymap->getName(); + if (topKeymapName.equals(name)) + _activeMaps.pop(); + else + warning("An attempt to pop wrong keymap was blocked (expected %s but was %s)", name, topKeymapName.c_str()); + } else { + _activeMaps.pop(); + } + } + } -bool Keymapper::notifyEvent(const Common::Event &ev) { +List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) { + if (source && !source->allowMapping()) { + return DefaultEventMapper::mapEvent(ev, source); + } + + List<Event> mappedEvents; + if (ev.type == Common::EVENT_KEYDOWN) - return mapKeyDown(ev.kbd); + mappedEvents = mapKeyDown(ev.kbd); else if (ev.type == Common::EVENT_KEYUP) - return mapKeyUp(ev.kbd); + mappedEvents = mapKeyUp(ev.kbd); + + if (!mappedEvents.empty()) + return mappedEvents; else - return false; + return DefaultEventMapper::mapEvent(ev, source); } -bool Keymapper::mapKeyDown(const KeyState& key) { +List<Event> Keymapper::mapKeyDown(const KeyState& key) { return mapKey(key, true); } -bool Keymapper::mapKeyUp(const KeyState& key) { +List<Event> Keymapper::mapKeyUp(const KeyState& key) { return mapKey(key, false); } -bool Keymapper::mapKey(const KeyState& key, bool keyDown) { +List<Event> Keymapper::mapKey(const KeyState& key, bool keyDown) { if (!_enabled || _activeMaps.empty()) - return false; + return List<Event>(); Action *action = 0; @@ -192,17 +215,17 @@ bool Keymapper::mapKey(const KeyState& key, bool keyDown) { // Search for key in active keymap stack for (int i = _activeMaps.size() - 1; i >= 0; --i) { MapRecord mr = _activeMaps[i]; - + debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str()); action = mr.keymap->getMappedAction(key); - if (action || mr.inherit == false) + if (action || !mr.transparent) break; } if (action) _keysDown[key] = action; } else { - HashMap<KeyState, Action*>::iterator it = _keysDown.find(key); + HashMap<KeyState, Action *>::iterator it = _keysDown.find(key); if (it != _keysDown.end()) { action = it->_value; @@ -211,11 +234,9 @@ bool Keymapper::mapKey(const KeyState& key, bool keyDown) { } if (!action) - return false; - - executeAction(action, keyDown); + return List<Event>(); - return true; + return executeAction(action, keyDown); } Action *Keymapper::getAction(const KeyState& key) { @@ -224,7 +245,8 @@ Action *Keymapper::getAction(const KeyState& key) { return action; } -void Keymapper::executeAction(const Action *action, bool keyDown) { +List<Event> Keymapper::executeAction(const Action *action, bool keyDown) { + List<Event> mappedEvents; List<Event>::const_iterator it; for (it = action->events.begin(); it != action->events.end(); ++it) { @@ -255,18 +277,22 @@ void Keymapper::executeAction(const Action *action, bool keyDown) { case EVENT_MBUTTONUP: if (keyDown) evt.type = EVENT_MBUTTONDOWN; break; + case EVENT_MAINMENU: + if (!keyDown) evt.type = EVENT_MAINMENU; + break; default: // don't deliver other events on key up if (!keyDown) continue; } evt.mouse = _eventMan->getMousePos(); - addEvent(evt); + mappedEvents.push_back(evt); } + return mappedEvents; } -const HardwareKey *Keymapper::findHardwareKey(const KeyState& key) { - return (_hardwareKeys) ? _hardwareKeys->findHardwareKey(key) : 0; +const HardwareInput *Keymapper::findHardwareInput(const KeyState& key) { + return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(key) : 0; } } // End of namespace Common diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h index fcb444aa64..daa746f379 100644 --- a/backends/keymapper/keymapper.h +++ b/backends/keymapper/keymapper.h @@ -31,17 +31,20 @@ #include "common/list.h" #include "common/hashmap.h" #include "common/stack.h" -#include "backends/keymapper/hardware-key.h" +#include "backends/keymapper/hardware-input.h" #include "backends/keymapper/keymap.h" namespace Common { -class Keymapper : public Common::EventMapper, private Common::ArtificialEventSource { +const char *const kGuiKeymapName = "gui"; +const char *const kGlobalKeymapName = "global"; + +class Keymapper : public Common::DefaultEventMapper { public: struct MapRecord { Keymap* keymap; - bool inherit; + bool transparent; bool global; }; @@ -74,18 +77,21 @@ public: Keymapper(EventManager *eventMan); ~Keymapper(); + // EventMapper interface + virtual List<Event> mapEvent(const Event &ev, EventSource *source); + /** - * Registers a HardwareKeySet with the Keymapper + * Registers a HardwareInputSet with the Keymapper * @note should only be called once (during backend initialisation) */ - void registerHardwareKeySet(HardwareKeySet *keys); + void registerHardwareInputSet(HardwareInputSet *inputs); /** - * Get a list of all registered HardwareKeys + * Get a list of all registered HardwareInputs */ - const List<const HardwareKey*> &getHardwareKeys() const { - assert(_hardwareKeys); - return _hardwareKeys->getHardwareKeys(); + const List<const HardwareInput *> &getHardwareInputs() const { + assert(_hardwareInputs); + return _hardwareInputs->getHardwareInputs(); } /** @@ -114,26 +120,25 @@ public: * @param name name of the keymap to return * @param global set to true if returned keymap is global, false if game */ - Keymap *getKeymap(const String& name, bool &global); + Keymap *getKeymap(const String& name, bool *global = 0); /** * Push a new keymap to the top of the active stack, activating * it for use. - * @param name name of the keymap to push - * @param inherit if true keymapper will iterate down the - * stack if it cannot find a key in the new map - * @return true if succesful + * @param name name of the keymap to push + * @param transparent if true keymapper will iterate down the + * stack if it cannot find a key in the new map + * @return true if succesful */ - bool pushKeymap(const String& name, bool inherit = false); + bool pushKeymap(const String& name, bool transparent = false); /** * Pop the top keymap off the active stack. + * @param name (optional) name of keymap expected to be popped + * if provided, will not pop unless name is the same + * as the top keymap */ - void popKeymap(); - - // Implementation of the EventMapper interface - bool notifyEvent(const Common::Event &ev); - bool pollEvent(Common::Event &ev) { return Common::ArtificialEventSource::pollEvent(ev); } + void popKeymap(const char *name = 0); /** * @brief Map a key press event. @@ -141,21 +146,21 @@ public: * the Action's events are pushed into the EventManager's event queue. * @param key key that was pressed * @param keyDown true for key down, false for key up - * @return true if key was mapped + * @return mapped events */ - bool mapKey(const KeyState& key, bool keyDown); + List<Event> mapKey(const KeyState& key, bool keyDown); /** * @brief Map a key down event. * @see mapKey */ - bool mapKeyDown(const KeyState& key); + List<Event> mapKeyDown(const KeyState& key); /** * @brief Map a key up event. * @see mapKey */ - bool mapKeyUp(const KeyState& key); + List<Event> mapKeyUp(const KeyState& key); /** * Enable/disable the keymapper @@ -163,9 +168,9 @@ public: void setEnabled(bool enabled) { _enabled = enabled; } /** - * Return a HardwareKey pointer for the given key state + * Return a HardwareInput pointer for the given key state */ - const HardwareKey *findHardwareKey(const KeyState& key); + const HardwareInput *findHardwareInput(const KeyState& key); Domain& getGlobalDomain() { return _globalDomain; } Domain& getGameDomain() { return _gameDomain; } @@ -178,19 +183,19 @@ private: Domain _globalDomain; Domain _gameDomain; - HardwareKeySet *_hardwareKeys; + HardwareInputSet *_hardwareInputs; - void pushKeymap(Keymap *newMap, bool inherit, bool global); + void pushKeymap(Keymap *newMap, bool transparent, bool global); Action *getAction(const KeyState& key); - void executeAction(const Action *act, bool keyDown); + List<Event> executeAction(const Action *act, bool keyDown); EventManager *_eventMan; bool _enabled; Stack<MapRecord> _activeMaps; - HashMap<KeyState, Action*> _keysDown; + HashMap<KeyState, Action *> _keysDown; }; diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp index 7f2df2f0fe..dab295219a 100644 --- a/backends/keymapper/remap-dialog.cpp +++ b/backends/keymapper/remap-dialog.cpp @@ -28,18 +28,18 @@ #include "gui/widgets/popup.h" #include "gui/widgets/scrollbar.h" #include "gui/ThemeEval.h" - #include "common/translation.h" namespace Common { enum { kRemapCmd = 'REMP', + kClearCmd = 'CLER', kCloseCmd = 'CLOS' }; RemapDialog::RemapDialog() - : Dialog("KeyMapper"), _keymapTable(0), _activeRemapAction(0), _topAction(0), _remapTimeout(0) { + : Dialog("KeyMapper"), _keymapTable(0), _activeRemapAction(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false) { _keymapper = g_system->getEventManager()->getKeymapper(); assert(_keymapper); @@ -57,12 +57,13 @@ RemapDialog::~RemapDialog() { } void RemapDialog::open() { - bool divider = false; const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack(); - if (!(activeKeymaps.size() > 0)) { - _kmPopUp->appendEntry(activeKeymaps.top().keymap->getName() + _(" (Active)")); - divider = true; + if (activeKeymaps.size() > 0) { + if (activeKeymaps.top().keymap->getName() == Common::kGuiKeymapName) + _topKeymapIsGui = true; + // Add the entry for the "effective" special view. See RemapDialog::loadKeymap() + _kmPopUp->appendEntry(activeKeymaps.top().keymap->getName() + _(" (Effective)")); } Keymapper::Domain *_globalKeymaps = &_keymapper->getGlobalDomain(); @@ -84,27 +85,45 @@ void RemapDialog::open() { keymapCount += _gameKeymaps->size(); } - debug(3, "keymaps: %d", keymapCount); + if (activeKeymaps.size() > 1) { + keymapCount += activeKeymaps.size() - 1; + } + + debug(3, "RemapDialog::open keymaps: %d", keymapCount); - _keymapTable = (Keymap **)malloc(sizeof(Keymap*) * keymapCount); + _keymapTable = (Keymap **)malloc(sizeof(Keymap *) * keymapCount); Keymapper::Domain::iterator it; uint32 idx = 0; + if (activeKeymaps.size() > 1) { + int topIndex = activeKeymaps.size() - 1; + bool active = activeKeymaps[topIndex].transparent; + for (int i = topIndex - 1; i >= 0; --i) { + Keymapper::MapRecord mr = activeKeymaps[i]; + // Add an entry for each keymap in the stack after the top keymap. Mark it Active if it is + // reachable or Blocked if an opaque keymap is on top of it thus blocking access to it. + _kmPopUp->appendEntry(mr.keymap->getName() + (active ? _(" (Active)") : _(" (Blocked)")), idx); + _keymapTable[idx++] = mr.keymap; + active &= mr.transparent; + } + } + + _kmPopUp->appendEntry(""); + + // Now add entries for all known keymaps. Note that there will be duplicates with the stack entries. + if (_globalKeymaps) { - if (divider) - _kmPopUp->appendEntry(""); for (it = _globalKeymaps->begin(); it != _globalKeymaps->end(); ++it) { + // "global" means its keybindings apply to all games; saved in a global conf domain _kmPopUp->appendEntry(it->_value->getName() + _(" (Global)"), idx); _keymapTable[idx++] = it->_value; } - divider = true; } if (_gameKeymaps) { - if (divider) - _kmPopUp->appendEntry(""); for (it = _gameKeymaps->begin(); it != _gameKeymaps->end(); ++it) { + // "game" means its keybindings are saved per-target _kmPopUp->appendEntry(it->_value->getName() + _(" (Game)"), idx); _keymapTable[idx++] = it->_value; } @@ -138,16 +157,19 @@ void RemapDialog::reflowLayout() { int16 areaX, areaY; uint16 areaW, areaH; + g_gui.xmlEval()->getWidgetData((const String&)String("KeyMapper.KeymapArea"), areaX, areaY, areaW, areaH); + int spacing = g_gui.xmlEval()->getVar("Globals.KeyMapper.Spacing"); - int labelWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.LabelWidth"); - int buttonWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.ButtonWidth"); - int colWidth = labelWidth + buttonWidth + spacing; + int keyButtonWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.ButtonWidth"); + int clearButtonWidth = g_gui.xmlEval()->getVar("Globals.Line.Height"); + int clearButtonHeight = g_gui.xmlEval()->getVar("Globals.Line.Height"); - g_gui.xmlEval()->getWidgetData((const String&)String("KeyMapper.KeymapArea"), areaX, areaY, areaW, areaH); + int colWidth = areaW - scrollbarWidth; + int labelWidth = colWidth - (keyButtonWidth + spacing + clearButtonWidth + spacing); - _colCount = (areaW - scrollbarWidth) / colWidth; _rowCount = (areaH + spacing) / (buttonHeight + spacing); - if (_colCount <= 0 || _rowCount <= 0) + debug(7, "rowCount = %d" , _rowCount); + if (colWidth <= 0 || _rowCount <= 0) error("Remap dialog too small to display any keymaps"); _scrollBar->resize(areaX + areaW - scrollbarWidth, areaY, scrollbarWidth, areaH); @@ -156,8 +178,9 @@ void RemapDialog::reflowLayout() { _scrollBar->recalc(); uint textYOff = (buttonHeight - kLineHeight) / 2; + uint clearButtonYOff = (buttonHeight - clearButtonHeight) / 2; uint oldSize = _keymapWidgets.size(); - uint newSize = _rowCount * _colCount; + uint newSize = _rowCount; _keymapWidgets.reserve(newSize); @@ -166,19 +189,22 @@ void RemapDialog::reflowLayout() { if (i >= _keymapWidgets.size()) { widg.actionText = - new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignRight); + new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignLeft); widg.keyButton = new GUI::ButtonWidget(this, 0, 0, 0, 0, "", 0, kRemapCmd + i); + widg.clearButton = addClearButton(this, "", kClearCmd + i, 0, 0, clearButtonWidth, clearButtonHeight); _keymapWidgets.push_back(widg); } else { widg = _keymapWidgets[i]; } - uint x = areaX + (i % _colCount) * colWidth; - uint y = areaY + (i / _colCount) * (buttonHeight + spacing); + uint x = areaX; + uint y = areaY + (i) * (buttonHeight + spacing); + + widg.keyButton->resize(x, y, keyButtonWidth, buttonHeight); + widg.clearButton->resize(x + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight); + widg.actionText->resize(x + keyButtonWidth + spacing + clearButtonWidth + spacing, y + textYOff, labelWidth, kLineHeight); - widg.actionText->resize(x, y + textYOff, labelWidth, kLineHeight); - widg.keyButton->resize(x + labelWidth, y, buttonWidth, buttonHeight); } while (oldSize > newSize) { ActionWidgets widg = _keymapWidgets.remove_at(--oldSize); @@ -188,14 +214,19 @@ void RemapDialog::reflowLayout() { removeWidget(widg.keyButton); delete widg.keyButton; + + removeWidget(widg.clearButton); + delete widg.clearButton; } } void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { - debug(0, "Command!"); + debug(3, "RemapDialog::handleCommand %u %u", cmd, data); if (cmd >= kRemapCmd && cmd < kRemapCmd + _keymapWidgets.size()) { startRemapping(cmd - kRemapCmd); + } else if (cmd >= kClearCmd && cmd < kClearCmd + _keymapWidgets.size()) { + clearMapping(cmd - kClearCmd); } else if (cmd == GUI::kPopUpItemSelectedCmd) { loadKeymap(); } else if (cmd == GUI::kSetPositionCmd) { @@ -207,6 +238,23 @@ void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 d } } +void RemapDialog::clearMapping(uint i) { + if (_topAction + i >= _currentActions.size()) + return; + + debug(3, "clear the mapping %u", i); + _activeRemapAction = _currentActions[_topAction + i].action; + _activeRemapAction->mapInput(0); + _activeRemapAction->getParent()->saveMappings(); + _changes = true; + + // force refresh + _topAction = -1; + refreshKeymap(); + + _activeRemapAction = 0; +} + void RemapDialog::startRemapping(uint i) { if (_topAction + i >= _currentActions.size()) return; @@ -238,12 +286,12 @@ void RemapDialog::handleKeyDown(Common::KeyState state) { void RemapDialog::handleKeyUp(Common::KeyState state) { if (_activeRemapAction) { - const HardwareKey *hwkey = _keymapper->findHardwareKey(state); + const HardwareInput *hwInput = _keymapper->findHardwareInput(state); - debug(0, "Key: %d, %d (%c), %x", state.keycode, state.ascii, (state.ascii ? state.ascii : ' '), state.flags); + debug(4, "RemapDialog::handleKeyUp Key: %d, %d (%c), %x", state.keycode, state.ascii, (state.ascii ? state.ascii : ' '), state.flags); - if (hwkey) { - _activeRemapAction->mapKey(hwkey); + if (hwInput) { + _activeRemapAction->mapInput(hwInput); _activeRemapAction->getParent()->saveMappings(); _changes = true; stopRemapping(); @@ -270,52 +318,67 @@ void RemapDialog::loadKeymap() { _currentActions.clear(); const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack(); + debug(3, "RemapDialog::loadKeymap active keymaps: %u", activeKeymaps.size()); + if (!activeKeymaps.empty() && _kmPopUp->getSelected() == 0) { - // load active keymaps + // This is the "effective" view which shows all effective actions: + // - all of the topmost keymap action + // - all mapped actions that are reachable - List<const HardwareKey*> freeKeys(_keymapper->getHardwareKeys()); + List<const HardwareInput *> freeInputs(_keymapper->getHardwareInputs()); - // add most active keymap's keys - Keymapper::MapRecord top = activeKeymaps.top(); - List<Action*>::iterator actIt; + int topIndex = activeKeymaps.size() - 1; + // This is a WORKAROUND for changing the popup list selected item and changing it back + // to the top entry. Upon changing it back, the top keymap is always "gui". + if (!_topKeymapIsGui && activeKeymaps[topIndex].keymap->getName() == kGuiKeymapName) + --topIndex; + + // add most active keymap's keys + Keymapper::MapRecord top = activeKeymaps[topIndex]; + List<Action *>::iterator actIt; + debug(3, "RemapDialog::loadKeymap top keymap: %s", top.keymap->getName().c_str()); for (actIt = top.keymap->getActions().begin(); actIt != top.keymap->getActions().end(); ++actIt) { Action *act = *actIt; ActionInfo info = {act, false, act->description}; _currentActions.push_back(info); - if (act->getMappedKey()) - freeKeys.remove(act->getMappedKey()); + if (act->getMappedInput()) + freeInputs.remove(act->getMappedInput()); } // loop through remaining finding mappings for unmapped keys - if (top.inherit) { - for (int i = activeKeymaps.size() - 2; i >= 0; --i) { + if (top.transparent && topIndex >= 0) { + for (int i = topIndex - 1; i >= 0; --i) { Keymapper::MapRecord mr = activeKeymaps[i]; - List<const HardwareKey*>::iterator keyIt = freeKeys.begin(); + debug(3, "RemapDialog::loadKeymap keymap: %s", mr.keymap->getName().c_str()); + List<const HardwareInput *>::iterator inputIt = freeInputs.begin(); + while (inputIt != freeInputs.end()) { - while (keyIt != freeKeys.end()) { - Action *act = mr.keymap->getMappedAction((*keyIt)->key); + Action *act = mr.keymap->getMappedAction((*inputIt)->key); if (act) { ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"}; _currentActions.push_back(info); - freeKeys.erase(keyIt++); + freeInputs.erase(inputIt); } else { - ++keyIt; + ++inputIt; } } - if (mr.inherit == false || freeKeys.empty()) + if (mr.transparent == false || freeInputs.empty()) break; } } } else if (_kmPopUp->getSelected() != -1) { + // This is the regular view of a keymap that isn't the topmost one. + // It shows all of that keymap's actions + Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()]; - List<Action*>::iterator it; + List<Action *>::iterator it; for (it = km->getActions().begin(); it != km->getActions().end(); ++it) { ActionInfo info = {*it, false, (*it)->description}; @@ -326,7 +389,7 @@ void RemapDialog::loadKeymap() { // refresh scroll bar _scrollBar->_currentPos = 0; - _scrollBar->_numEntries = (_currentActions.size() + _colCount - 1) / _colCount; + _scrollBar->_numEntries = _currentActions.size(); _scrollBar->recalc(); // force refresh @@ -335,7 +398,7 @@ void RemapDialog::loadKeymap() { } void RemapDialog::refreshKeymap() { - int newTopAction = _scrollBar->_currentPos * _colCount; + int newTopAction = _scrollBar->_currentPos; if (newTopAction == _topAction) return; @@ -351,25 +414,28 @@ void RemapDialog::refreshKeymap() { ActionWidgets& widg = _keymapWidgets[widgetI]; if (actionI < _currentActions.size()) { + debug(8, "RemapDialog::refreshKeymap actionI=%u", actionI); ActionInfo& info = _currentActions[actionI]; - widg.actionText->setLabel(info.description + ": "); + widg.actionText->setLabel(info.description); widg.actionText->setEnabled(!info.inherited); - const HardwareKey *mappedKey = info.action->getMappedKey(); + const HardwareInput *mappedInput = info.action->getMappedInput(); - if (mappedKey) - widg.keyButton->setLabel(mappedKey->description); + if (mappedInput) + widg.keyButton->setLabel(mappedInput->description); else widg.keyButton->setLabel("-"); widg.actionText->setVisible(true); widg.keyButton->setVisible(true); + widg.clearButton->setVisible(true); actionI++; } else { widg.actionText->setVisible(false); widg.keyButton->setVisible(false); + widg.clearButton->setVisible(false); } //widg.actionText->draw(); //widg.keyButton->draw(); diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h index f587ae515d..143deca4cf 100644 --- a/backends/keymapper/remap-dialog.h +++ b/backends/keymapper/remap-dialog.h @@ -55,6 +55,7 @@ protected: struct ActionWidgets { GUI::StaticTextWidget *actionText; GUI::ButtonWidget *keyButton; + GUI::ButtonWidget *clearButton; }; struct ActionInfo { Action *action; @@ -64,6 +65,7 @@ protected: void loadKeymap(); void refreshKeymap(); + void clearMapping(uint i); void startRemapping(uint i); void stopRemapping(); @@ -80,7 +82,7 @@ protected: //GUI::ContainerWidget *_container; GUI::ScrollBarWidget *_scrollBar; - uint _colCount, _rowCount; + uint _rowCount; Array<ActionWidgets> _keymapWidgets; Action *_activeRemapAction; @@ -89,6 +91,8 @@ protected: bool _changes; + bool _topKeymapIsGui; + }; } // End of namespace Common diff --git a/backends/keymapper/types.h b/backends/keymapper/types.h deleted file mode 100644 index ed2e498bd0..0000000000 --- a/backends/keymapper/types.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ScummVM - Graphic Adventure Engine -* -* ScummVM is the legal property of its developers, whose names -* are too numerous to list here. Please refer to the COPYRIGHT -* file distributed with this source distribution. -* -* 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; either version 2 -* of the License, or (at your option) any later version. -* -* 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 for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -*/ - -#ifndef KEYMAPPER_TYPES_H -#define KEYMAPPER_TYPES_H - -#include "common/scummsys.h" - -#ifdef ENABLE_KEYMAPPER - -namespace Common { - -enum KeyType { - kGenericKeyType, - kDirUpKeyType, - kDirDownKeyType, - kDirLeftKeyType, - kDirRightKeyType, - kActionKeyType, - kTriggerLeftKeyType, - kTriggerRightKeyType, - kStartKeyType, - kSelectKeyType, - /* ... */ - - kKeyTypeMax -}; - -enum ActionType { - kGenericActionType, - - // common actions - kDirUpActionType, - kDirDownActionType, - kDirLeftActionType, - kDirRightActionType, - kLeftClickActionType, - kRightClickActionType, - kSaveActionType, - kMenuActionType, - kQuitActionType, - kVirtualKeyboardActionType, - kKeyRemapActionType, - kVolumeUpActionType, - kVolumeDownActionType, - - - kActionTypeMax -}; - -} // End of namespace Common - -#endif // #ifdef ENABLE_KEYMAPPER - -#endif // #ifndef KEYMAPPER_TYPES_H |