all repos — fluxbox @ 144091995610ea1b562e96d5e55c99659034bd55

custom fork of the fluxbox windowmanager

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
commit

144091995610ea1b562e96d5e55c99659034bd55

parent

83b9e392933ca882ff89140a9a7f93df8df512e6

5 files changed, 111 insertions(+), 187 deletions(-)

jump to
M ChangeLogChangeLog

@@ -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.ccsrc/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.ccsrc/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.hhsrc/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.ccsrc/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