ULTIMA8: Support key bindings using Ctrl, Alt, Shift, or Meta

This commit is contained in:
Paul Gilbert 2019-12-15 18:09:55 -08:00 committed by Paul Gilbert
parent bae44fcb51
commit 4abed94231
10 changed files with 170 additions and 181 deletions

Binary file not shown.

View File

@ -234,18 +234,6 @@ static const KeyName keyNames[] = {
{HID_SCROLL_LOCK, "Scroll-Lock"},
{HID_PAUSE, "Pause"},
{HID_LEFTSHIFT, "Left-Shift"},
{HID_RIGHTSHIFT, "Right-Shift"},
{HID_LEFTCONTROL, "Left-Control"},
{HID_LEFTCONTROL, "Left-Ctrl"},
{HID_RIGHTCONTROL, "Right-Control"},
{HID_RIGHTCONTROL, "Right-Ctrl"},
{HID_LEFTALT, "Left-Alt"},
{HID_RIGHTALT, "Right-Alt"},
{HID_MOUSE1, "Mouse1"},
{HID_MOUSE2, "Mouse2"},
{HID_MOUSE3, "Mouse3"},
@ -288,13 +276,18 @@ struct EventName {
const char *name;
};
static const EventName eventNames[] = {
{HID_EVENT_DEPRESS, "<Depress>"},
{HID_EVENT_RELEASE, "<Release>"},
{HID_EVENT_DOUBLE, "<Double>"},
{HID_EVENT_CLICK, "<Click>"},
{HID_EVENT_PREEMPT, "<Preempt>"},
{HID_EVENT_LAST, ""}
static const EventName EVENT_NAMES[] = {
{ HID_EVENT_DEPRESS, "Depress" },
{ HID_EVENT_RELEASE, "Release" },
{ HID_EVENT_DOUBLE, "Double" },
{ HID_EVENT_CLICK, "Click" },
{ HID_EVENT_PREEMPT, "Preempt" },
{ HID_EVENT_LAST, "" },
{ HID_FLAGS_CTRL, "Ctrl" },
{ HID_FLAGS_ALT, "Alt" },
{ HID_FLAGS_SHIFT, "Shift" },
{ HID_FLAGS_META, "Meta" },
{ HID_FLAGS_LAST, "" }
};
const char *HID_GetKeyName(HID_Key key) {
@ -303,6 +296,7 @@ const char *HID_GetKeyName(HID_Key key) {
if (key == keyNames[i].key)
return keyNames[i].name;
}
return "";
}
@ -312,6 +306,7 @@ HID_Key HID_GetKeyFromName(Pentagram::istring &name) {
if (name == keyNames[i].name)
return keyNames[i].key;
}
return HID_LAST;
}
@ -552,24 +547,27 @@ HID_Key HID_translateSDLKey(Common::KeyCode key) {
return HID_PAUSE;
case Common::KEYCODE_ESCAPE:
return HID_ESCAPE;
case Common::KEYCODE_RSHIFT:
return HID_RIGHTSHIFT;
case Common::KEYCODE_LSHIFT:
return HID_LEFTSHIFT;
case Common::KEYCODE_RCTRL:
return HID_RIGHTCONTROL;
case Common::KEYCODE_LCTRL:
return HID_LEFTCONTROL;
case Common::KEYCODE_RALT:
return HID_RIGHTALT;
case Common::KEYCODE_LALT:
return HID_LEFTALT;
default:
break;
}
return HID_LAST;
}
HID_Events HID_translateSDLKeyFlags(byte flags) {
HID_Events result = 0;
if (flags & Common::KBD_CTRL)
result |= HID_FLAGS_CTRL;
if (flags & Common::KBD_ALT)
result |= HID_FLAGS_ALT;
if (flags & Common::KBD_SHIFT)
result |= HID_FLAGS_SHIFT;
if (flags & Common::KBD_META)
result |= HID_FLAGS_META;
return result;
}
HID_Key HID_translateSDLMouseButton(uint8 button) {
switch (button) {
case 1:
@ -650,22 +648,55 @@ HID_Key HID_translateSDLJoystickButton(uint8 button) {
return HID_LAST;
}
const char *HID_GetEventName(HID_Event event) {
const char *HID_GetEventsName(HID_Events events) {
static char buffer[32];
strcpy(buffer, "<");
int i;
for (i = 0; eventNames[i].event != HID_EVENT_LAST; ++i) {
if (event == eventNames[i].event)
return eventNames[i].name;
for (i = 0; EVENT_NAMES[i].event != HID_FLAGS_LAST; ++i) {
if ((EVENT_NAMES[i].event <= HID_EVENT_LAST) ? (events & 0xff) == EVENT_NAMES[i].event :
(events & EVENT_NAMES[i].event) != 0) {
if (EVENT_NAMES[i].event == HID_EVENT_DEPRESS && events != HID_EVENT_DEPRESS)
continue;
strcat(buffer, EVENT_NAMES[i].name);
strcat(buffer, ",");
}
}
return "";
buffer[strlen(buffer) - 1] = '>';
return buffer;
}
HID_Event HID_GetEventFromName(Pentagram::istring &name) {
int i;
for (i = 0; eventNames[i].event != HID_EVENT_LAST; ++i) {
if (name == eventNames[i].name)
return eventNames[i].event;
HID_Events HID_GetEventFromName(const Pentagram::istring &name) {
// Split up the name(s)
Pentagram::istring str = name;
if (name.hasPrefix("<") && name.hasSuffix(">")) {
str.deleteChar(0);
str.deleteLastChar();
}
return HID_EVENT_LAST;
Common::Array<Pentagram::istring> events;
str.split(events);
HID_Events result = 0;
for (uint termIdx = 0; termIdx < events.size(); ++termIdx) {
// Scan for matching event/flag name
for (int i = 0; EVENT_NAMES[i].event != HID_FLAGS_LAST; ++i) {
if (EVENT_NAMES[i].event == HID_EVENT_LAST)
continue;
if (events[termIdx] == EVENT_NAMES[i].name) {
if (EVENT_NAMES[i].event < HID_EVENT_LAST)
result = (result & ~0xff) | EVENT_NAMES[i].event;
else
result |= EVENT_NAMES[i].event;
}
}
}
return result;
}
} // End of namespace Ultima8

View File

@ -165,13 +165,6 @@ enum HID_Key {
HID_PAUSE,
HID_ESCAPE,
HID_LEFTSHIFT,
HID_RIGHTSHIFT,
HID_LEFTCONTROL,
HID_RIGHTCONTROL,
HID_LEFTALT,
HID_RIGHTALT,
/* Mouse Buttons */
HID_MOUSE1,
HID_MOUSE2,
@ -224,11 +217,18 @@ enum HID_Event {
HID_EVENT_DOUBLE,
HID_EVENT_CLICK,
HID_EVENT_PREEMPT,
HID_EVENT_LAST
HID_EVENT_LAST,
HID_FLAGS_CTRL = 0x100,
HID_FLAGS_ALT = 0x200,
HID_FLAGS_SHIFT = 0x400,
HID_FLAGS_META = 0x800,
HID_FLAGS_LAST = 0xffff
};
typedef uint16 HID_Events;
const char *HID_GetEventName(HID_Event event);
HID_Event HID_GetEventFromName(Pentagram::istring &name);
HID_Events HID_translateSDLKeyFlags(byte flags);
const char *HID_GetEventsName(HID_Events event);
HID_Events HID_GetEventFromName(const Pentagram::istring &name);
} // End of namespace Ultima8

View File

@ -30,15 +30,13 @@
namespace Ultima8 {
HIDManager *HIDManager::hidmanager = 0;
HIDManager *HIDManager::_hidManager = 0;
HIDManager::HIDManager() {
_hidManager = this;
con->Print(MM_INFO, "Creating HIDManager...\n");
hidmanager = this;
InitJoystick();
resetBindings();
}
@ -46,47 +44,40 @@ HIDManager::~HIDManager() {
std::vector<Console::ArgvType *>::iterator it;
con->Print(MM_INFO, "Destroying HIDManager...\n");
for (it = commands.begin(); it != commands.end(); ++it) {
for (it = _commands.begin(); it != _commands.end(); ++it) {
if (*it) {
delete *it;
}
}
commands.clear();
_commands.clear();
ShutdownJoystick();
hidmanager = 0;
_hidManager = 0;
}
bool HIDManager::handleEvent(const HID_Key key, const HID_Event evn) {
bool HIDManager::handleEvent(HID_Key key, HID_Events events) {
bool handled = false;
uint32 keyEvent = (uint32)key | ((uint32)events << 16);
if (key < HID_LAST && evn < HID_EVENT_LAST) {
Console::ArgvType *command = bindings[key][evn];
if (command) {
con->ExecuteConsoleCommand(*command);
handled = true;
}
if (_bindings.contains(keyEvent)) {
con->ExecuteConsoleCommand(*_bindings[keyEvent]);
handled = true;
}
return handled;
}
void HIDManager::resetBindings() {
uint16 key, event;
std::vector<Console::ArgvType *>::iterator it;
for (key = 0; key < HID_LAST; ++key) {
for (event = 0; event < HID_EVENT_LAST; ++event) {
bindings[key][event] = 0;
}
}
_bindings.clear();
for (it = commands.begin(); it != commands.end(); ++it) {
for (it = _commands.begin(); it != _commands.end(); ++it) {
if (*it) {
delete *it;
}
}
commands.clear();
_commands.clear();
bind(HID_BACKQUOTE, HID_EVENT_PREEMPT, "ConsoleGump::toggle");
bind(HID_TILDE, HID_EVENT_PREEMPT, "ConsoleGump::toggle");
@ -117,34 +108,33 @@ void HIDManager::loadBindings() {
bind(i->_key, args);
++i;
}
listBindings();
}
void HIDManager::saveBindings() {
uint16 key, event;
uint16 key, events;
SettingManager *settings = SettingManager::get_instance();
Pentagram::istring section = "keys/";
Pentagram::istring confkey;
for (key = 0; key < HID_LAST; ++key) {
for (event = 0; event < HID_EVENT_LAST; ++event) {
confkey = section +
HID_GetEventName((HID_Event) event) + ' ' +
HID_GetKeyName((HID_Key) key);
if (bindings[key][event]) {
Console::ArgsType command;
Pentagram::ArgvToString(*bindings[key][event], command);
settings->set(confkey, command);
} else if (settings->exists(confkey)) {
settings->unset(confkey);
}
}
for (Bindings::iterator it = _bindings.begin(); it != _bindings.end(); ++it) {
key = it->_key & 0xffff;
events = it->_key >> 16;
confkey = section + HID_GetEventsName((HID_Events)events) + ' ' +
HID_GetKeyName((HID_Key) key);
Console::ArgsType command;
Pentagram::ArgvToString(*(it->_value), command);
settings->set(confkey, command);
// settings->unset(confkey);
}
}
void HIDManager::bind(const Pentagram::istring &control, const Console::ArgvType &argv) {
HID_Key key = HID_LAST;
HID_Event event = HID_EVENT_DEPRESS;
HID_Events event = HID_EVENT_DEPRESS;
std::vector<Pentagram::istring> ctrl_argv;
Pentagram::StringToArgv(control, ctrl_argv);
@ -152,15 +142,11 @@ void HIDManager::bind(const Pentagram::istring &control, const Console::ArgvType
key = HID_GetKeyFromName(ctrl_argv[0]);
} else if (ctrl_argv.size() > 1) {
// we have a event
event = HID_GetEventFromName(ctrl_argv[0]);
key = HID_GetKeyFromName(ctrl_argv[1]);
event = HID_GetEventFromName(ctrl_argv[0]);
}
if (event < HID_EVENT_LAST && key < HID_LAST) {
bind(key, event, argv);
} else {
pout << "Error: Cannot bind " << control << std::endl;
}
bind(key, event, argv);
}
void HIDManager::bind(const Pentagram::istring &control, const Console::ArgsType &args) {
@ -169,11 +155,13 @@ void HIDManager::bind(const Pentagram::istring &control, const Console::ArgsType
bind(control, argv);
}
void HIDManager::bind(HID_Key key, HID_Event event, const Console::ArgvType &argv) {
void HIDManager::bind(HID_Key key, HID_Events event, const Console::ArgvType &argv) {
uint32 keyEvent = (uint32)key | ((uint32)event << 16);
Console::ArgvType *command = 0;
if (! argv.empty()) {
std::vector<Console::ArgvType *>::iterator it;
for (it = commands.begin(); it != commands.end(); ++it) {
for (it = _commands.begin(); it != _commands.end(); ++it) {
if (argv == (**it)) {
// Change from iterator to pointer
command = *it;
@ -183,13 +171,15 @@ void HIDManager::bind(HID_Key key, HID_Event event, const Console::ArgvType &arg
if (!command) {
command = new Console::ArgvType(argv);
commands.push_back(command);
_commands.push_back(command);
}
}
bindings[key][event] = command;
assert(command);
_bindings[keyEvent] = command;
}
void HIDManager::bind(HID_Key key, HID_Event event, const Console::ArgsType &args) {
void HIDManager::bind(HID_Key key, HID_Events event, const Console::ArgsType &args) {
Console::ArgvType argv;
Pentagram::StringToArgv(args, argv);
bind(key, event, argv);
@ -251,19 +241,16 @@ void HIDManager::listBindings() {
uint16 key, event;
Console::ArgsType command;
for (key = 0; key < HID_LAST; ++key) {
for (event = 0; event < HID_EVENT_LAST; ++event) {
if (bindings[key][event]) {
Pentagram::ArgvToString(*bindings[key][event], command);
if (event != HID_EVENT_DEPRESS) {
pout << HID_GetEventName((HID_Event) event) << ' ' <<
HID_GetKeyName((HID_Key) key) <<
" = " << command << std::endl;
} else {
pout << HID_GetKeyName((HID_Key) key) <<
" = " << command << std::endl;
}
}
for (Bindings::iterator it = _bindings.begin(); it != _bindings.end(); ++it) {
key = it->_key & 0xffff;
event = it->_key >> 16;
Pentagram::ArgvToString(*(it->_value), command);
if (event == HID_EVENT_DEPRESS) {
pout << HID_GetKeyName((HID_Key)key) << " = " << command << std::endl;
} else {
pout << HID_GetEventsName((HID_Events)event);
pout << ' ' << HID_GetKeyName((HID_Key) key) << " = " << command << std::endl;
}
}
}

View File

@ -32,20 +32,27 @@ namespace Ultima8 {
//! Responsible to loading the keybindings and storing them
class HIDManager {
private:
static HIDManager *_hidManager;
std::vector<Console::ArgvType *> _commands;
typedef Common::HashMap<uint32, Console::ArgvType *> Bindings;
Bindings _bindings;
void listBindings();
public:
HIDManager();
~HIDManager();
//! obtain the singleton instance of the HIDManager
static HIDManager *get_instance() {
return hidmanager;
return _hidManager;
}
//! execute the Console command associated with the event
//! \param key a HID_KEY used to find an appropriate Console command
//! \param evn a HID_Event used to find an appropriate Console command
//! \param events is a bitset of event/flags
//! \return true if a console command is executed
bool handleEvent(const HID_Key key, const HID_Event evn);
bool handleEvent(HID_Key key, HID_Events events);
//! Reset the keybindings
void resetBindings();
@ -62,8 +69,8 @@ public:
void bind(const Pentagram::istring &control, const Console::ArgvType &argv);
void bind(const Pentagram::istring &control, const Console::ArgsType &args);
void bind(HID_Key key, HID_Event event, const Console::ArgvType &argv);
void bind(HID_Key key, HID_Event event, const Console::ArgsType &args);
void bind(HID_Key key, HID_Events event, const Console::ArgvType &argv);
void bind(HID_Key key, HID_Events event, const Console::ArgsType &args);
//! removes all controls to a HIDBinding or the binding to one specified key
//! \param bindingName name of a HIDBinding or the name of key
@ -80,14 +87,6 @@ public:
//! "save" console command
static void ConCmd_save(const Console::ArgvType &argv);
private:
void listBindings();
std::vector<Console::ArgvType *> commands;
Console::ArgvType *bindings[HID_LAST][HID_EVENT_LAST];
static HIDManager *hidmanager;
};
} // End of namespace Ultima8

View File

@ -450,7 +450,7 @@ template<class T>
class console_ostream : public ConsoleStream {
virtual uint32 write(const void *dataPtr, uint32 dataSize) override {
Common::String str((const char *)dataPtr, (const char *)dataPtr + dataSize);
debug("%s", str.c_str());
debugN("%s", str.c_str());
return dataSize;
}
};

View File

@ -63,34 +63,23 @@ void strcpy_s(char *dest, size_t size, const char *src) {
dest[-1] = 0;
}
#if 0
void istring::split(Common::Array<istring> &arr) const {
const char *startP = _str, *endP;
bool ichar_traits::eq(const char_type &c1, const char_type &c2) {
uint32 c3 = c1;
uint32 c4 = c2;
if (c3 >= 'a' && c3 <= 'z')
c3 -= ('a' - 'A');
if (c4 >= 'a' && c4 <= 'z')
c4 -= ('a' - 'A');
return c3 == c4;
arr.clear();
if (empty())
return;
for (;;) {
endP = strchr(startP + 1, ',');
arr.push_back(Pentagram::istring(startP, endP ? endP : _str + _size));
if (!endP)
break;
startP = endP;
}
}
bool ichar_traits::lt(const char_type &c1, const char_type &c2) {
uint32 c3 = c1;
uint32 c4 = c2;
if (c3 >= 'a' && c3 <= 'z')
c3 -= ('a' - 'A');
if (c4 >= 'a' && c4 <= 'z')
c4 -= ('a' - 'A');
return c3 < c4;
}
int ichar_traits::compare(const char_type *s1, const char_type *s2, size_t length) {
return strncasecmp(s1, s2, length);
}
#endif
} // End of namespace Pentagram
} // ENd of namespace Ultima8

View File

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "ultima/ultima8/std/misc.h"
#include "ultima/ultima8/std/string.h"
#include "common/array.h"
#ifdef strcasecmp
#undef strcasecmp
@ -74,6 +75,8 @@ public:
virtual int Compare(const string &s) const override {
return compareToIgnoreCase(s);
}
void split(Common::Array<istring> &arr) const ;
};

View File

@ -207,7 +207,6 @@ bool Ultima8Engine::initialize() {
con->AddConsoleCommand("Ultima8Engine::memberVar", &Ultima8Engine::ConCmd_memberVar);
con->AddConsoleCommand("Ultima8Engine::setVideoMode", ConCmd_setVideoMode);
con->AddConsoleCommand("Ultima8Engine::toggleFullscreen", ConCmd_toggleFullscreen);
con->AddConsoleCommand("Ultima8Engine::toggleAvatarInStasis", ConCmd_toggleAvatarInStasis);
con->AddConsoleCommand("Ultima8Engine::togglePaintEditorItems", ConCmd_togglePaintEditorItems);
@ -327,7 +326,6 @@ void Ultima8Engine::deinitialize() {
con->RemoveConsoleCommand(Ultima8Engine::ConCmd_memberVar);
con->RemoveConsoleCommand(Ultima8Engine::ConCmd_setVideoMode);
con->RemoveConsoleCommand(Ultima8Engine::ConCmd_toggleFullscreen);
con->RemoveConsoleCommand(Ultima8Engine::ConCmd_toggleAvatarInStasis);
con->RemoveConsoleCommand(Ultima8Engine::ConCmd_togglePaintEditorItems);
@ -1131,32 +1129,16 @@ void Ultima8Engine::leaveTextMode(Gump *gump) {
void Ultima8Engine::handleEvent(const Common::Event &event) {
uint32 now = g_system->getMillis();
HID_Key key = HID_LAST;
HID_Event evn = HID_EVENT_LAST;
uint16 evn = HID_EVENT_LAST;
bool handled = false;
switch (event.type) {
case Common::EVENT_KEYDOWN:
key = HID_translateSDLKey(event.kbd.keycode);
evn = HID_EVENT_DEPRESS;
evn = HID_translateSDLKeyFlags(event.kbd.flags);
break;
case Common::EVENT_KEYUP:
key = HID_translateSDLKey(event.kbd.keycode);
evn = HID_EVENT_RELEASE;
if (_mouse->dragging() == Mouse::DRAG_NOT) {
switch (event.kbd.keycode) {
case Common::KEYCODE_q: // Quick quit
#ifndef MACOSX
if (event.kbd.flags & Common::KBD_CTRL)
ForceQuit();
#else
if (event.kbd.flags & Common::KBD_META)
ForceQuit();
#endif
return;
default:
break;
}
}
// Any system keys not in the bindings can be handled here
break;
case Common::EVENT_LBUTTONDOWN:
@ -1301,6 +1283,9 @@ void Ultima8Engine::handleEvent(const Common::Event &event) {
break;
// Any special key handling goes here
if ((event.kbd.keycode == Common::KEYCODE_x || event.kbd.keycode == Common::KEYCODE_x) &&
(event.kbd.flags & (Common::KBD_CTRL | Common::KBD_ALT | Common::KBD_META)) != 0)
ForceQuit();
break;
default:
@ -1851,7 +1836,6 @@ void Ultima8Engine::ConCmd_newGame(const Console::ArgvType &argv) {
Ultima8Engine::get_instance()->newGame(std::string());
}
void Ultima8Engine::ConCmd_quit(const Console::ArgvType &argv) {
Ultima8Engine::get_instance()->isRunning = false;
}
@ -1914,10 +1898,6 @@ void Ultima8Engine::ConCmd_setVideoMode(const Console::ArgvType &argv) {
Ultima8Engine::get_instance()->changeVideoMode(strtol(argv[1].c_str(), 0, 0), strtol(argv[2].c_str(), 0, 0), fullscreen);
}
void Ultima8Engine::ConCmd_toggleFullscreen(const Console::ArgvType &argv) {
Ultima8Engine::get_instance()->changeVideoMode(-1, -1, -2);
}
void Ultima8Engine::ConCmd_toggleAvatarInStasis(const Console::ArgvType &argv) {
Ultima8Engine *g = Ultima8Engine::get_instance();
g->toggleAvatarInStasis();

View File

@ -102,9 +102,10 @@ private:
bool loadData();
// Load and save games from arbitrary filenames from the console
static void ConCmd_saveGame(const Console::ArgvType &argv); //!< "Ultima8Engine::saveGame <filename>" console command
static void ConCmd_loadGame(const Console::ArgvType &argv); //!< "Ultima8Engine::loadGame <filename>" console command
static void ConCmd_saveGame(const Console::ArgvType &argv); //!< "Ultima8Engine::saveGame <optional filename>" console command
static void ConCmd_loadGame(const Console::ArgvType &argv); //!< "Ultima8Engine::loadGame <optional filename>" console command
static void ConCmd_newGame(const Console::ArgvType &argv); //!< "Ultima8Engine::newGame" console command
static void ConCmd_ForceQuit(const Console::ArgvType &argv);
static void ConCmd_quit(const Console::ArgvType &argv); //!< "quit" console command
@ -112,7 +113,6 @@ private:
static void ConCmd_listGames(const Console::ArgvType &argv); //!< "Ultima8Engine::listGames" console command
static void ConCmd_setVideoMode(const Console::ArgvType &argv); //!< "Ultima8Engine::setVideoMode" console command
static void ConCmd_toggleFullscreen(const Console::ArgvType &argv); //!< "Ultima8Engine::toggleFullscreen" console command
// This should be a console variable once they are implemented
bool drawRenderStats;