Make the hotkey code a bit less bloated

This commit is contained in:
Thomas Goyne 2014-07-04 20:16:24 -07:00
parent c0c05e982a
commit 518342b919
5 changed files with 225 additions and 270 deletions

View File

@ -12,36 +12,33 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/// @file hotkey.cpp
/// @brief Hotkey handler
/// @ingroup hotkey menu event window
#include "libaegisub/hotkey.h"
#include "libaegisub/cajun/writer.h"
#include "libaegisub/io.h"
#include "libaegisub/json.h"
#include "libaegisub/log.h"
#include "libaegisub/split.h"
#include <algorithm>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/equal_range.hpp>
#include <tuple>
namespace agi {
namespace hotkey {
namespace agi { namespace hotkey {
namespace {
struct combo_cmp {
bool operator()(const Combo *a, const Combo *b) {
return a->Str() < b->Str();
}
std::string Combo::Str() const {
return boost::algorithm::join(key_map, "-");
}
bool operator()(const Combo *a, std::string const& b) {
return a->Str() < b;
}
std::string Combo::StrMenu() const {
return Str();
}
void Hotkey::ComboInsert(Combo const& combo) {
str_map.insert(make_pair(combo.Str(), combo));
cmd_map.insert(make_pair(combo.CmdName(), combo));
bool operator()(std::string const& a, const Combo *b) {
return a < b->Str();
}
};
}
Hotkey::Hotkey(fs::path const& file, std::pair<const char *, size_t> default_config)
@ -52,85 +49,84 @@ Hotkey::Hotkey(fs::path const& file, std::pair<const char *, size_t> default_con
auto root = json_util::file(config_file, default_config);
for (auto const& hotkey_context : static_cast<json::Object const&>(root))
BuildHotkey(hotkey_context.first, hotkey_context.second);
UpdateStrMap();
}
void Hotkey::BuildHotkey(std::string const& context, json::Object const& hotkeys) {
for (auto const& command : hotkeys) {
const json::Array& command_hotkeys = command.second;
json::Array const& command_hotkeys = command.second;
for (json::Object const& hotkey : command_hotkeys) {
std::vector<std::string> keys;
auto it = hotkey.find("modifiers");
if (it == end(hotkey)) {
auto mod_it = hotkey.find("modifiers");
if (mod_it == end(hotkey)) {
LOG_E("agi/hotkey/load") << "Hotkey for command '" << command.first << "' is missing modifiers";
continue;
}
json::Array const& arr_mod = it->second;
keys.reserve(arr_mod.size() + 1);
copy(arr_mod.begin(), arr_mod.end(), back_inserter(keys));
it = hotkey.find("key");
if (it == end(hotkey)) {
auto key_it = hotkey.find("key");
if (key_it == end(hotkey)) {
LOG_E("agi/hotkey/load") << "Hotkey for command '" << command.first << "' is missing the key";
continue;
}
keys.push_back(it->second);
ComboInsert(Combo(context, command.first, keys));
std::string key_str;
json::Array const& arr_mod = mod_it->second;
for (std::string const& mod : arr_mod) {
key_str += mod;
key_str += '-';
}
key_str += static_cast<std::string const&>(key_it->second);
cmd_map.insert(make_pair(command.first, Combo(context, command.first, std::move(key_str))));
}
}
}
std::string Hotkey::Scan(const std::string &context, const std::string &str, bool always) const {
std::string local, dfault;
std::string Hotkey::Scan(std::string const& context, std::string const& str, bool always) const {
const std::string *local = nullptr, *dfault = nullptr;
HotkeyMap::const_iterator index, end;
for (std::tie(index, end) = str_map.equal_range(str); index != end; ++index) {
std::string const& ctext = index->second.Context();
std::vector<const Combo *>::const_iterator index, end;
for (std::tie(index, end) = boost::equal_range(str_map, str, combo_cmp()); index != end; ++index) {
std::string const& ctext = (*index)->Context();
if (always && ctext == "Always") {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Always Command: " << index->second.CmdName();
return index->second.CmdName();
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Always Command: " << (*index)->CmdName();
return (*index)->CmdName();
}
if (ctext == "Default")
dfault = index->second.CmdName();
dfault = &(*index)->CmdName();
else if (ctext == context)
local = index->second.CmdName();
local = &(*index)->CmdName();
}
if (!local.empty()) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context: " << context << " Command: " << local;
return local;
if (local) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context: " << context << " Command: " << *local;
return *local;
}
if (!dfault.empty()) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Default Command: " << dfault;
return dfault;
if (dfault) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Default Command: " << *dfault;
return *dfault;
}
return "";
}
bool Hotkey::HasHotkey(const std::string &context, const std::string &str) const {
HotkeyMap::const_iterator index, end;
for (std::tie(index, end) = str_map.equal_range(str); index != end; ++index) {
std::string const& ctext = index->second.Context();
if (ctext == context)
bool Hotkey::HasHotkey(std::string const& context, std::string const& str) const {
std::vector<const Combo *>::const_iterator index, end;
for (std::tie(index, end) = boost::equal_range(str_map, str, combo_cmp()); index != end; ++index) {
if (context == (*index)->Context())
return true;
}
return false;
}
std::vector<std::string> Hotkey::GetHotkeys(const std::string &context, const std::string &command) const {
std::vector<std::string> Hotkey::GetHotkeys(std::string const& context, std::string const& command) const {
std::vector<std::string> ret;
HotkeyMap::const_iterator it, end;
for (std::tie(it, end) = cmd_map.equal_range(command); it != end; ++it) {
std::string ctext = it->second.Context();
std::string const& ctext = it->second.Context();
if (ctext == "Always" || ctext == "Default" || ctext == context)
ret.emplace_back(it->second.StrMenu());
ret.emplace_back(it->second.Str());
}
sort(ret.begin(), ret.end());
@ -139,16 +135,16 @@ std::vector<std::string> Hotkey::GetHotkeys(const std::string &context, const st
return ret;
}
std::string Hotkey::GetHotkey(const std::string &context, const std::string &command) const {
std::string Hotkey::GetHotkey(std::string const& context, std::string const& command) const {
std::string ret;
HotkeyMap::const_iterator it, end;
for (std::tie(it, end) = cmd_map.equal_range(command); it != end; ++it) {
std::string ctext = it->second.Context();
if (ctext == context) return it->second.StrMenu();
std::string const& ctext = it->second.Context();
if (ctext == context) return it->second.Str();
if (ctext == "Default")
ret = it->second.StrMenu();
ret = it->second.Str();
else if (ret.empty() && ctext == "Always")
ret = it->second.StrMenu();
ret = it->second.Str();
}
return ret;
}
@ -156,16 +152,21 @@ std::string Hotkey::GetHotkey(const std::string &context, const std::string &com
void Hotkey::Flush() {
json::Object root;
for (auto const& combo : str_map | boost::adaptors::map_values) {
for (auto const& combo : str_map) {
auto keys = combo->Str();
if (keys.empty()) continue;
json::Object hotkey;
if (combo.Get().size()) {
hotkey["key"] = combo.Get().back();
json::Array& modifiers = hotkey["modifiers"];
modifiers.insert(modifiers.end(), combo.Get().begin(), combo.Get().end() - 1);
json::Array& modifiers = hotkey["modifiers"];
for (auto tok : agi::Split(keys, '-')) {
if (end(tok) == end(keys))
hotkey.insert(make_pair("key", agi::str(tok)));
else
modifiers.push_back(agi::str(tok));
}
json::Object& context = root[combo.Context()];
json::Array& combo_array = context[combo.CmdName()];
json::Object& context = root[combo->Context()];
json::Array& combo_array = context[combo->CmdName()];
combo_array.push_back(std::move(hotkey));
}
@ -173,16 +174,20 @@ void Hotkey::Flush() {
JsonWriter::Write(root, file.Get());
}
void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) {
cmd_map = new_map;
void Hotkey::UpdateStrMap() {
str_map.clear();
for (auto const& combo : cmd_map | boost::adaptors::map_values)
str_map.insert(make_pair(combo.Str(), combo));
str_map.reserve(cmd_map.size());
for (auto const& combo : cmd_map)
str_map.push_back(&combo.second);
sort(begin(str_map), end(str_map), combo_cmp());
}
void Hotkey::SetHotkeyMap(HotkeyMap new_map) {
cmd_map = std::move(new_map);
UpdateStrMap();
Flush();
HotkeysChanged();
}
} // namespace toolbar
} // namespace agi
} }

View File

@ -12,10 +12,6 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/// @file hotkey.h
/// @brief Hotkey handler
/// @ingroup hotkey menu event window
#include <boost/filesystem/path.hpp>
#include <map>
#include <string>
@ -36,39 +32,31 @@ namespace agi {
/// A Combo represents a linear sequence of characters set in an std::vector.
/// This makes up a single combination, or "Hotkey".
class Combo {
std::vector<std::string> key_map;
std::string keys;
std::string cmd_name;
std::string context;
public:
/// Constructor
/// @param ctx Context
/// @param cmd Command name
Combo(std::string ctx, std::string cmd, std::vector<std::string> keys)
: key_map(std::move(keys))
Combo(std::string ctx, std::string cmd, std::string keys)
: keys(std::move(keys))
, cmd_name(std::move(cmd))
, context(std::move(ctx))
{
}
/// String representation of the Combo
std::string Str() const;
/// String suitable for usage in a menu.
std::string StrMenu() const;
/// Get the literal combo map.
/// @return ComboMap (std::vector) of linear key sequence.
const std::vector<std::string>& Get() const { return key_map; }
std::string Str() const { return keys; }
/// Command name triggered by the combination.
/// @return Command name
const std::string& CmdName() const { return cmd_name; }
std::string const& CmdName() const { return cmd_name; }
/// Context this Combo is triggered in.
const std::string& Context() const { return context; }
std::string const& Context() const { return context; }
};
/// @class Hotkey
/// Holds the map of Combo instances and handles searching for matching key sequences.
class Hotkey {
@ -76,22 +64,20 @@ public:
/// Map to hold Combo instances
typedef std::multimap<std::string, Combo> HotkeyMap;
private:
HotkeyMap str_map; ///< String representation -> Combo
HotkeyMap cmd_map; ///< Command name -> Combo
const agi::fs::path config_file; ///< Default user config location.
HotkeyMap cmd_map; ///< Command name -> Combo
std::vector<const Combo *> str_map; ///< Sorted by string representation
const agi::fs::path config_file; ///< Default user config location.
/// Build hotkey map.
/// @param context Context being parsed.
/// @param object json::Object holding items for context being parsed.
void BuildHotkey(std::string const& context, const json::Object& object);
/// Insert Combo into HotkeyMap instance.
/// @param combo Combo to insert.
void ComboInsert(Combo const& combo);
/// Write active Hotkey configuration to disk.
void Flush();
void UpdateStrMap();
/// Announce that the loaded hotkeys have been changed
agi::signal::Signal<> HotkeysChanged;
public:
@ -129,7 +115,7 @@ public:
HotkeyMap const& GetHotkeyMap() const { return cmd_map; }
/// Replace the loaded hotkeys with a new set
void SetHotkeyMap(HotkeyMap const& new_map);
void SetHotkeyMap(HotkeyMap new_map);
DEFINE_SIGNAL_ADDERS(HotkeysChanged, AddHotkeyChangeListener)
};

View File

@ -12,10 +12,6 @@
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/// @file hotkey.cpp
/// @brief Hotkey handler
/// @ingroup hotkey menu event window
#include <libaegisub/hotkey.h>
#include "include/aegisub/hotkey.h"
@ -33,42 +29,40 @@
#include <wx/msgdlg.h>
namespace {
const char *added_hotkeys_7035[][5] = {
{ "audio/play/line", "Audio", "R", nullptr, nullptr },
{ nullptr }
const char *added_hotkeys_7035[][3] = {
{"audio/play/line", "Audio", "R"},
{nullptr}
};
const char *added_hotkeys_7070[][5] = {
{ "edit/color/primary", "Subtitle Edit Box", "Alt", "1", nullptr },
{ "edit/color/secondary", "Subtitle Edit Box", "Alt", "2", nullptr },
{ "edit/color/outline", "Subtitle Edit Box", "Alt", "3", nullptr },
{ "edit/color/shadow", "Subtitle Edit Box", "Alt", "4", nullptr },
{ nullptr }
const char *added_hotkeys_7070[][3] = {
{"edit/color/primary", "Subtitle Edit Box", "Alt-1"},
{"edit/color/secondary", "Subtitle Edit Box", "Alt-2"},
{"edit/color/outline", "Subtitle Edit Box", "Alt-3"},
{"edit/color/shadow", "Subtitle Edit Box", "Alt-4"},
{nullptr}
};
const char *added_hotkeys_shift_back[][5] = {
{ "edit/line/duplicate/shift_back", "Default", "Ctrl", "Shift", "D" },
{ nullptr }
const char *added_hotkeys_shift_back[][3] = {
{"edit/line/duplicate/shift_back", "Default", "Ctrl-Shift-D"},
{nullptr}
};
void migrate_hotkeys(const char *added[][5]) {
agi::hotkey::Hotkey::HotkeyMap hk_map = hotkey::inst->GetHotkeyMap();
void migrate_hotkeys(const char *added[][3]) {
auto hk_map = hotkey::inst->GetHotkeyMap();
bool changed = false;
for (size_t i = 0; added[i] && added[i][0]; ++i) {
std::vector<std::string> keys;
for (size_t j = 2; j < 5; ++j) {
if (added[i][j])
keys.emplace_back(added[i][j]);
}
agi::hotkey::Combo combo(added[i][1], added[i][0], keys);
agi::hotkey::Combo combo(added[i][1], added[i][0], added[i][2]);
if (hotkey::inst->HasHotkey(combo.Context(), combo.Str()))
continue;
hk_map.insert(make_pair(std::string(added[i][0]), combo));
hk_map.insert(make_pair(std::string(added[i][0]), std::move(combo)));
changed = true;
}
hotkey::inst->SetHotkeyMap(hk_map);
if (changed)
hotkey::inst->SetHotkeyMap(std::move(hk_map));
}
}
@ -100,18 +94,18 @@ void init() {
if (boost::find(migrations, "duplicate -> split") == end(migrations)) {
auto hk_map = hotkey::inst->GetHotkeyMap();
for (auto const& hotkey : boost::make_iterator_range(hk_map.equal_range("edit/line/duplicate/shift"))) {
auto combo = agi::hotkey::Combo(hotkey.second.Context(), "edit/line/split/before", hotkey.second.Get());
auto combo = agi::hotkey::Combo(hotkey.second.Context(), "edit/line/split/before", hotkey.second.Str());
hk_map.insert({combo.CmdName(), combo});
}
for (auto const& hotkey : boost::make_iterator_range(hk_map.equal_range("edit/line/duplicate/shift_back"))) {
auto combo = agi::hotkey::Combo(hotkey.second.Context(), "edit/line/split/after", hotkey.second.Get());
auto combo = agi::hotkey::Combo(hotkey.second.Context(), "edit/line/split/after", hotkey.second.Str());
hk_map.insert({combo.CmdName(), combo});
}
hk_map.erase("edit/line/duplicate/shift");
hk_map.erase("edit/line/duplicate/shift_back");
hotkey::inst->SetHotkeyMap(hk_map);
hotkey::inst->SetHotkeyMap(std::move(hk_map));
migrations.emplace_back("duplicate -> split");
}
@ -122,20 +116,95 @@ void clear() {
delete inst;
}
static std::vector<std::string> keycode_names;
static void init_keycode_names();
static std::string const& keycode_name(int code) {
if (keycode_names.empty())
init_keycode_names();
if (static_cast<size_t>(code) > keycode_names.size()) {
static std::string str;
return str;
static const char *keycode_name(int code) {
switch (code) {
case WXK_BACK: return "Backspace";
case WXK_TAB: return "Tab";
case WXK_RETURN: return "Enter";
case WXK_ESCAPE: return "Escape";
case WXK_SPACE: return "Space";
case WXK_DELETE: return "Delete";
case WXK_SHIFT: return "Shift";
case WXK_ALT: return "Alt";
case WXK_CONTROL: return "Control";
case WXK_PAUSE: return "Pause";
case WXK_END: return "End";
case WXK_HOME: return "Home";
case WXK_LEFT: return "Left";
case WXK_UP: return "Up";
case WXK_RIGHT: return "Right";
case WXK_DOWN: return "Down";
case WXK_PRINT: return "Print";
case WXK_INSERT: return "Insert";
case WXK_NUMPAD0: return "KP_0";
case WXK_NUMPAD1: return "KP_1";
case WXK_NUMPAD2: return "KP_2";
case WXK_NUMPAD3: return "KP_3";
case WXK_NUMPAD4: return "KP_4";
case WXK_NUMPAD5: return "KP_5";
case WXK_NUMPAD6: return "KP_6";
case WXK_NUMPAD7: return "KP_7";
case WXK_NUMPAD8: return "KP_8";
case WXK_NUMPAD9: return "KP_9";
case WXK_MULTIPLY: return "Asterisk";
case WXK_ADD: return "Plus";
case WXK_SUBTRACT: return "Hyphen";
case WXK_DECIMAL: return "Period";
case WXK_DIVIDE: return "Slash";
case WXK_F1: return "F1";
case WXK_F2: return "F2";
case WXK_F3: return "F3";
case WXK_F4: return "F4";
case WXK_F5: return "F5";
case WXK_F6: return "F6";
case WXK_F7: return "F7";
case WXK_F8: return "F8";
case WXK_F9: return "F9";
case WXK_F10: return "F10";
case WXK_F11: return "F11";
case WXK_F12: return "F12";
case WXK_F13: return "F13";
case WXK_F14: return "F14";
case WXK_F15: return "F15";
case WXK_F16: return "F16";
case WXK_F17: return "F17";
case WXK_F18: return "F18";
case WXK_F19: return "F19";
case WXK_F20: return "F20";
case WXK_F21: return "F21";
case WXK_F22: return "F22";
case WXK_F23: return "F23";
case WXK_F24: return "F24";
case WXK_NUMLOCK: return "Num_Lock";
case WXK_SCROLL: return "Scroll_Lock";
case WXK_PAGEUP: return "PageUp";
case WXK_PAGEDOWN: return "PageDown";
case WXK_NUMPAD_SPACE: return "KP_Space";
case WXK_NUMPAD_TAB: return "KP_Tab";
case WXK_NUMPAD_ENTER: return "KP_Enter";
case WXK_NUMPAD_F1: return "KP_F1";
case WXK_NUMPAD_F2: return "KP_F2";
case WXK_NUMPAD_F3: return "KP_F3";
case WXK_NUMPAD_F4: return "KP_F4";
case WXK_NUMPAD_HOME: return "KP_Home";
case WXK_NUMPAD_LEFT: return "KP_Left";
case WXK_NUMPAD_UP: return "KP_Up";
case WXK_NUMPAD_RIGHT: return "KP_Right";
case WXK_NUMPAD_DOWN: return "KP_Down";
case WXK_NUMPAD_PAGEUP: return "KP_PageUp";
case WXK_NUMPAD_PAGEDOWN: return "KP_PageDown";
case WXK_NUMPAD_END: return "KP_End";
case WXK_NUMPAD_BEGIN: return "KP_Begin";
case WXK_NUMPAD_INSERT: return "KP_insert";
case WXK_NUMPAD_DELETE: return "KP_Delete";
case WXK_NUMPAD_EQUAL: return "KP_Equal";
case WXK_NUMPAD_MULTIPLY: return "KP_Multiply";
case WXK_NUMPAD_ADD: return "KP_Add";
case WXK_NUMPAD_SUBTRACT: return "KP_Subtract";
case WXK_NUMPAD_DECIMAL: return "KP_Decimal";
case WXK_NUMPAD_DIVIDE: return "KP_Divide";
default: return "";
}
return keycode_names[code];
}
std::string keypress_to_str(int key_code, int modifier) {
@ -146,7 +215,10 @@ std::string keypress_to_str(int key_code, int modifier) {
if ((modifier & wxMOD_SHIFT) != 0) combo.append("Shift-");
}
combo += keycode_name(key_code);
if (key_code < 127)
combo += (char)key_code;
else
combo += keycode_name(key_code);
return combo;
}
@ -186,102 +258,4 @@ std::string get_hotkey_str_first(std::string const& context, std::string const&
return inst->GetHotkey(context, command);
}
static inline void set_kc(std::vector<std::string> &vec, int code, std::string const& str) {
if (static_cast<size_t>(code) >= vec.size()) vec.resize(code * 2, "");
vec[code] = str;
}
static void init_keycode_names() {
char str[] = { 0, 0 };
for (char i = 33; i < 127; ++i) {
str[0] = i;
set_kc(keycode_names, i, str);
}
set_kc(keycode_names, WXK_BACK, "Backspace");
set_kc(keycode_names, WXK_TAB, "Tab");
set_kc(keycode_names, WXK_RETURN, "Enter");
set_kc(keycode_names, WXK_ESCAPE, "Escape");
set_kc(keycode_names, WXK_SPACE, "Space");
set_kc(keycode_names, WXK_DELETE, "Delete");
set_kc(keycode_names, WXK_SHIFT, "Shift");
set_kc(keycode_names, WXK_ALT, "Alt");
set_kc(keycode_names, WXK_CONTROL, "Control");
set_kc(keycode_names, WXK_PAUSE, "Pause");
set_kc(keycode_names, WXK_END, "End");
set_kc(keycode_names, WXK_HOME, "Home");
set_kc(keycode_names, WXK_LEFT, "Left");
set_kc(keycode_names, WXK_UP, "Up");
set_kc(keycode_names, WXK_RIGHT, "Right");
set_kc(keycode_names, WXK_DOWN, "Down");
set_kc(keycode_names, WXK_PRINT, "Print");
set_kc(keycode_names, WXK_INSERT, "Insert");
set_kc(keycode_names, WXK_NUMPAD0, "KP_0");
set_kc(keycode_names, WXK_NUMPAD1, "KP_1");
set_kc(keycode_names, WXK_NUMPAD2, "KP_2");
set_kc(keycode_names, WXK_NUMPAD3, "KP_3");
set_kc(keycode_names, WXK_NUMPAD4, "KP_4");
set_kc(keycode_names, WXK_NUMPAD5, "KP_5");
set_kc(keycode_names, WXK_NUMPAD6, "KP_6");
set_kc(keycode_names, WXK_NUMPAD7, "KP_7");
set_kc(keycode_names, WXK_NUMPAD8, "KP_8");
set_kc(keycode_names, WXK_NUMPAD9, "KP_9");
set_kc(keycode_names, WXK_MULTIPLY, "Asterisk");
set_kc(keycode_names, WXK_ADD, "Plus");
set_kc(keycode_names, WXK_SUBTRACT, "Hyphen");
set_kc(keycode_names, WXK_DECIMAL, "Period");
set_kc(keycode_names, WXK_DIVIDE, "Slash");
set_kc(keycode_names, WXK_F1, "F1");
set_kc(keycode_names, WXK_F2, "F2");
set_kc(keycode_names, WXK_F3, "F3");
set_kc(keycode_names, WXK_F4, "F4");
set_kc(keycode_names, WXK_F5, "F5");
set_kc(keycode_names, WXK_F6, "F6");
set_kc(keycode_names, WXK_F7, "F7");
set_kc(keycode_names, WXK_F8, "F8");
set_kc(keycode_names, WXK_F9, "F9");
set_kc(keycode_names, WXK_F10, "F10");
set_kc(keycode_names, WXK_F11, "F11");
set_kc(keycode_names, WXK_F12, "F12");
set_kc(keycode_names, WXK_F13, "F13");
set_kc(keycode_names, WXK_F14, "F14");
set_kc(keycode_names, WXK_F15, "F15");
set_kc(keycode_names, WXK_F16, "F16");
set_kc(keycode_names, WXK_F17, "F17");
set_kc(keycode_names, WXK_F18, "F18");
set_kc(keycode_names, WXK_F19, "F19");
set_kc(keycode_names, WXK_F20, "F20");
set_kc(keycode_names, WXK_F21, "F21");
set_kc(keycode_names, WXK_F22, "F22");
set_kc(keycode_names, WXK_F23, "F23");
set_kc(keycode_names, WXK_F24, "F24");
set_kc(keycode_names, WXK_NUMLOCK, "Num_Lock");
set_kc(keycode_names, WXK_SCROLL, "Scroll_Lock");
set_kc(keycode_names, WXK_PAGEUP, "PageUp");
set_kc(keycode_names, WXK_PAGEDOWN, "PageDown");
set_kc(keycode_names, WXK_NUMPAD_SPACE, "KP_Space");
set_kc(keycode_names, WXK_NUMPAD_TAB, "KP_Tab");
set_kc(keycode_names, WXK_NUMPAD_ENTER, "KP_Enter");
set_kc(keycode_names, WXK_NUMPAD_F1, "KP_F1");
set_kc(keycode_names, WXK_NUMPAD_F2, "KP_F2");
set_kc(keycode_names, WXK_NUMPAD_F3, "KP_F3");
set_kc(keycode_names, WXK_NUMPAD_F4, "KP_F4");
set_kc(keycode_names, WXK_NUMPAD_HOME, "KP_Home");
set_kc(keycode_names, WXK_NUMPAD_LEFT, "KP_Left");
set_kc(keycode_names, WXK_NUMPAD_UP, "KP_Up");
set_kc(keycode_names, WXK_NUMPAD_RIGHT, "KP_Right");
set_kc(keycode_names, WXK_NUMPAD_DOWN, "KP_Down");
set_kc(keycode_names, WXK_NUMPAD_PAGEUP, "KP_PageUp");
set_kc(keycode_names, WXK_NUMPAD_PAGEDOWN, "KP_PageDown");
set_kc(keycode_names, WXK_NUMPAD_END, "KP_End");
set_kc(keycode_names, WXK_NUMPAD_BEGIN, "KP_Begin");
set_kc(keycode_names, WXK_NUMPAD_INSERT, "KP_insert");
set_kc(keycode_names, WXK_NUMPAD_DELETE, "KP_Delete");
set_kc(keycode_names, WXK_NUMPAD_EQUAL, "KP_Equal");
set_kc(keycode_names, WXK_NUMPAD_MULTIPLY, "KP_Multiply");
set_kc(keycode_names, WXK_NUMPAD_ADD, "KP_Add");
set_kc(keycode_names, WXK_NUMPAD_SUBTRACT, "KP_Subtract");
set_kc(keycode_names, WXK_NUMPAD_DECIMAL, "KP_Decimal");
set_kc(keycode_names, WXK_NUMPAD_DIVIDE, "KP_Divide");
}
} // namespace hotkey

View File

@ -24,7 +24,6 @@
#include <libaegisub/exception.h>
#include <libaegisub/hotkey.h>
#include <libaegisub/make_unique.h>
#include <libaegisub/split.h>
#include <algorithm>
#include <boost/algorithm/string/case_conv.hpp>
@ -111,11 +110,7 @@ public:
bool SetValue(wxVariant const& variant, unsigned int col) override {
if (col == 0) {
std::vector<std::string> keys;
auto str = from_wx(variant.GetString());
for (auto tok : agi::Split(str, '-'))
keys.emplace_back(begin(tok), end(tok));
combo = Combo(combo.Context(), combo.CmdName(), keys);
combo = Combo(combo.Context(), combo.CmdName(), from_wx(variant.GetString()));
cmd_str = combo.Str();
return true;
}
@ -123,7 +118,7 @@ public:
wxDataViewIconText text;
text << variant;
cmd_name = from_wx(text.GetText());
combo = Combo(combo.Context(), cmd_name, combo.Get());
combo = Combo(combo.Context(), cmd_name, combo.Str());
return true;
}
return false;
@ -307,7 +302,7 @@ wxDataViewItem HotkeyDataViewModel::New(wxDataViewItem item) {
HotkeyModelCategory *ctx = static_cast<HotkeyModelCategory*>(item.GetID());
wxVariant name;
ctx->GetValue(name, 0);
return ctx->AddChild(Combo(from_wx(name.GetString()), "", std::vector<std::string>()));
return ctx->AddChild(Combo(from_wx(name.GetString()), "", ""));
}
void HotkeyDataViewModel::Delete(wxDataViewItem const& item) {

View File

@ -17,15 +17,13 @@
#include <libaegisub/fs.h>
#include <libaegisub/hotkey.h>
#include <cstdarg>
using namespace agi::hotkey;
static const char simple_valid[] = "{"
"\"Always\":{\"cmd1\":[{\"modifiers\":[\"Ctrl\"], \"key\":\"C\"}]},"
"\"Default\":{\"cmd1\":[{\"modifiers\":[\"Alt\"], \"key\":\"C\"}], \"cmd2\":[{\"modifiers\":[\"Ctrl\"], \"key\":\"C\"}]},"
"\"Other\":{\"cmd1\":[{\"modifiers\":[\"Shift\"], \"key\":\"C\"}], \"cmd3\":[{\"modifiers\":[], \"key\":\"Q\"}]}"
"}";
static const char simple_valid[] = R"raw({
"Always":{"cmd1":[{"modifiers":["Ctrl"], "key":"C"}]},
"Default":{"cmd1":[{"modifiers":["Alt"], "key":"C"}], "cmd2":[{"modifiers":["Ctrl"], "key":"C"}]},
"Other":{"cmd1":[{"modifiers":["Shift"], "key":"C"}], "cmd3":[{"modifiers":[], "key":"Q"}]}
})raw";
TEST(lagi_hotkey, simple_valid_default) {
EXPECT_NO_THROW(Hotkey("", simple_valid));
@ -137,20 +135,18 @@ TEST(lagi_hotkey, get_hotkeys) {
EXPECT_EQ(0, h.GetHotkeys("Nonexistent", "cmd4").size());
}
TEST(lagi_hotkey, has_hotkey) {
Hotkey h("", simple_valid);
EXPECT_TRUE(h.HasHotkey("Always", "Ctrl-C"));
EXPECT_FALSE(h.HasHotkey("Always", "Alt-C"));
}
TEST(lagi_hotkey, get_hotkeys_dedups) {
Hotkey h("", "{\"Always\":{\"cmd1\":[{\"modifiers\":[\"Ctrl\"], \"key\":\"C\"}]},\"Default\":{\"cmd1\":[{\"modifiers\":[\"Ctrl\"], \"key\":\"C\"}]}}");
EXPECT_EQ(1, h.GetHotkeys("Always", "cmd1").size());
}
static void insert_combo(Hotkey::HotkeyMap &hm, const char *ctx, const char *cmd, int N, ...) {
std::vector<std::string> keys(N);
va_list argp;
va_start(argp, N);
for (int i = 0; i < N; ++i)
keys[i] = va_arg(argp, const char *);
va_end(argp);
static void insert_combo(Hotkey::HotkeyMap &hm, const char *ctx, const char *cmd, const char *keys) {
hm.insert(make_pair(std::string(cmd), Combo(ctx, cmd, keys)));
}
@ -162,8 +158,8 @@ TEST(lagi_hotkey, set_hotkey_map) {
Hotkey::HotkeyMap hm = h.GetHotkeyMap();
EXPECT_EQ(0, hm.size());
insert_combo(hm, "Always", "cmd1", 1, "C");
insert_combo(hm, "Default", "cmd2", 2, "Shift", "C");
insert_combo(hm, "Always", "cmd1", "C");
insert_combo(hm, "Default", "cmd2", "Shift-C");
bool listener_called = false;
h.AddHotkeyChangeListener([&] { listener_called = true; });
@ -189,8 +185,7 @@ TEST(lagi_hotkey, combo_stuff) {
ASSERT_EQ(1, std::distance(it, end));
Combo c = it->second;
EXPECT_STREQ("Ctrl-C", c.StrMenu().c_str());
EXPECT_STREQ("Ctrl-C", c.Str().c_str());
EXPECT_STREQ("cmd2", c.CmdName().c_str());
EXPECT_STREQ("Default", c.Context().c_str());
EXPECT_EQ(2, c.Get().size());
}