You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.4 KiB

#include "keymapper.hpp"
#include <cassert>
#include <fmt/format.h>
#include <utility>
#include <SDL.h>
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#endif
#include "control.h"
#include "options.h"
5 years ago
#include "utils/log.hpp"
namespace devilution {
Keymapper::Keymapper()
{
// Insert all supported keys: a-z, 0-9 and F1-F12.
keyIDToKeyName.reserve(('Z' - 'A' + 1) + ('9' - '0' + 1) + 12);
for (char c = 'A'; c <= 'Z'; ++c) {
keyIDToKeyName.emplace(c, std::string(1, c));
}
for (char c = '0'; c <= '9'; ++c) {
keyIDToKeyName.emplace(c, std::string(1, c));
}
for (int i = 0; i < 12; ++i) {
keyIDToKeyName.emplace(DVL_VK_F1 + i, fmt::format("F{}", i + 1));
}
keyNameToKeyID.reserve(keyIDToKeyName.size());
for (const auto &kv : keyIDToKeyName) {
keyNameToKeyID.emplace(kv.second, kv.first);
}
}
5 years ago
Keymapper::ActionIndex Keymapper::AddAction(const Action &action)
{
actions.emplace_back(action);
return actions.size() - 1;
}
5 years ago
void Keymapper::KeyPressed(int key) const
{
auto it = keyIDToAction.find(key);
if (it == keyIDToAction.end())
return; // Ignore unmapped keys.
const auto &action = it->second;
// Check that the action can be triggered and that the chat textbox is not
// open.
if (!action.get().enable() || talkflag)
return;
action();
}
5 years ago
std::string Keymapper::KeyNameForAction(ActionIndex actionIndex) const
{
assert(actionIndex < actions.size());
auto key = actions[actionIndex].key;
auto it = keyIDToKeyName.find(key);
assert(it != keyIDToKeyName.end());
return it->second;
}
5 years ago
void Keymapper::Save() const
{
// Use the action vector to go though the actions to keep the same order.
for (const auto &action : actions) {
if (action.key == DVL_VK_INVALID) {
// Just add an empty config entry if the action is unbound.
SetIniValue("Keymapping", action.name.c_str(), "");
continue;
}
auto keyNameIt = keyIDToKeyName.find(action.key);
if (keyNameIt == keyIDToKeyName.end()) {
Log("Keymapper: no name found for key '{}'", action.key);
continue;
}
SetIniValue("Keymapping", action.name.c_str(), keyNameIt->second.c_str());
}
}
5 years ago
void Keymapper::Load()
{
keyIDToAction.clear();
for (auto &action : actions) {
5 years ago
auto key = GetActionKey(action);
action.key = key;
if (key == DVL_VK_INVALID) {
// Skip if the action has no key bound to it.
continue;
}
// Store the key in action.key and in the map so we can save() the
// actions while keeping the same order as they have been added.
keyIDToAction.emplace(key, action);
}
}
5 years ago
int Keymapper::GetActionKey(const Keymapper::Action &action)
{
std::array<char, 64> result;
if (!GetIniValue("Keymapping", action.name.c_str(), result.data(), result.size()))
return action.defaultKey; // Return the default key if no key has been set.
std::string key = result.data();
if (key.empty())
return DVL_VK_INVALID;
auto keyIt = keyNameToKeyID.find(key);
if (keyIt == keyNameToKeyID.end()) {
// Return the default key if the key is unknown.
Log("Keymapper: unknown key '{}'", key);
return action.defaultKey;
}
auto it = keyIDToAction.find(keyIt->second);
if (it != keyIDToAction.end()) {
// Warn about overwriting keys.
Log("Keymapper: key '{}' is already bound to action '{}', overwriting", key, it->second.get().name);
}
return keyIt->second;
}
} // namespace devilution