//-------------------------------------------------------------------------- // Read all keyboard definitions //-------------------------------------------------------------------------- int CKeyMap::Read (SStream *stream, Tag tag) { int rc = TAG_IGNORED; switch (tag) { case 'vers': // Version ReadInt (&vers, stream); rc = TAG_READ; break; case 'kset': // KeySet sub-object { Tag ksetTag; ReadTag (&ksetTag, stream); CheckSet(ksetTag); CKeySet *ks = new CKeySet (ksetTag); ReadFrom (ks, stream); kset[ks->GetTag()] = ks; oset.push_back(ks); } rc = TAG_READ; break; } if (rc == TAG_IGNORED) { globals->logWarning->Write ("CKeyMap::Read : Unknown tag %s", TagToString(tag)); } return rc; }
//-------------------------------------------------------------------------- // Print all keys //-------------------------------------------------------------------------- void CKeyMap::Print (FILE* f) { // Iterate over keysets std::map<Tag,CKeySet*>::iterator i; for (i=kset.begin(); i!=kset.end(); i++) { CKeySet *pKeySet = i->second; // Format key set unique ID char s[8]; TagToString (s, pKeySet->GetTag()); fprintf (f, "KeySet '%s' %s\n", s, pKeySet->GetName()); // Iterate over key definitions within the keyset std::map<Tag,CKeyDefinition*>::iterator j; for (j=pKeySet->dkey.begin(); j!=pKeySet->dkey.end(); j++) { CKeyDefinition *pKeyDef = j->second; // Format key definition unique ID char sId[8]; TagToString (sId, pKeyDef->GetTag()); // Format key code char sCode[32]; formatKeyCode (sCode, pKeyDef->GetCode()); fprintf (f, " '%s' %-40s %s\n", sId, pKeyDef->GetName(), sCode); } } }
//------------------------------------------------------------------------------ // Bind keyset with group key to global function f //------------------------------------------------------------------------------ void CKeyMap::BindGroup(Tag gp,KeyGroupCB f) { CKeySet *set = FindKeySetById(gp); if (0 == set) return; lgrp = gp; // Remember the group set->BindTo(f); return; }
int LuaUnsyncedRead::GetKeyBindings(lua_State* L) { const int args = lua_gettop(L); // number of arguments if ((args != 1) || !lua_isstring(L, 1)) { luaL_error(L, "Incorrect arguments to GetKeyBindings(\"keyset\")"); } const string keysetStr = lua_tostring(L, 1); CKeySet ks; if (!ks.Parse(keysetStr)) { return 0; } const CKeyBindings::ActionList& actions = keyBindings->GetActionList(ks); lua_newtable(L); for (int i = 0; i < (int)actions.size(); i++) { const Action& action = actions[i]; lua_pushnumber(L, i + 1); lua_newtable(L); lua_pushstring(L, action.command.c_str()); lua_pushstring(L, action.extra.c_str()); lua_rawset(L, -3); lua_rawset(L, -3); } lua_pushstring(L, "n"); lua_pushnumber(L, actions.size()); lua_rawset(L, -3); return 1; }
const CKeyBindings::ActionList& CKeyBindings::GetActionList(const CKeySet& ks) const { static const ActionList empty; const ActionList* alPtr = NULL; if (ks.AnyMod()) { KeyMap::const_iterator it = bindings.find(ks); if (it == bindings.end()) { alPtr = ∅ } else { alPtr = &(it->second); } } else { // have to check for an AnyMod keyset as well as the normal one CKeySet anyMod = ks; anyMod.SetAnyBit(); KeyMap::const_iterator nit = bindings.find(ks); KeyMap::const_iterator ait = bindings.find(anyMod); const bool haveNormal = (nit != bindings.end()); const bool haveAnyMod = (ait != bindings.end()); if (!haveNormal && !haveAnyMod) { alPtr = ∅ } else if (haveNormal && !haveAnyMod) { alPtr = &(nit->second); } else if (!haveNormal && haveAnyMod) { alPtr = &(ait->second); } else { // combine the two lists (normal first) static ActionList merged; merged = nit->second; const ActionList& aal = ait->second; for (int i = 0; i < (int)aal.size(); ++i) { merged.push_back(aal[i]); } alPtr = &merged; } } if (LOG_IS_ENABLED(L_DEBUG)) { const bool isEmpty = (alPtr == &empty); LOG_L(L_DEBUG, "GetAction: %s (0x%03X)%s", ks.GetString(false).c_str(), ks.Key(), (isEmpty ? " EMPTY" : "")); if (!isEmpty) { const ActionList& al = *alPtr; for (size_t i = 0; i < al.size(); ++i) { LOG_L(L_DEBUG, " %s \"%s\"", al[i].command.c_str(), al[i].rawline.c_str()); } } } return *alPtr; }
//------------------------------------------------------------------------------ // Reset all keys to default values //------------------------------------------------------------------------------ void CKeyMap::SetDefaultValues(CKeyFile *def) { std::map<Tag,CKeySet*>::iterator i; for (i=kset.begin(); i!=kset.end(); i++) { CKeySet *ks = i->second; ks->SetDefaultValues(def); } return; }
//------------------------------------------------------------------------------ // Assign code to key definition //------------------------------------------------------------------------------ void CKeyMap::Assign(int cde,CKeyDefinition *kdf) { Tag ks = kdf->GetSet(); kdf->SetCode(cde); std::map<Tag,CKeySet*>::iterator it = kset.find(ks); if (it == kset.end()) return; CKeySet *set = (*it).second; set->StoreKeyDef(kdf); return; }
//------------------------------------------------------------------------------ // Unassign code from any key definition existing in the set // NOTE: The key is unassigned from the current set only //------------------------------------------------------------------------------ CKeyDefinition *CKeyMap::UnAssign(int cde,CKeyDefinition *kdf) { CKeySet *set = FindKeySetById(kdf->GetSet()); CKeyDefinition *kpv = set->GetKeyByCode(cde); if (0 == kpv) return 0; kdf->SetCode(0); // remove code from actual kpv->SetCode(0); // remove code from previous set->ClearCode(cde); return kpv; }
//------------------------------------------------------------------------------ // Locate a key definition by key identifier only // NOTE: Group are searched from upper group(menus,..) to lower group (aircraft) //------------------------------------------------------------------------------ CKeyDefinition* CKeyMap::FindKeyDefinitionById (Tag id) { CKeyDefinition *rc = NULL; for (U_INT k=0; k< oset.size();k++) { CKeySet *ks = oset[k]; CKeyDefinition* kdf = ks->GetKeyByTag(id); if (0 == kdf) continue; return kdf; } return 0; }
//------------------------------------------------------------------------- // Change group callback if key is redirected //------------------------------------------------------------------------- // Activate key in group (simulate a key stroke) // The group is taken from the Keydef in case of redirection //------------------------------------------------------------------------- bool CKeyMap::Stroke(Tag grp,Tag kid) { //--- find the Key set --------------------------- CKeySet *ks = FindKeySetById (grp); if (0 == ks) return false; CKeyDefinition *kdf = ks->GetKeyByTag(kid); if (0 == kdf) return false; //--- Group Redirection -------------------------- Tag ngp = kdf->GetSet(); ks = FindKeySetById (ngp); KeyGroupCB cb = ks->GetCB(); return (cb)(kdf,kdf->GetCode()) ; }
//------------------------------------------------------------------------------ // Locate a key definition by keyboard code only //------------------------------------------------------------------------------ CKeyDefinition* CKeyMap::FindKeyDefinitionByCode (int iCode, Tag &setTagOut) { setTagOut = 0; std::map<Tag,CKeySet*>::iterator i; for (i=kset.begin(); i!=kset.end(); i++) { CKeySet *set = i->second; CKeyDefinition *kdf = set->GetKeyByCode(iCode); if (0 == kdf) continue; setTagOut = set->GetTag(); return kdf; } return 0; }
bool CKeyBindings::AddKeySymbol(const string& keysym, const string& code) { CKeySet ks; if (!ks.Parse(code)) { logOutput.Print("AddKeySymbol: could not parse key: %s\n", code.c_str()); return false; } if (!keyCodes->AddKeySymbol(keysym, ks.Key())) { logOutput.Print("AddKeySymbol: could not add: %s\n", keysym.c_str()); return false; } return true; }
bool CKeyBindings::AddNamedKeySet(const string& name, const string& keystr) { CKeySet ks; if (!ks.Parse(keystr)) { printf("AddNamedKeySet: could not parse keyset: %s\n", keystr.c_str()); return false; } if ((ks.Key() < 0) || !CKeyCodes::IsValidLabel(name)) { printf("AddNamedKeySet: bad custom keyset name: %s\n", name.c_str()); return false; } namedKeySets[name] = ks; }
bool CKeyBindings::AddKeySymbol(const string& keysym, const string& code) { CKeySet ks; if (!ks.Parse(code)) { LOG_L(L_WARNING, "AddKeySymbol: could not parse key: %s", code.c_str()); return false; } if (!keyCodes->AddKeySymbol(keysym, ks.Key())) { LOG_L(L_WARNING, "AddKeySymbol: could not add: %s", keysym.c_str()); return false; } return true; }
//------------------------------------------------------------------------------ // Swap key code //------------------------------------------------------------------------------ void CKeyMap::SwapCode(CKeyDefinition *kdf,int nc) { Tag ks = kdf->GetSet(); int cd = kdf->GetCode(); kdf->SetCode(0); std::map<Tag,CKeySet*>::iterator it = kset.find(ks); if (it != kset.end()) return; // No set CKeySet *set = (*it).second; set->ClearCode(cd); //---Set the new code ---------------------------- kdf->SetCode(nc); set->StoreKeyDef(kdf); return; }
bool CKeyBindings::SetFakeMetaKey(const string& keystr) { CKeySet ks; if (StringToLower(keystr) == "none") { fakeMetaKey = -1; return true; } if (!ks.Parse(keystr)) { logOutput.Print("SetFakeMetaKey: could not parse key: %s\n", keystr.c_str()); return false; } fakeMetaKey = ks.Key(); return true; }
bool CKeyBindings::SetFakeMetaKey(const string& keystr) { CKeySet ks; if (StringToLower(keystr) == "none") { fakeMetaKey = -1; return true; } if (!ks.Parse(keystr)) { LOG_L(L_WARNING, "SetFakeMetaKey: could not parse key: %s", keystr.c_str()); return false; } fakeMetaKey = ks.Key(); return true; }
const CKeyBindings::ActionList& CKeyBindings::GetActionList(const CKeySet& ks) const { static const ActionList empty; const ActionList* alPtr = ∅ if (ks.AnyMod()) { KeyMap::const_iterator it = bindings.find(ks); if (it != bindings.end()) { alPtr = &(it->second); } } else { // have to check for an AnyMod keyset as well as the normal one CKeySet anyMod = ks; anyMod.SetAnyBit(); KeyMap::const_iterator nit = bindings.find(ks); KeyMap::const_iterator ait = bindings.find(anyMod); const bool haveNormal = (nit != bindings.end()); const bool haveAnyMod = (ait != bindings.end()); if (haveNormal && !haveAnyMod) { alPtr = &(nit->second); } else if (!haveNormal && haveAnyMod) { alPtr = &(ait->second); } else if (haveNormal && haveAnyMod) { // combine the two lists (normal first) static ActionList merged; //FIXME switch to thread_local when all buildbots are using >=gcc4.7 merged = nit->second; merged.insert(merged.end(), ait->second.begin(), ait->second.end()); alPtr = &merged; } } if (debugEnabled) { LOG("GetActions: hex=0x%02X acii=\"%s\":", ks.Key(), ks.GetString(false).c_str()); if (alPtr != &empty) { int i = 1; for (const auto& a: *alPtr) { LOG(" %i. action=\"%s\" rawline=\"%s\" shortcut=\"%s\"", i++, a.command.c_str(), a.rawline.c_str(), a.boundWith.c_str()); } } else { LOG(" EMPTY"); } } return *alPtr; }
bool CKeyBindings::Bind(const string& keystr, const string& line) { CKeySet ks; if (!ParseKeySet(keystr, ks)) { LOG_L(L_WARNING, "Bind: could not parse key: %s", keystr.c_str()); return false; } Action action(line); action.boundWith = keystr; if (action.command.empty()) { LOG_L(L_WARNING, "Bind: empty action: %s", line.c_str()); return false; } // Try to be safe, force AnyMod mode for stateful commands if (statefulCommands.find(action.command) != statefulCommands.end()) { ks.SetAnyBit(); } KeyMap::iterator it = bindings.find(ks); if (it == bindings.end()) { // new entry, push it ActionList& al = bindings[ks]; al.push_back(action); } else { if (it->first != ks) { // not a match, push it ActionList& al = it->second; al.push_back(action); } else { // an exact keyset match, check the command ActionList& al = it->second; int i; for (i = 0; i < (int)al.size(); i++) { if (action.command == al[i].command) { break; } } if (i == (int)al.size()) { // not a match, push it al.push_back(action); } } } return true; }
bool CKeyBindings::UnBindKeyset(const std::string& keystr) { CKeySet ks; if (!ks.Parse(keystr)) { LOG_L(L_WARNING, "UnBindKeyset: could not parse key: %s", keystr.c_str()); return false; } bool success = false; KeyMap::iterator it = bindings.find(ks); if (it != bindings.end()) { bindings.erase(it); success = true; } return success; }
bool CKeyBindings::UnBind(const std::string& keystr, const std::string& command) { CKeySet ks; if (!ks.Parse(keystr)) { LOG_L(L_WARNING, "UnBind: could not parse key: %s", keystr.c_str()); return false; } bool success = false; KeyMap::iterator it = bindings.find(ks); if (it != bindings.end()) { ActionList& al = it->second; success = RemoveCommandFromList(al, command); if (al.empty()) { bindings.erase(it); } } return success; }
static bool ParseSingleChain(const std::string& keystr, CKeyChain* kc) { kc->clear(); CKeySet ks; // note: this will fail if keystr contains spaces std::stringstream ss(keystr); while (ss.good()) { char kcstr[256]; ss.getline(kcstr, 256, ','); std::string kstr(kcstr); if (!ks.Parse(kstr, false)) return false; kc->emplace_back(ks); } return true; }
void CKeyBindings::BuildHotkeyMap() { hotkeys.clear(); KeyMap::const_iterator kit; for (kit = bindings.begin(); kit != bindings.end(); ++kit) { const CKeySet ks = kit->first; const string keystr = ks.GetString(true); const ActionList& al = kit->second; for (int i = 0; i < (int)al.size(); ++i) { HotkeyList& hl = hotkeys[al[i].command + ((al[i].extra == "") ? "" : " " + al[i].extra)]; int j; for (j = 0; j < (int)hl.size(); ++j) { if (hl[j] == keystr) { break; } } if (j == (int)hl.size()) { hl.push_back(keystr); } } } }
//------------------------------------------------------------------------------ // Keyboard Key pressed //------------------------------------------------------------------------------ void CKeyMap::KeyPress (U_INT key, EKeyboardModifiers mod) { // Translate key and modifier into keycode int code = (mod << 16) + key; bool handled = false; //--- special detection mode ------------------------------ if(m_bKeyDetect && m_fKeyCallback) { /// \todo unbind if this key code is already asigned if (m_fKeyCallback(m_winID, code)) return; } //---Standard key ----------------------------------------- for (U_INT k=0; (k<oset.size()); k++) { CKeySet *ks = oset[k]; CKeyDefinition *kdf = ks->GetKeyByCode(code); if (0 == kdf) continue; //---Call the redirected group key callback ----------- Tag ngp = kdf->GetSet(); ks = FindKeySetById (ngp); KeyGroupCB cb = ks->GetCB(); handled = (cb)(kdf,code); if (handled) return; } return; }
bool CKeyBindings::ParseKeySet(const string& keystr, CKeySet& ks) const { if (keystr[0] != NamedKeySetChar) { return ks.Parse(keystr); } else { const string keysetName = keystr.substr(1); NamedKeySetMap::const_iterator it = namedKeySets.find(keysetName); if (it != namedKeySets.end()) { ks = it->second; } else { return false; } } return true; }
//------------------------------------------------------------------------------ // Unbind keyset with group key to global function f //------------------------------------------------------------------------------ void CKeyMap::UnbindGroup(Tag gp) { CKeySet *set = FindKeySetById(gp); if (0 == set) return; set->BindTo(GroupUnbind); return; }
//-------------------------------------------------------------------------- // Save keyboard mapping to file //-------------------------------------------------------------------------- void CKeyMap::SaveCurrentConfig() { char codk[128]; char stag[8]; int i; CStreamFile sf; std::map<Tag,CKeySet*>::const_iterator it; std::map<Tag,CKeyDefinition*>::const_iterator kit; CKeySet * pset; CKeyDefinition * pkey; sf.OpenWrite("System/Keymap.txt"); // // file header and version // sf.WriteString("//================================================="); sf.WriteString("// Please note that Keyset are ordered by name "); sf.WriteString("// Menus should come first as they intercept keys "); sf.WriteString("// that may be dispatched to lower entity such as "); sf.WriteString("// Aircraft or ground vehicles "); sf.WriteString("//================================================="); sf.DebObject(); sf.WriteTag('vers', "---- configuration version ----"); sf.WriteInt(vers); for(it = kset.begin(); it != kset.end(); it++) { pset = it->second; sf.WriteTag('kset', "=== KeySet Definition File ==="); TagToString(stag, it->first); sf.WriteString(stag); sf.WriteTag('bgno', "========== BEGIN OBJECT =========="); sf.WriteTag('name', "---- key set name ----"); sf.WriteString(pset->GetName()); sf.WriteTag('user', "---- user can modify ----"); sf.WriteInt(pset->GetUserModifiableState()); sf.WriteTag('enab', "---- enabled ----"); sf.WriteInt(pset->GetEnabledState()); for(kit = pset->dkey.begin(); kit != pset->dkey.end(); kit++) { pkey = kit->second; sf.WriteTag('kkey', "---- key definition ----"); sf.DebObject(); sf.WriteTag('kyid', "---- key ID ----"); TagToString(stag, kit->first); sf.WriteString(stag); sf.WriteTag('name', "---- key name ----"); sf.WriteString(pkey->GetName()); sf.WriteTag('code', "---- key code & modifier ----"); i = pkey->GetCode(); formatKeyCode(codk,i,0); sf.WriteString(codk); sf.WriteTag('user', "---- user definable ----"); sf.WriteInt(pkey->IsUserMod()); sf.WriteTag('enab', "---- enabled ----"); sf.WriteInt(pkey->IsEnabled()); sf.EndObject(); } sf.EndObject(); } // File end // sf.EndObject(); sf.Close(); return; }
const CKeyBindings::ActionList& CKeyBindings::GetActionList(const CKeySet& ks) const { static const ActionList empty; const ActionList* alPtr = NULL; if (ks.AnyMod()) { KeyMap::const_iterator it = bindings.find(ks); if (it == bindings.end()) { alPtr = ∅ } else { alPtr = &(it->second); } } else { // have to check for an AnyMod keyset as well as the normal one CKeySet anyMod = ks; anyMod.SetAnyBit(); KeyMap::const_iterator nit = bindings.find(ks); KeyMap::const_iterator ait = bindings.find(anyMod); const bool haveNormal = (nit != bindings.end()); const bool haveAnyMod = (ait != bindings.end()); if (!haveNormal && !haveAnyMod) { alPtr = ∅ } else if (haveNormal && !haveAnyMod) { alPtr = &(nit->second); } else if (!haveNormal && haveAnyMod) { alPtr = &(ait->second); } else { // combine the two lists (normal first) static ActionList merged; merged = nit->second; const ActionList& aal = ait->second; for (int i = 0; i < (int)aal.size(); ++i) { merged.push_back(aal[i]); } alPtr = &merged; } } if (debug > 0) { char buf[256]; SNPRINTF(buf, sizeof(buf), "GetAction: %s (0x%03X)", ks.GetString(false).c_str(), ks.Key()); if (alPtr == &empty) { strncat(buf, " EMPTY", sizeof(buf)); logOutput.Print("%s", buf); } else { logOutput.Print("%s", buf); const ActionList& al = *alPtr; for (int i = 0; i < (int)al.size(); ++i) { SNPRINTF(buf, sizeof(buf), " %s \"%s\"", al[i].command.c_str(), al[i].rawline.c_str()); logOutput.Print("%s", buf); } } } return *alPtr; }