Change to data structure for keybindings, ungrab and grab keys when switching keymodes instead of deciding whether we need it and repeating the key.
markt markt
5 files changed,
111 insertions(+),
187 deletions(-)
M
ChangeLog
→
ChangeLog
@@ -1,5 +1,16 @@
(Format: Year/Month/Day) Changes for 1.0rc3: +*06/12/19: + * Little simplification of data structure for keybindings (Mark) + Side effects: + - "Mod4 a b" now behaves like "Mod4 a None b" -- in fact, "None" is now + completely obsolete + - You can press "Escape" to cancel any Emacs-style keychain in progress + (unless it's bound to something else) + - If there is a conflict between bindings, the first one in the file wins + - Fixes handling of keychains like "Mod4 a Mod1 b" + - Should fix some issues with "None" modifier + Keys.cc/hh FbTk/KeyUtil.cc fluxbox.cc *06/12/18: * Rotate items in toolbar the same way as tabs (Mark) Toolbar.cc
M
src/FbTk/KeyUtil.cc
→
src/FbTk/KeyUtil.cc
@@ -124,42 +124,42 @@ Window root = RootWindow(display, screen);
XGrabKey(display, key, mod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); // Grab with numlock, capslock and scrlock //numlock XGrabKey(display, key, mod|nummod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //scrolllock XGrabKey(display, key, mod|scrollmod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //capslock XGrabKey(display, key, mod|capsmod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //capslock+numlock XGrabKey(display, key, mod|capsmod|nummod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //capslock+scrolllock XGrabKey(display, key, mod|capsmod|scrollmod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //capslock+numlock+scrolllock XGrabKey(display, key, mod|capsmod|scrollmod|nummod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); //numlock+scrollLock XGrabKey(display, key, mod|nummod|scrollmod, root, True, - GrabModeAsync, GrabModeSync); + GrabModeAsync, GrabModeAsync); }
M
src/Keys.cc
→
src/Keys.cc
@@ -94,6 +94,7 @@ using std::endl;
using std::string; using std::vector; using std::ifstream; +using std::pair; Keys::Keys(): m_display(FbTk::App::instance()->display())@@ -109,14 +110,8 @@ }
/// Destroys the keytree void Keys::deleteTree() { - for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it) { - keylist_t::iterator it = map_it->second->begin(); - const keylist_t::iterator it_end = map_it->second->end(); - for ( ; it != it_end; it++) - delete *it; - map_it->second->clear(); + for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it) delete map_it->second; - } m_map.clear(); }@@ -128,14 +123,11 @@ */
bool Keys::load(const char *filename) { if (!filename) return false; - - //ungrab all keys - FbTk::KeyUtil::ungrabKeys(); //free memory of previous grabs deleteTree(); - m_map["default:"] = new keylist_t; + m_map["default:"] = new t_key(0,0); FbTk::App::instance()->sync(false);@@ -144,21 +136,25 @@ ifstream infile(filename);
if (!infile) return false; // faild to open file - m_current_line = 0;//current line, so we can tell the user where the fault is + unsigned int current_line = 0;//so we can tell the user where the fault is while (!infile.eof()) { string linebuffer; getline(infile, linebuffer); - m_current_line++; + current_line++; - addBinding(linebuffer); + if (!addBinding(linebuffer)) { + cerr<<_FB_CONSOLETEXT(Keys, InvalidKeyMod, + "Keys: Invalid key/modifier on line", + "A bad key/modifier string was found on line (number following)")<<" "<< + current_line<<"): "<<linebuffer<<endl; + } } // end while eof - m_current_line = 0; m_filename = filename; - m_keylist = m_map["default:"]; + keyMode("default"); return true; }@@ -189,16 +185,16 @@ if (val[0][0] == '#' || val[0][0] == '!' ) //the line is commented
return true; // still a valid line. unsigned int key = 0, mod = 0; - t_key *current_key=0, *last_key=0; size_t argc = 0; - string keyMode = "default:"; + t_key *current_key=m_map["default:"]; + t_key *first_new_keylist = current_key, *first_new_key=0; if (val[0][val[0].length()-1] == ':') { argc++; keyspace_t::iterator it = m_map.find(val[0]); if (it == m_map.end()) - m_map[val[0]] = new keylist_t; - keyMode = val[0]; + m_map[val[0]] = new t_key(0,0); + current_key = m_map[val[0]]; } _FB_USES_NLS; // for each argument@@ -209,9 +205,7 @@
int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); if(tmpmod) mod |= tmpmod; //If it's a modifier - else if (strcasecmp("NONE",val[argc].c_str()) == 0) - mod = 0; - else { + else if (strcasecmp("NONE",val[argc].c_str())) { // keycode covers the following three two-byte cases: // 0x - hex // +[1-9] - number between +1 and +9@@ -229,111 +223,86 @@
} else // convert from string symbol key = FbTk::KeyUtil::getKey(val[argc].c_str()); - if (key == 0) { - cerr<<_FB_CONSOLETEXT(Keys, InvalidKeyMod, - "Keys: Invalid key/modifier on line", - "A bad key/modifier string was found on line (number following)")<<" "<< - m_current_line<<"): "<<linebuffer<<endl; + if (key == 0) return false; - } - if (!current_key) { - current_key = new t_key(key, mod); - last_key = current_key; + if (!first_new_key) { + first_new_keylist = current_key; + current_key = current_key->find(key, mod); + if (!current_key) { + first_new_key = new t_key(key, mod); + current_key = first_new_key; + } else if (*current_key->m_command) // already being used + return false; } else { t_key *temp_key = new t_key(key, mod); - last_key->keylist.push_back(temp_key); - last_key = temp_key; + current_key->keylist.push_back(temp_key); + current_key = temp_key; } + mod = 0; + key = 0; } } else { // parse command line - if (last_key == 0) { - cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; - cerr<<"> "<<linebuffer<<endl; + if (!first_new_key) return false; - } - bool ret_val = true; - const char *str = - FbTk::StringUtil::strcasestr(linebuffer.c_str(), - val[argc].c_str() + 1); // +1 to skip ':' - if (str == 0) { - cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; - cerr<<"> "<<linebuffer<<endl; - ret_val = false; - } else { - last_key->m_command = CommandParser::instance().parseLine(str); + const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(), + val[argc].c_str() + 1); // +1 to skip ':' + if (str) + current_key->m_command = CommandParser::instance().parseLine(str); - if (*last_key->m_command == 0) { - cerr<<_FB_CONSOLETEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "<<m_current_line<<endl; - cerr<<"> "<<linebuffer<<endl; - } else { - // need to change keymode here so it doesn't get changed by CommandParser - m_keylist = m_map[keyMode]; - // Add the keychain to list - if (!mergeTree(current_key)) { - cerr<<_FB_CONSOLETEXT(Keys, BadMerge, "Keys: Failed to merge keytree!", "relatively technical error message. Key bindings are stored in a tree structure")<<endl; - ret_val = false; - } - } + if (!str || *current_key->m_command == 0 || mod) { + delete first_new_key; + return false; } - delete current_key; - current_key = 0; - last_key = 0; - return ret_val; - + // success + first_new_keylist->keylist.push_back(first_new_key); + return true; } // end if } // end for return false; } - -/** - @return the KeyAction of the XKeyEvent; return false if not bound -*/ +// return true if bound to a command, else false bool Keys::doAction(XKeyEvent &ke) { ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); - static struct t_key* next_key = 0; + static t_key* next_key = m_keylist; + if (!next_key) + next_key = m_keylist; + t_key *temp_key = next_key->find(ke); + + + // need to save this for emacs-style keybindings + static t_key *saved_keymode = 0; - if (!next_key) { - bool retval = false; - // need a local keylist, in case m_command->execute() changes it - keylist_t *keylist = m_keylist; - for (size_t i = 0; i < keylist->size(); i++) { - if (*(*keylist)[i] == ke) { - if ((*keylist)[i]->keylist.size()) { - next_key = (*keylist)[i]; - return true; //still counts as being grabbed - } - if (*(*keylist)[i]->m_command != 0) { - (*keylist)[i]->m_command->execute(); - retval = true; - } - } - } - return retval; - } - t_key *temp_key = next_key->find(ke); - if (temp_key) { - if (temp_key->keylist.size()) { - next_key = temp_key; - return true; - } - next_key = 0; - if (*temp_key->m_command == 0) - return false; - temp_key->m_command->execute(); + if (temp_key && temp_key->keylist.size()) { // emacs-style + saved_keymode = m_keylist; + next_key = temp_key; + setKeyMode(next_key); + // grab "None Escape" to exit keychain in the middle + unsigned int esc = FbTk::KeyUtil::getKey("Escape"); + FbTk::KeyUtil::grabKey(esc,0); return true; } - temp_key = next_key; - next_key = 0; - if (*temp_key->m_command == 0) + if (!temp_key || *temp_key->m_command == 0) { + next_key = 0; + if (saved_keymode) { + setKeyMode(saved_keymode); + saved_keymode = 0; + } return false; + } temp_key->m_command->execute(); + if (saved_keymode) { + if (next_key == m_keylist) // don't reset keymode if command changed it + setKeyMode(saved_keymode); + saved_keymode = 0; + } + next_key = 0; return true; }@@ -345,62 +314,21 @@ bool Keys::reconfigure(const char *filename) {
return load(filename); } -/** - Merges two chains and binds new keys - @return true on success else false. -*/ -bool Keys::mergeTree(t_key *newtree, t_key *basetree) { - size_t baselist_i = 0; - if (basetree==0) { - for (; baselist_i<m_keylist->size(); baselist_i++) { - if ((*m_keylist)[baselist_i]->mod == newtree->mod && - (*m_keylist)[baselist_i]->key == newtree->key) { - if (newtree->keylist.size() && *(*m_keylist)[baselist_i]->m_command == 0) { - //assumes the newtree only have one branch - return mergeTree(newtree->keylist[0], (*m_keylist)[baselist_i]); - } else - break; - } - } - - if (baselist_i == m_keylist->size()) { - FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); - m_keylist->push_back(new t_key(newtree)); - if (newtree->keylist.size()) - return mergeTree(newtree->keylist[0], m_keylist->back()); - return true; - } - - } else { - for (; baselist_i<basetree->keylist.size(); baselist_i++) { - if (basetree->keylist[baselist_i]->mod == newtree->mod && - basetree->keylist[baselist_i]->key == newtree->key) { - if (newtree->keylist.size()) { - //assumes the newtree only have on branch - return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]); - } else - return false; - } - } - //if it wasn't in the list grab the key and add it to the list - if (baselist_i==basetree->keylist.size()) { - FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); - basetree->keylist.push_back(new t_key(newtree)); - if (newtree->keylist.size()) - return mergeTree(newtree->keylist[0], basetree->keylist.back()); - return true; - } - } - - return false; -} - -void Keys::keyMode(string keyMode = "default") { +void Keys::keyMode(string keyMode) { keyspace_t::iterator it = m_map.find(keyMode + ":"); if (it == m_map.end()) - m_keylist = m_map["default:"]; + setKeyMode(m_map["default:"]); else - m_keylist = it->second; + setKeyMode(it->second); +} + +void Keys::setKeyMode(t_key *keyMode) { + FbTk::KeyUtil::ungrabKeys(); + keylist_t::iterator it = keyMode->keylist.begin(); + keylist_t::iterator it_end = keyMode->keylist.end(); + for (; it != it_end; ++it) + FbTk::KeyUtil::grabKey((*it)->key,(*it)->mod); + m_keylist = keyMode; } Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) {@@ -416,12 +344,7 @@ m_command = k->m_command;
} Keys::t_key::~t_key() { - while (!keylist.empty()) { - t_key *k = keylist.back(); - if (k != 0) { // make sure we don't have a bad key pointer - delete k; - keylist.pop_back(); - } - } - + for (keylist_t::iterator list_it = keylist.begin(); list_it != keylist.end(); ++list_it) + delete *list_it; + keylist.clear(); }
M
src/Keys.hh
→
src/Keys.hh
@@ -116,18 +116,13 @@ unsigned int mod;
keylist_t keylist; }; - /** - merge two linked list - @return true on success, else false - */ - bool mergeTree(t_key *newtree, t_key *basetree=0); + void setKeyMode(t_key *keyMode); - typedef std::map<std::string, keylist_t *> keyspace_t; - keylist_t *m_keylist; + typedef std::map<std::string, t_key *> keyspace_t; + t_key *m_keylist; keyspace_t m_map; Display *m_display; ///< display connection - unsigned int m_current_line; }; #endif // KEYS_HH
M
src/fluxbox.cc
→
src/fluxbox.cc
@@ -1119,16 +1119,11 @@ switch (ke.type) {
case KeyPress: // see if we need to keep watching for key releases m_watching_screen = 0; - if (m_key->doAction(ke)) { - XAllowEvents(FbTk::App::instance()->display(), AsyncKeyboard, CurrentTime); - // if we've done some action other than cycling focus - if (old_watching_screen && m_watching_screen != old_watching_screen) - old_watching_screen->notifyReleasedKeys(ke); - } else { - XAllowEvents(FbTk::App::instance()->display(), ReplayKeyboard, CurrentTime); - // could still be cycling + if (!m_key->doAction(ke)) // could still be cycling m_watching_screen = old_watching_screen; - } + else if (old_watching_screen && + m_watching_screen != old_watching_screen) + old_watching_screen->notifyReleasedKeys(ke); break; case KeyRelease: { // we ignore most key releases unless we need to use