all repos — fluxbox @ 33079d2593a7a598446cc837fc39eb2a914ebb1f

custom fork of the fluxbox windowmanager

add "key modes" - thanks to Mark Tiefenbruck, mark at tiefenbruck dot org
simonb simonb
commit

33079d2593a7a598446cc837fc39eb2a914ebb1f

parent

48579408d19fe0042a32f9634e6518b2eca3671c

M ChangeLogChangeLog

@@ -1,5 +1,27 @@

(Format: Year/Month/Day) Changes for 0.9.16: +*06/04/13: + * Provide "Key Modes" (Thanks Mark Tiefenbruck, mark at tiefenbruck dot org) + - New action in keys file: + Modifier Key :Keymode <Name> <End Modifier> <End Key> + Will define a keybinding namespace activated by the given mod/key + combination. The End Modifier and key are optional. They define + the key combination that quits the given key mode. They default + to just 'Escape'. + - New keys file optional prefix: + <Name>: Modifier Key :Command + will only work when the <Name> keymode is activated. + - <Name> is "default" if not specified - so: + **default commands will not be activated inside another keymode** + - Handy Example: + Mod1 X :KeyMode XNest + XNest: Mod1 X :KeyMode default + Will switch to XNest keymode when you press Alt-X. Then the + default bindings will not be caught by normal fluxbox, and will + pass through to an Xnested one! Groovy... Alt-X will switch back + to normal. + Keys.hh/cc FbCommands.hh/cc fluxbox.cc FbCommandFactory.cc + FbTk/KeyUtil.cc *06/04/11: * Ensure applying of size hints while maximizing (Mathias) Window.cc
M src/FbCommandFactory.ccsrc/FbCommandFactory.cc

@@ -65,6 +65,7 @@ "focusleft",

"focusright", "fullscreen", "iconify", + "keymode", "killwindow", "leftworkspace", "lower",

@@ -106,11 +107,11 @@ "restart",

"rightworkspace", "rootmenu", "saverc", - "setenv", - "sethead", "sendtoworkspace", "sendtonextworkspace", "sendtoprevworkspace", + "setenv", + "sethead", "setstyle", "setworkspacename", "setworkspacenamedialog",

@@ -168,6 +169,8 @@ else if (command == "setstyle")

return new SetStyleCmd(arguments); else if (command == "reloadstyle") return new ReloadStyleCmd(); + else if (command == "keymode") + return new KeyModeCmd(arguments); else if (command == "saverc") return new SaveResources(); else if (command == "execcommand" || command == "execute" || command == "exec")
M src/FbCommands.ccsrc/FbCommands.cc

@@ -225,6 +225,21 @@ FbTk::ThemeManager::instance().load(m_filename,

Fluxbox::instance()->getStyleOverlayFilename()); } +KeyModeCmd::KeyModeCmd(const std::string &arguments):m_keymode(arguments),m_end_args("None Escape") { + string::size_type second_pos = m_keymode.find_first_of(" \t", 0); + if (second_pos != string::npos) { + // ok we have arguments, parsing them here + m_end_args = m_keymode.substr(second_pos); + m_keymode.erase(second_pos); // remove argument from command + } + if (m_keymode != "default") + Fluxbox::instance()->keys()->addBinding(m_keymode + ": " + m_end_args + " :keymode default"); +} + +void KeyModeCmd::execute() { + Fluxbox::instance()->keys()->keyMode(m_keymode); +} + void ShowRootMenuCmd::execute() { BScreen *screen = Fluxbox::instance()->mouseScreen(); if (screen == 0)
M src/FbCommands.hhsrc/FbCommands.hh

@@ -96,6 +96,15 @@ private:

std::string m_filename; }; +class KeyModeCmd: public FbTk::Command { +public: + explicit KeyModeCmd(const std::string &arguments); + void execute(); +private: + std::string m_keymode; + std::string m_end_args; +}; + class ShowRootMenuCmd: public FbTk::Command { public: void execute();
M src/FbTk/KeyUtil.ccsrc/FbTk/KeyUtil.cc

@@ -124,42 +124,42 @@ Window root = RootWindow(display, screen);

XGrabKey(display, key, mod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); // Grab with numlock, capslock and scrlock //numlock XGrabKey(display, key, mod|nummod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //scrolllock XGrabKey(display, key, mod|scrollmod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //capslock XGrabKey(display, key, mod|capsmod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //capslock+numlock XGrabKey(display, key, mod|capsmod|nummod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //capslock+scrolllock XGrabKey(display, key, mod|capsmod|scrollmod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //capslock+numlock+scrolllock XGrabKey(display, key, mod|capsmod|scrollmod|nummod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); //numlock+scrollLock XGrabKey(display, key, mod|nummod|scrollmod, root, True, - GrabModeAsync, GrabModeAsync); + GrabModeAsync, GrabModeSync); }
M src/Keys.ccsrc/Keys.cc

@@ -86,6 +86,7 @@

#include <iostream> #include <fstream> #include <vector> +#include <map> #ifdef HAVE_CASSERT #include <cassert> #else

@@ -95,12 +96,10 @@ #include <memory>

using namespace std; -Keys::Keys(const char *filename): +Keys::Keys(): m_display(FbTk::App::instance()->display()) { - if (filename != 0) - load(filename); } Keys::~Keys() {

@@ -111,11 +110,15 @@ }

/// Destroys the keytree void Keys::deleteTree() { - keylist_t::iterator it = m_keylist.begin(); - const keylist_t::iterator end = m_keylist.end(); - for ( ; it != end; it++) - delete *it; - m_keylist.clear(); + 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(); + delete map_it->second; + m_map.erase(map_it->first); + } } /**

@@ -132,6 +135,8 @@ FbTk::KeyUtil::ungrabKeys();

//free memory of previous grabs deleteTree(); + + m_map["default:"] = new keylist_t; FbTk::App::instance()->sync(false);

@@ -154,6 +159,7 @@ } // end while eof

m_current_line = 0; m_filename = filename; + m_keylist = m_map["default:"]; return true; }

@@ -184,55 +190,60 @@ if (val[0][0] == '#' || val[0][0] == '!' ) //the line is commented

return true; // still a valid line. unsigned int key = 0, mod = 0; - char keyarg = 0; t_key *current_key=0, *last_key=0; + size_t argc = 0; + std::string keyMode = "default:"; + 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]; + } _FB_USES_NLS; // for each argument - for (size_t argc = 0; argc < val.size(); argc++) { + for (; argc < val.size(); argc++) { if (val[argc][0] != ':') { // parse key(s) - keyarg++; - if (keyarg==1) //first arg is modifier - mod = FbTk::KeyUtil::getModifier(val[argc].c_str()); - else if (keyarg > 1) { - int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); - if(tmpmod) - mod |= tmpmod; //If it's a modifier - else { - // keycode covers the following three two-byte cases: - // 0x - hex - // +[1-9] - number between +1 and +9 - // numbers 10 and above - // - if (val[argc].size() > 1 && (isdigit(val[argc][0]) && - (isdigit(val[argc][1]) || val[argc][1] == 'x') || - val[argc][0] == '+' && isdigit(val[argc][1])) ) { + 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 { + // keycode covers the following three two-byte cases: + // 0x - hex + // +[1-9] - number between +1 and +9 + // numbers 10 and above + // + if (val[argc].size() > 1 && (isdigit(val[argc][0]) && + (isdigit(val[argc][1]) || val[argc][1] == 'x') || + val[argc][0] == '+' && isdigit(val[argc][1])) ) { - key = strtoul(val[argc].c_str(), NULL, 0); + key = strtoul(val[argc].c_str(), NULL, 0); - if (errno == EINVAL || errno == ERANGE) - key = 0; + if (errno == EINVAL || errno == ERANGE) + key = 0; - } else // convert from string symbol - key = FbTk::KeyUtil::getKey(val[argc].c_str()); + } else // convert from string symbol + key = FbTk::KeyUtil::getKey(val[argc].c_str()); - if (key == 0) { - cerr<<_FBTEXT(Keys, InvalidKeyMod, - "Keys: Invalid key/modifier on line", - "A bad key/modifier string was found on line (number following)")<<" "<< - m_current_line<<"): "<<linebuffer<<endl; - return false; - } - if (!current_key) { - current_key = new t_key(key, mod); - last_key = current_key; - } else { - t_key *temp_key = new t_key(key, mod); - last_key->keylist.push_back(temp_key); - last_key = temp_key; - } + if (key == 0) { + cerr<<_FBTEXT(Keys, InvalidKeyMod, + "Keys: Invalid key/modifier on line", + "A bad key/modifier string was found on line (number following)")<<" "<< + m_current_line<<"): "<<linebuffer<<endl; + return false; + } + if (!current_key) { + current_key = new t_key(key, mod); + last_key = current_key; + } else { + t_key *temp_key = new t_key(key, mod); + last_key->keylist.push_back(temp_key); + last_key = temp_key; } }

@@ -258,6 +269,8 @@ if (*last_key->m_command == 0) {

cerr<<_FBTEXT(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<<_FBTEXT(Keys, BadMerge, "Keys: Failed to merge keytree!", "relatively technical error message. Key bindings are stored in a tree structure")<<endl;

@@ -279,46 +292,50 @@ }

/** - @return the KeyAction of the XKeyEvent + @return the KeyAction of the XKeyEvent; return false if not bound */ -void Keys::doAction(XKeyEvent &ke) { +bool Keys::doAction(XKeyEvent &ke) { ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); static struct t_key* next_key = 0; if (!next_key) { - - for (size_t i = 0; i < m_keylist.size(); i++) { - if (*m_keylist[i] == ke) { - if (m_keylist[i]->keylist.size()) { - next_key = m_keylist[i]; - break; //end for-loop - } else { - if (*m_keylist[i]->m_command != 0) - m_keylist[i]->m_command->execute(); + 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; } } } - - } else { //check the nextkey - t_key *temp_key = next_key->find(ke); - if (temp_key) { - if (temp_key->keylist.size()) { - next_key = temp_key; - } else { - next_key = 0; - if (*temp_key->m_command != 0) - temp_key->m_command->execute(); - } - } else { - temp_key = next_key; - next_key = 0; - if (*temp_key->m_command != 0) - temp_key->m_command->execute(); - + 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(); + return true; } + temp_key = next_key; + next_key = 0; + if (*temp_key->m_command == 0) + return false; + temp_key->m_command->execute(); + return true; } /**

@@ -337,22 +354,22 @@ */

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) { + 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]); + return mergeTree(newtree->keylist[0], (*m_keylist)[baselist_i]); } else break; } } - if (baselist_i == m_keylist.size()) { + if (baselist_i == m_keylist->size()) { FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); - m_keylist.push_back(new t_key(newtree)); + m_keylist->push_back(new t_key(newtree)); if (newtree->keylist.size()) - return mergeTree(newtree->keylist[0], m_keylist.back()); + return mergeTree(newtree->keylist[0], m_keylist->back()); return true; }

@@ -378,6 +395,14 @@ }

} return false; +} + +void Keys::keyMode(std::string keyMode = "default") { + keyspace_t::iterator it = m_map.find(keyMode + ":"); + if (it == m_map.end()) + m_keylist = m_map["default:"]; + else + m_keylist = it->second; } Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) {
M src/Keys.hhsrc/Keys.hh

@@ -26,6 +26,7 @@ #define KEYS_HH

#include <string> #include <vector> +#include <map> #include <X11/Xlib.h> #include "FbTk/NotCopyable.hh"

@@ -41,7 +42,7 @@ Constructor

@param display display connection @param filename file to load, default none */ - explicit Keys(const char *filename=0); + explicit Keys(); /// destructor ~Keys();

@@ -61,9 +62,9 @@ /// @return false on failure

bool addBinding(const std::string &binding); /** - do action from XKeyEvent + do action from XKeyEvent; return false if not bound to anything */ - void doAction(XKeyEvent &ke); + bool doAction(XKeyEvent &ke); /** Reload configuration from filename

@@ -71,6 +72,7 @@ @return true on success, else false

*/ bool reconfigure(const char *filename); const std::string filename() const { return m_filename; } + void keyMode(std::string keyMode); private: void deleteTree();

@@ -120,7 +122,9 @@ @return true on success, else false

*/ bool mergeTree(t_key *newtree, t_key *basetree=0); - keylist_t m_keylist; + typedef std::map<std::string, keylist_t *> keyspace_t; + keylist_t *m_keylist; + keyspace_t m_map; Display *m_display; ///< display connection unsigned int m_current_line;
M src/fluxbox.ccsrc/fluxbox.cc

@@ -383,7 +383,8 @@

m_reconfigure_wait = m_reread_menu_wait = false; // Create keybindings handler and load keys file - m_key.reset(new Keys(StringUtil::expandFilename(*m_rc_keyfile).c_str())); + m_key.reset(new Keys); + m_key->load(StringUtil::expandFilename(*m_rc_keyfile).c_str()); m_resourcemanager.unlock(); ungrab();

@@ -1083,7 +1084,10 @@ return;

switch (ke.type) { case KeyPress: - m_key->doAction(ke); + if (m_key->doAction(ke)) + XAllowEvents(FbTk::App::instance()->display(), AsyncKeyboard, CurrentTime); + else + XAllowEvents(FbTk::App::instance()->display(), ReplayKeyboard, CurrentTime); break; case KeyRelease: { // we ignore most key releases unless we need to use