10 changed files with 323 additions and 303 deletions
@ -1,133 +0,0 @@ |
|||||||
#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" |
|
||||||
#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); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Keymapper::ActionIndex Keymapper::AddAction(const Action &action) |
|
||||||
{ |
|
||||||
actions.emplace_back(action); |
|
||||||
|
|
||||||
return actions.size() - 1; |
|
||||||
} |
|
||||||
|
|
||||||
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(); |
|
||||||
} |
|
||||||
|
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
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()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void Keymapper::Load() |
|
||||||
{ |
|
||||||
keyIDToAction.clear(); |
|
||||||
|
|
||||||
for (auto &action : actions) { |
|
||||||
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); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,69 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <cstddef> |
|
||||||
#include <functional> |
|
||||||
#include <string> |
|
||||||
#include <unordered_map> |
|
||||||
#include <vector> |
|
||||||
|
|
||||||
namespace devilution { |
|
||||||
|
|
||||||
/** The Keymapper maps keys to actions. */ |
|
||||||
class Keymapper final { |
|
||||||
public: |
|
||||||
using ActionIndex = std::size_t; |
|
||||||
|
|
||||||
/**
|
|
||||||
* Action represents an action that can be triggered using a keyboard |
|
||||||
* shortcut. |
|
||||||
*/ |
|
||||||
class Action final { |
|
||||||
public: |
|
||||||
Action(const std::string &name, int defaultKey, std::function<void()> action) |
|
||||||
: name(name) |
|
||||||
, defaultKey(defaultKey) |
|
||||||
, action(action) |
|
||||||
, enable([] { return true; }) |
|
||||||
{ |
|
||||||
} |
|
||||||
Action(const std::string &name, int defaultKey, std::function<void()> action, std::function<bool()> enable) |
|
||||||
: name(name) |
|
||||||
, defaultKey(defaultKey) |
|
||||||
, action(action) |
|
||||||
, enable(enable) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
void operator()() const |
|
||||||
{ |
|
||||||
action(); |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
std::string name; |
|
||||||
int defaultKey; |
|
||||||
std::function<void()> action; |
|
||||||
std::function<bool()> enable; |
|
||||||
int key {}; |
|
||||||
|
|
||||||
friend class Keymapper; |
|
||||||
}; |
|
||||||
|
|
||||||
Keymapper(); |
|
||||||
|
|
||||||
ActionIndex AddAction(const Action &action); |
|
||||||
void KeyPressed(int key) const; |
|
||||||
std::string KeyNameForAction(ActionIndex actionIndex) const; |
|
||||||
void Save() const; |
|
||||||
void Load(); |
|
||||||
|
|
||||||
private: |
|
||||||
int GetActionKey(const Action &action); |
|
||||||
|
|
||||||
std::vector<Action> actions; |
|
||||||
std::unordered_map<int, std::reference_wrapper<Action>> keyIDToAction; |
|
||||||
std::unordered_map<int, std::string> keyIDToKeyName; |
|
||||||
std::unordered_map<std::string, int> keyNameToKeyID; |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace devilution
|
|
||||||
Loading…
Reference in new issue