#include "profile/keybinds.h" #include "main/logging.h" #include "os/key_consts.h" #include "str_util.h" #include "main/references.h" #include "main/input_handling.h" #include #include namespace profile { void BindGroup::clear() { clearPressedKeys(); foreach(bind, descriptors) delete bind->bind; descriptors.clear(); descriptorIDs.clear(); binds.clear(); } BindGroup::~BindGroup() { clear(); } Keybinds::Keybinds() { global.name = "Global"; groups.push_back(&global); groupNames["Global"] = &global; } void Keybinds::clear() { clearPressedKeys(); global.clear(); foreach(it, groups) { if(*it != &global) delete *it; } groups.clear(); groupNames.clear(); groups.push_back(&global); groupNames["Global"] = &global; } void Keybinds::loadBinds(const std::string& filename) { DataReader datafile(filename); BindGroup* grp = &global; while(datafile++) { if(datafile.key == "Group") { auto it = groupNames.find(datafile.value); if(it != groupNames.end()) { grp = it->second; } continue; } int key = getKey(datafile.key); if(datafile.value == "-") { grp->clearBind(key); } else { auto it = grp->descriptorIDs.find(datafile.value); if(it != grp->descriptorIDs.end()) grp->setBind(key, it->second); } } } void Keybinds::saveBinds(const std::string& filename) { std::ofstream file(filename); foreach(it, groups) { BindGroup* grp = *it; std::unordered_set writtenKeys; file << "Group: " << grp->name << "\n"; //Set all the binds we have foreach(it, grp->binds) { BindDescriptor& desc = grp->descriptors[it->second]; std::string line = getKeyName(it->first); line += ": "; line += desc.name; line += "\n"; file << line; writtenKeys.insert(it->first); } //Clear out all default binds we no longer have foreach(it, grp->descriptors) { BindDescriptor& desc = *it; foreach(k, desc.defaults) { int key = *k; if(writtenKeys.find(key) == writtenKeys.end()) { file << "\t" << getKeyName(key) << ": -\n"; writtenKeys.insert(key); } } } file << "\n"; } file.close(); } BindGroup* Keybinds::getGroup(const std::string& name) { auto it = groupNames.find(name); if(it == groupNames.end()) return 0; return it->second; } void Keybinds::loadDescriptors(const std::string& filename) { BindGroup* grp = &global; DataReader datafile(filename); while(datafile++) { if(datafile.key == "Group") { if(datafile.value == "Global") { grp = &global; } else { grp = new BindGroup(); grp->name = datafile.value; groups.push_back(grp); groupNames[grp->name] = grp; } continue; } if(grp->descriptorIDs.find(datafile.key) != grp->descriptorIDs.end()) continue; BindDescriptor bind; bind.name = datafile.key; bind.bind = 0; if(datafile.value != "-" && !datafile.value.empty()) { std::vector keys; split(datafile.value, keys, ','); foreach(key, keys) { if(int num = getKey(*key)) bind.defaults.push_back(num); } } grp->addDescriptor(bind); } } void Keybinds::setDefaultBinds() { foreach(it, groups) (*it)->setDefaultBinds(); } void BindGroup::addDescriptor(BindDescriptor desc) { desc.id = (int)descriptors.size(); descriptors.push_back(desc); descriptorIDs[desc.name] = desc.id; } void BindGroup::addBind(const std::string& name, Keybind* bind) { auto it = descriptorIDs.find(name); if(it == descriptorIDs.end()) { error(std::string("Error (addBind): Could not find keybind with name: ")+name); return; } BindDescriptor& desc = descriptors[it->second]; clearPressedKeys(); delete desc.bind; desc.bind = bind; } void BindGroup::addBind(unsigned id, Keybind* bind) { if(id >= (unsigned)descriptors.size()) { error(std::string("Error (addBind): Descriptor id out of range: ")+toString(id)); return; } BindDescriptor& desc = descriptors[id]; clearPressedKeys(); delete desc.bind; desc.bind = bind; } void BindGroup::setBind(int key, const std::string& name) { auto it = descriptorIDs.find(name); if(it == descriptorIDs.end()) { error(std::string("Error (setBind): Could not find keybind with name: ")+name); return; } setBind(key, it->second); } void BindGroup::setBind(int key, unsigned id) { if(id >= descriptors.size()) { error(std::string("Error (setBind): Descriptor id out of range: ")+toString(id)); return; } clearBind(key); binds[key] = id; descriptors[id].current.push_back(key); } void BindGroup::clearBind(int key) { auto it = binds.find(key); if(it != binds.end()) { if(it->second < (int)descriptors.size()) { foreach(kb, descriptors[it->second].current) { if(*kb == key) { descriptors[it->second].current.erase(kb); break; } } } binds.erase(it); } } void BindGroup::setDefaultBinds() { for(unsigned i = 0; i < descriptors.size(); ++i) { foreach(key, descriptors[i].defaults) setBind(*key, i); } } BindDescriptor* BindGroup::getDescriptor(const std::string& name) { auto it = descriptorIDs.find(name); if(it == descriptorIDs.end()) return 0; return &descriptors[it->second]; } Keybind* BindGroup::getBind(int key) { auto it = binds.find(key); if(it == binds.end()) { //SPECIAL: Try it without shift if(key & Mod_Shift) { key &= ~Mod_Shift; it = binds.find(key); if(it == binds.end()) return 0; } else { return 0; } } return descriptors[it->second].bind; } int BindGroup::getBindID(int key) { auto it = binds.find(key); if(it == binds.end()) { //SPECIAL: Try it without shift if(key & Mod_Shift) { key &= ~Mod_Shift; it = binds.find(key); if(it == binds.end()) return -1; } else { return -1; } } return descriptors[it->second].id; } unsigned BindGroup::getDefaultCount(unsigned id) { if(id >= descriptors.size()) { error("Error (getDefaultCount): Descriptor id out of range: %d", id); return 0; } return (unsigned)descriptors[id].defaults.size(); } int BindGroup::getDefaultKey(unsigned id, unsigned index) { if(id >= descriptors.size()) { error("Error (getDefaultKey): Descriptor id out of range: %d", id); return 0; } if(index >= descriptors[id].defaults.size()) { error("Error (getDefaultKey): Key index out of range: %d", index); return 0; } return descriptors[id].defaults[index]; } unsigned BindGroup::getBindCount(unsigned id) { if(id >= descriptors.size()) { error("Error (getBindCount): Descriptor id out of range: %d", id); return 0; } return (unsigned)descriptors[id].current.size(); } int BindGroup::getBindKey(unsigned id, unsigned index) { if(id >= descriptors.size()) { error("Error (getBindKey): Descriptor id out of range: %d", id); return 0; } if(index >= descriptors[id].current.size()) { error("Error (getBindKey): Key index out of range: %d", index); return 0; } return descriptors[id].current[index]; } void BindGroup::clearBinds(unsigned id) { if(id >= descriptors.size()) { error("Error (clearBinds): Descriptor id out of range: %d", id); return; } foreach(it, descriptors[id].current) binds.erase(*it); descriptors[id].current.clear(); } void BindGroup::setDefaultBinds(unsigned id) { if(id >= descriptors.size()) { error("Error (setDefaultBinds): Descriptor id out of range: %d", id); return; } clearBinds(id); foreach(it, descriptors[id].defaults) setBind(*it, id); } std::unordered_map keyNames; std::unordered_map keyValues; #define keyName(name, value)\ keyNames[name] = value;\ keyValues[value] = name; bool init_keyNames = true; inline void initKeyNames() { if(init_keyNames) { init_keyNames = false; keyName("esc", os::KEY_ESC); keyName("f1", os::KEY_F1); keyName("f2", os::KEY_F2); keyName("f3", os::KEY_F3); keyName("f4", os::KEY_F4); keyName("f5", os::KEY_F5); keyName("f6", os::KEY_F6); keyName("f7", os::KEY_F7); keyName("f8", os::KEY_F8); keyName("f9", os::KEY_F9); keyName("f10", os::KEY_F10); keyName("f11", os::KEY_F11); keyName("f12", os::KEY_F12); keyName("f13", os::KEY_F13); keyName("f14", os::KEY_F14); keyName("f15", os::KEY_F15); keyName("f16", os::KEY_F16); keyName("f17", os::KEY_F17); keyName("f18", os::KEY_F18); keyName("f19", os::KEY_F19); keyName("f20", os::KEY_F20); keyName("f21", os::KEY_F21); keyName("f22", os::KEY_F22); keyName("f23", os::KEY_F23); keyName("f24", os::KEY_F24); keyName("f25", os::KEY_F25); keyName("up", os::KEY_UP); keyName("down", os::KEY_DOWN); keyName("left", os::KEY_LEFT); keyName("right", os::KEY_RIGHT); keyName("lshift", os::KEY_LSHIFT); keyName("rshift", os::KEY_RSHIFT); keyName("lctrl", os::KEY_LCTRL); keyName("rctrl", os::KEY_RCTRL); keyName("lalt", os::KEY_LALT); keyName("ralt", os::KEY_RALT); keyName("tab", os::KEY_TAB); keyName("enter", os::KEY_ENTER); keyName("backspace", os::KEY_BACKSPACE); keyName("space", ' '); keyName("insert", os::KEY_INSERT); keyName("del", os::KEY_DEL); keyName("pageup", os::KEY_PAGEUP); keyName("pagedown", os::KEY_PAGEDOWN); keyName("home", os::KEY_HOME); keyName("end", os::KEY_END); keyName("kp_0", os::KEY_KP_0); keyName("kp_1", os::KEY_KP_1); keyName("kp_2", os::KEY_KP_2); keyName("kp_3", os::KEY_KP_3); keyName("kp_4", os::KEY_KP_4); keyName("kp_5", os::KEY_KP_5); keyName("kp_6", os::KEY_KP_6); keyName("kp_7", os::KEY_KP_7); keyName("kp_8", os::KEY_KP_8); keyName("kp_9", os::KEY_KP_9); keyName("kp_divide", os::KEY_KP_DIVIDE); keyName("kp_multiply", os::KEY_KP_MULTIPLY); keyName("kp_subtract", os::KEY_KP_SUBTRACT); keyName("kp_add", os::KEY_KP_ADD); keyName("kp_decimal", os::KEY_KP_DECIMAL); keyName("kp_equal", os::KEY_KP_EQUAL); keyName("kp_enter", os::KEY_KP_ENTER); keyName("num_lock", os::KEY_NUM_LOCK); keyName("caps_lock", os::KEY_CAPS_LOCK); keyName("scroll_lock", os::KEY_SCROLL_LOCK); keyName("pause", os::KEY_PAUSE); keyName("lsuper", os::KEY_LSUPER); keyName("rsuper", os::KEY_RSUPER); keyName("menu", os::KEY_MENU); } } int getKey(std::string name) { initKeyNames(); int key = 0; name = trim(name); toLowercase(name); while(!name.empty()) { if(name.compare(0, 5, "ctrl+") == 0) { name = name.substr(5, name.size() - 5); key |= Mod_Ctrl; continue; } if(name.compare(0, 4, "alt+") == 0) { name = name.substr(4, name.size() - 4); key |= Mod_Alt; continue; } if(name.compare(0, 6, "shift+") == 0) { name = name.substr(6, name.size() - 6); key |= Mod_Shift; continue; } if(name[0] == '#') { key |= toNumber(name.substr(1, name.size() - 1)); break; } auto it = keyNames.find(name); if(it != keyNames.end()) { key |= (int)it->second; break; } u8it ch(name); key |= ch++; break; } return key; } int getKeyFromDisplayName(std::string name) { initKeyNames(); int key = 0; name = trim(name); toLowercase(name); while(!name.empty()) { if(name.compare(0, 5, "ctrl+") == 0) { name = name.substr(5, name.size() - 5); key |= Mod_Ctrl; continue; } if(name.compare(0, 4, "alt+") == 0) { name = name.substr(4, name.size() - 4); key |= Mod_Alt; continue; } if(name.compare(0, 6, "shift+") == 0) { name = name.substr(6, name.size() - 6); key |= Mod_Shift; continue; } if(name[0] == '#') { key |= toNumber(name.substr(1, name.size() - 1)); break; } auto it = keyNames.find(name); if(it != keyNames.end()) { key |= (int)it->second; break; } u8it ch(name); int chr = ch++; int lookup = devices.driver->getKeyForChar(chr); if(lookup >= 'A' && lookup <= 'Z') lookup -= 'A'-'a'; if(lookup == -1) key |= chr; else key |= lookup; break; } return key; } std::string getKeyName(int key) { std::string name; if(key & Mod_Ctrl) { name += "ctrl+"; key &= ~Mod_Ctrl; } if(key & Mod_Alt) { name += "alt+"; key &= ~Mod_Alt; } if(key & Mod_Shift) { name += "shift+"; key &= ~Mod_Shift; } auto it = keyValues.find(key); if(it != keyValues.end()) { name += it->second; return name; } u8append(name, key); return name; } std::string getKeyDisplayName(int key) { std::string name; if(key & Mod_Ctrl) { name += "ctrl+"; key &= ~Mod_Ctrl; } if(key & Mod_Alt) { name += "alt+"; key &= ~Mod_Alt; } if(key & Mod_Shift) { name += "shift+"; key &= ~Mod_Shift; } auto it = keyValues.find(key); if(it != keyValues.end()) { name += it->second; return name; } int chr = devices.driver->getCharForKey(key); if(chr == -1) u8append(name, key); else u8append(name, chr); return name; } int getModifiedKey(int key, bool ctrlKey, bool altKey, bool shiftKey) { int mod_key = key; if(mod_key >= 'A' && mod_key <= 'Z') mod_key += 'a'-'A'; if(ctrlKey) mod_key |= profile::Mod_Ctrl; if(altKey) mod_key |= profile::Mod_Alt; if(shiftKey) mod_key |= profile::Mod_Shift; return mod_key; } };