Keymapper WIP:

* Implemented stack-based active map in Keymapper
* Started proper testing by adding code to OSystem_SDL to set up simple HardwareKeySet and Keymap

svn-id: r33660
This commit is contained in:
Stephen Kennedy 2008-08-06 14:21:05 +00:00
parent 1caf48b084
commit 57b13141af
14 changed files with 201 additions and 76 deletions

View file

@ -28,14 +28,16 @@
namespace Common {
Action::Action(String des, ActionCategory cat, ActionType ty,
int pr, int gr, int fl) {
Action::Action(int32 i, String des,
ActionCategory cat, ActionType typ,
int pri, int grp, int flg) {
id = i;
description = des;
category = cat;
type = ty;
priority = pr;
group = gr;
flags = fl;
type = typ;
priority = pri;
group = grp;
flags = flg;
_hwKey = 0;
_parent = 0;
}

View file

@ -49,8 +49,12 @@ enum ActionType {
kRightClickAction,
kSaveAction,
kMenuAction,
kQuitAction,
kVirtualKeyboardAction,
kRemapKeysAction,
kKeyRemapAction,
kVolumeUpAction,
kVolumeDownAction,
kActionTypeMax
};
@ -69,9 +73,9 @@ struct Action {
int32 id;
/** Human readable description */
String description;
/** Events to be sent when mapped key is pressed */
List<Event> events;
ActionCategory category;
ActionType type;
int priority;
@ -84,16 +88,17 @@ private:
Keymap *_parent;
public:
Action( String des = "",
ActionCategory cat = kGenericActionCategory,
ActionType ty = kGenericActionType,
int pr = 0, int gr = 0, int fl = 0 );
Action( int32 id,
String des = "",
ActionCategory cat = kGenericActionCategory,
ActionType typ = kGenericActionType,
int pri = 0, int grp = 0, int flg = 0 );
void addEvent(const Event &evt) { events.push_back(evt); }
void setParent(Keymap *parent);
void mapKey(const HardwareKey *key);
const HardwareKey *getMappedKey() const;
};
struct ActionPriorityComp : public BinaryFunction<Action, Action, bool> {

View file

@ -48,14 +48,15 @@ struct HardwareKey {
ActionType preferredType;
int16 group;
HardwareKey(KeyState ks = KeyState(), String des = "",
ActionCategory cat = kGenericActionCategory,
ActionType ty = kGenericActionType, int gr = 0) {
key = ks;
description = des;
preferredCategory = cat;
preferredType = ty;
group = gr;
HardwareKey(int32 i, KeyState ks = KeyState(), String des = "",
ActionCategory cat = kGenericActionCategory,
ActionType ty = kGenericActionType, int gr = 0) {
id = i;
key = ks;
description = des;
preferredCategory = cat;
preferredType = ty;
group = gr;
}
};
@ -69,7 +70,7 @@ class HardwareKeySet {
public:
HardwareKeySet() {}
~HardwareKeySet() {
virtual ~HardwareKeySet() {
List<HardwareKey*>::iterator it;
for (it = _keys.begin(); it != _keys.end(); it++)
delete *it;
@ -113,9 +114,9 @@ private:
List<HardwareKey*>::iterator it;
for (it = _keys.begin(); it != _keys.end(); it++) {
if ((*it)->id == key->id)
error("HardwareKey with id %d already given!", key->id);
error("Error adding HardwareKey '%s' - id of %d already in use!", key->description.c_str(), key->id);
else if ((*it)->key == key->key)
error("HardwareKey with same KeyState already given!");
error("Error adding HardwareKey '%s' - key already in use!", key->description.c_str());
}
}

View file

@ -28,13 +28,14 @@
namespace Common {
void KeymapManager::Domain::addDefaultKeymap(Keymap *map) {
void KeymapManager::Domain::setDefaultKeymap(Keymap *map) {
delete _defaultKeymap;
_defaultKeymap = map;
}
void KeymapManager::Domain::addKeymap(const String& name, Keymap *map) {
if (_keymaps.contains(name))
KeymapMap::iterator it = _keymaps.find(name);
if (it != _keymaps.end())
delete _keymaps[name];
_keymaps[name] = map;
}
@ -44,6 +45,7 @@ void KeymapManager::Domain::deleteAllKeyMaps() {
for (it = _keymaps.begin(); it != _keymaps.end(); it++)
delete it->_value;
_keymaps.clear();
delete _defaultKeymap;
}
Keymap *KeymapManager::Domain::getDefaultKeymap() {
@ -58,6 +60,15 @@ Keymap *KeymapManager::Domain::getKeymap(const String& name) {
return 0;
}
KeymapManager::KeymapManager() {
_hardwareKeys = 0;
}
KeymapManager::~KeymapManager() {
delete _hardwareKeys;
}
void KeymapManager::registerHardwareKeySet(HardwareKeySet *keys) {
if (_hardwareKeys)
error("Hardware key set already registered!");
@ -68,7 +79,7 @@ void KeymapManager::registerDefaultGlobalKeymap(Keymap *map) {
ConfigManager::Domain *dom = ConfMan.getDomain(ConfigManager::kApplicationDomain);
assert(dom);
initKeymap(dom, "default", map);
_globalDomain.addDefaultKeymap(map);
_globalDomain.setDefaultKeymap(map);
}
void KeymapManager::registerGlobalKeymap(const String& name, Keymap *map) {
@ -84,7 +95,7 @@ void KeymapManager::registerDefaultGameKeymap(Keymap *map) {
assert(dom);
initKeymap(dom, "default", map);
_gameDomain.addDefaultKeymap(map);
_gameDomain.setDefaultKeymap(map);
}
void KeymapManager::registerGameKeymap(const String& name, Keymap *map) {
@ -99,8 +110,7 @@ void KeymapManager::initKeymap(ConfigManager::Domain *domain,
const String& name,
Keymap *map) {
if (!loadKeymap(domain, name, map))
return;
automaticMap(map);
automaticMap(map);
}
bool KeymapManager::loadKeymap(ConfigManager::Domain *domain,
@ -155,10 +165,9 @@ bool KeymapManager::isMapComplete(const Keymap *map) {
numberMapped++;
} else {
allMapped = false;
break;
}
}
return (allMapped || numberMapped == _hardwareKeys->count());
return allMapped || (numberMapped == _hardwareKeys->count());
}
void KeymapManager::saveKeymap(ConfigManager::Domain *domain,
@ -196,7 +205,7 @@ void KeymapManager::automaticMap(Keymap *map) {
if ((*keyIt)->preferredType == act->type) {
selectedKey = keyIt;
break;
} else if ((*keyIt)->preferredCategory == act->category) {
} else if ((*keyIt)->preferredCategory == act->category && selectedKey == keys.end()) {
selectedKey = keyIt;
}
}

View file

@ -42,7 +42,7 @@ public:
Domain() : _defaultKeymap(0) {}
~Domain() { deleteAllKeyMaps(); }
void addDefaultKeymap(Keymap *map);
void setDefaultKeymap(Keymap *map);
void addKeymap(const String& name, Keymap *map);
void deleteAllKeyMaps();
@ -58,6 +58,9 @@ public:
KeymapMap _keymaps;
};
KeymapManager();
~KeymapManager();
void registerHardwareKeySet(HardwareKeySet *keys);
void registerDefaultGlobalKeymap(Keymap *map);

View file

@ -24,31 +24,50 @@
*/
#include "backends/common/keymapper.h"
#include "backends/common/keymap-manager.h"
#include "common/config-manager.h"
namespace Common {
Keymapper::Keymapper(EventManager *evtMgr) {
_eventMan = evtMgr;
_keymapMan = new KeymapManager();
_currentMap = 0;
}
Keymapper::~Keymapper() {
delete _keymapMan;
}
void Keymapper::registerHardwareKeySet(HardwareKeySet *keys) {
_keymapMan->registerHardwareKeySet(keys);
}
void Keymapper::addGlobalKeyMap(const String& name, Keymap *keymap) {
void Keymapper::addGlobalKeymap(const String& name, Keymap *keymap) {
_keymapMan->registerGlobalKeymap(name, keymap);
}
void Keymapper::addGameKeyMap(const String& name, Keymap *keymap) {
if (_gameId.size() == 0) {
initGame();
if (_gameId.size() == 0)
return;
void Keymapper::setDefaultGlobalKeymap(Keymap *keymap) {
_keymapMan->registerDefaultGlobalKeymap(keymap);
pushKeymap(keymap, false);
}
void Keymapper::addGameKeymap(const String& name, Keymap *keymap) {
if (checkGameInit())
_keymapMan->registerGameKeymap(name, keymap);
}
void Keymapper::setDefaultGameKeymap(Keymap *keymap) {
if (checkGameInit()) {
_keymapMan->registerDefaultGameKeymap(keymap);
pushKeymap(keymap, true);
}
_keymapMan->registerGameKeymap(name, keymap);
}
bool Keymapper::checkGameInit() {
if (_gameId.empty()) {
initGame();
if (_gameId.empty())
return false;
}
return true;
}
void Keymapper::initGame() {
@ -65,17 +84,28 @@ void Keymapper::cleanupGame() {
_gameId.clear();
}
bool Keymapper::switchKeymap(const String& name) {
Keymap *new_map = _keymapMan->getKeymap(name);
if (!new_map) {
bool Keymapper::pushKeymap(const String& name, bool inherit) {
Keymap *newMap = _keymapMan->getKeymap(name);
if (!newMap) {
warning("Keymap '%s' not registered", name.c_str());
return false;
}
_currentMap = new_map;
pushKeymap(newMap, inherit);
return true;
}
void Keymapper::pushKeymap(Keymap *newMap, bool inherit) {
MapRecord mr;
mr.inherit = inherit;
mr.keymap = newMap;
_activeMaps.push(mr);
}
void Keymapper::popKeymap() {
if (!_activeMaps.empty())
_activeMaps.pop();
}
bool Keymapper::mapKeyDown(const KeyState& key) {
return mapKey(key, true);
}
@ -85,9 +115,16 @@ bool Keymapper::mapKeyUp(const KeyState& key) {
}
bool Keymapper::mapKey(const KeyState& key, bool isKeyDown) {
if (!_currentMap) return false;
Action *action = _currentMap->getMappedAction(key);
if (_activeMaps.empty()) return false;
Action *action = 0;
for (int i = _activeMaps.size() - 1; !action && i >= 0; i++) {
MapRecord mr = _activeMaps[i];
action = mr.keymap->getMappedAction(key);
if (mr.inherit == false) break;
}
if (!action) return false;
List<Event>::iterator it;
for (it = action->events.begin(); it != action->events.end(); it++) {
Event evt = *it;

View file

@ -28,19 +28,18 @@
#include "common/events.h"
#include "common/list.h"
#include "common/stack.h"
#include "backends/common/hardware-key.h"
#include "backends/common/keymap.h"
#include "backends/common/keymap-manager.h"
namespace Common {
struct HardwareKey;
class HardwareKeySet;
class KeymapManager;
class Keymap;
class Keymapper {
public:
Keymapper(EventManager *eventMan);
~Keymapper();
/**
* Registers a HardwareKeySet with the Keymapper
@ -48,19 +47,30 @@ public:
*/
void registerHardwareKeySet(HardwareKeySet *keys);
/**
* Add a keymap to the global domain.
* Add a general keymap to the global domain.
* If a saved key setup exists for it in the ini file it will be used.
* Else, the key setup will be automatically mapped.
*/
void addGlobalKeyMap(const String& name, Keymap *keymap);
void addGlobalKeymap(const String& name, Keymap *keymap);
/**
* Add a keymap to the game domain.
* Sets the default keymap for the global domain.
*/
void setDefaultGlobalKeymap(Keymap *keymap);
/**
* Add a general keymap to the game domain.
* @see addGlobalKeyMap
* @note initGame() should be called before any game keymaps are added.
*/
void addGameKeyMap(const String& name, Keymap *keymap);
void addGameKeymap(const String& name, Keymap *keymap);
/**
* Sets the default keymap for the game domain.
*/
void setDefaultGameKeymap(Keymap *keymap);
/**
* Initialise the keymapper for a new game
@ -73,19 +83,25 @@ public:
void cleanupGame();
/**
* Switch the active keymap.
* @param name name of the new keymap
* 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
* @return true if successful
*/
bool switchKeymap(const String& name);
bool pushKeymap(const String& name, bool inherit = false);
/**
* Pop the active keymap off the stack.
*/
void popKeymap();
/**
* @brief Map a key press event.
* If the active keymap contains a Action mapped to the given key, then
* the Action's events are pushed into the EventManager's event queue.
* @param key key that was pressed
* @param isKeyDown true for key down, false for key up
* @return true if key was mapped
* @param key key that was pressed
* @param isKeyDown true for key down, false for key up
* @return true if key was mapped
*/
bool mapKey(const KeyState& key, bool isKeyDown);
@ -103,6 +119,9 @@ public:
private:
void pushKeymap(Keymap *newMap, bool inherit);
bool checkGameInit();
typedef List<HardwareKey*>::iterator Iterator;
EventManager *_eventMan;
@ -110,7 +129,12 @@ private:
String _gameId;
Keymap *_currentMap;
struct MapRecord {
Keymap* keymap;
bool inherit;
};
Stack<MapRecord> _activeMaps;
};

View file

@ -196,10 +196,11 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) :
}
_vk = new Common::VirtualKeyboard();
_keyMapper = new Common::Keymapper(this);
_keymapper = new Common::Keymapper(this);
}
DefaultEventManager::~DefaultEventManager() {
delete _keymapper;
delete _vk;
_boss->lockMutex(_timeMutex);
_boss->lockMutex(_recorderMutex);
@ -372,10 +373,10 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
if (result) {
// send key press events to keymapper
if (event.type == Common::EVENT_KEYDOWN) {
if (_keyMapper->mapKeyDown(event.kbd))
if (_keymapper->mapKeyDown(event.kbd))
result = false;
} else if (event.type == Common::EVENT_KEYUP) {
if (_keyMapper->mapKeyUp(event.kbd))
if (_keymapper->mapKeyUp(event.kbd))
result = false;
}
}

View file

@ -32,7 +32,6 @@
namespace Common {
class VirtualKeyboard;
class Keymapper;
}
/*
@ -51,7 +50,7 @@ class DefaultEventManager : public Common::EventManager {
OSystem *_boss;
Common::VirtualKeyboard *_vk;
Common::Keymapper *_keyMapper;
Common::Keymapper *_keymapper;
Common::Queue<Common::Event> _artificialEventQueue;
int _artificialEventCounter;
@ -130,6 +129,7 @@ public:
virtual int getButtonState() const { return _buttonState; }
virtual int getModifierState() const { return _modifierState; }
virtual int shouldQuit() const { return _shouldQuit; }
virtual Common::Keymapper *getKeymapper() { return _keymapper; }
};
#endif

View file

@ -24,6 +24,7 @@
*/
#include "backends/platform/sdl/sdl.h"
#include "backends/common/keymapper.h"
#include "common/util.h"
#include "common/events.h"
@ -520,3 +521,36 @@ bool OSystem_SDL::remapKey(SDL_Event &ev, Common::Event &event) {
return false;
}
void OSystem_SDL::setupKeymapper() {
using namespace Common;
Keymapper *mapper = getEventManager()->getKeymapper();
HardwareKeySet *keySet = new HardwareKeySet();
keySet->addHardwareKey(new HardwareKey( 'a', KeyState(KEYCODE_a), "a" ));
keySet->addHardwareKey(new HardwareKey( 's', KeyState(KEYCODE_s), "s" ));
keySet->addHardwareKey(new HardwareKey( 'd', KeyState(KEYCODE_d), "d" ));
keySet->addHardwareKey(new HardwareKey( 'f', KeyState(KEYCODE_f), "f" ));
mapper->registerHardwareKeySet(keySet);
Keymap *global = new Keymap();
Action *act;
Event evt;
#define ADD_KEYDOWN_EVENT(kc, asc, flags) \
evt.type = EVENT_KEYDOWN; \
evt.kbd = KeyState(kc, asc, flags); \
act->events.push_back(evt);
act = new Action('MENU', "Menu", kGenericActionCategory, kMenuAction);
ADD_KEYDOWN_EVENT(KEYCODE_F5, ASCII_F5, 0)
global->addAction(act);
act = new Action('QUIT', "Quit", kGenericActionCategory, kQuitAction);
ADD_KEYDOWN_EVENT(KEYCODE_ESCAPE, ASCII_ESCAPE, 0);
global->addAction(act);
#undef ADD_KEYDOWN_EVENT
mapper->setDefaultGlobalKeymap(global);
}

View file

@ -148,6 +148,9 @@ void OSystem_SDL::initBackend() {
_timerID = SDL_AddTimer(10, &timer_handler, _timer);
}
// Provide the keymapper with backend's set of keys
setupKeymapper();
// Invoke parent implementation of this method
OSystem::initBackend();

View file

@ -142,6 +142,9 @@ public:
// Returns true if an event was retrieved.
virtual bool pollEvent(Common::Event &event); // overloaded by CE backend
// Sets up the keymapper with the backends hardware key set
virtual void setupKeymapper();
// Set function that generates samples
virtual void setupMixer();
static void mixCallback(void *s, byte *samples, int len);

View file

@ -119,6 +119,7 @@ struct Event {
Common::Point mouse;
};
class Keymapper;
/**
* The EventManager provides user input events to the client code.
@ -178,6 +179,8 @@ public:
// TODO: Consider removing OSystem::getScreenChangeID and
// replacing it by a generic getScreenChangeID method here
virtual Common::Keymapper *getKeymapper() = 0;
};
} // End of namespace Common

View file

@ -33,7 +33,7 @@ ImageMap::~ImageMap() {
Rect *ImageMap::createRectArea(const String& id) {
if (_areas.contains(id)) {
warning("Image map already contains an area with target of '%s'");
warning("Image map already contains an area with target of '%s'", id.c_str());
return 0;
}
Rect *r = new Rect();
@ -43,7 +43,7 @@ Rect *ImageMap::createRectArea(const String& id) {
Polygon *ImageMap::createPolygonArea(const String& id) {
if (_areas.contains(id)) {
warning("Image map already contains an area with target of '%s'");
warning("Image map already contains an area with target of '%s'", id.c_str());
return 0;
}
Polygon *p = new Polygon();