From 33079d2593a7a598446cc837fc39eb2a914ebb1f Mon Sep 17 00:00:00 2001 From: simonb Date: Wed, 12 Apr 2006 15:51:37 +0000 Subject: add "key modes" - thanks to Mark Tiefenbruck, mark at tiefenbruck dot org --- ChangeLog | 22 ++++++ src/FbCommandFactory.cc | 7 +- src/FbCommands.cc | 15 ++++ src/FbCommands.hh | 9 +++ src/FbTk/KeyUtil.cc | 16 ++-- src/Keys.cc | 193 +++++++++++++++++++++++++++--------------------- src/Keys.hh | 12 ++- src/fluxbox.cc | 8 +- 8 files changed, 182 insertions(+), 100 deletions(-) diff --git a/ChangeLog b/ChangeLog index c921dde..f6a32df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 + 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: + : Modifier Key :Command + will only work when the keymode is activated. + - 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 diff --git a/src/FbCommandFactory.cc b/src/FbCommandFactory.cc index aa091bb..4bf1dd5 100644 --- a/src/FbCommandFactory.cc +++ b/src/FbCommandFactory.cc @@ -65,6 +65,7 @@ FbCommandFactory::FbCommandFactory() { "focusright", "fullscreen", "iconify", + "keymode", "killwindow", "leftworkspace", "lower", @@ -106,11 +107,11 @@ FbCommandFactory::FbCommandFactory() { "rightworkspace", "rootmenu", "saverc", - "setenv", - "sethead", "sendtoworkspace", "sendtonextworkspace", "sendtoprevworkspace", + "setenv", + "sethead", "setstyle", "setworkspacename", "setworkspacenamedialog", @@ -168,6 +169,8 @@ FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, 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") diff --git a/src/FbCommands.cc b/src/FbCommands.cc index eb4e040..fc2426d 100644 --- a/src/FbCommands.cc +++ b/src/FbCommands.cc @@ -225,6 +225,21 @@ void SetStyleCmd::execute() { 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) diff --git a/src/FbCommands.hh b/src/FbCommands.hh index 1783c3a..023ff02 100644 --- a/src/FbCommands.hh +++ b/src/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(); diff --git a/src/FbTk/KeyUtil.cc b/src/FbTk/KeyUtil.cc index 1837873..cb0db93 100644 --- a/src/FbTk/KeyUtil.cc +++ b/src/FbTk/KeyUtil.cc @@ -124,42 +124,42 @@ void KeyUtil::grabKey(unsigned int key, unsigned int mod) { 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); } diff --git a/src/Keys.cc b/src/Keys.cc index 5e30726..c4099f6 100644 --- a/src/Keys.cc +++ b/src/Keys.cc @@ -86,6 +86,7 @@ #include #include #include +#include #ifdef HAVE_CASSERT #include #else @@ -95,12 +96,10 @@ 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 @@ Keys::~Keys() { /// 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); + } } /** @@ -133,6 +136,8 @@ bool Keys::load(const char *filename) { //free memory of previous grabs deleteTree(); + m_map["default:"] = new keylist_t; + FbTk::App::instance()->sync(false); //open the file @@ -154,6 +159,7 @@ bool Keys::load(const char *filename) { m_current_line = 0; m_filename = filename; + m_keylist = m_map["default:"]; return true; } @@ -184,55 +190,60 @@ bool Keys::addBinding(const std::string &linebuffer) { 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<<"): "<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<<"): "<keylist.push_back(temp_key); + last_key = temp_key; } } @@ -258,6 +269,8 @@ bool Keys::addBinding(const std::string &linebuffer) { cerr<<_FBTEXT(Keys, BadLine, "Keys: Error on line", "Error on line (number following)")<<": "< "<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::reconfigure(const char *filename) { bool Keys::mergeTree(t_key *newtree, t_key *basetree) { size_t baselist_i = 0; if (basetree==0) { - for (; baselist_imod == newtree->mod && - m_keylist[baselist_i]->key == newtree->key) { - if (newtree->keylist.size() && *m_keylist[baselist_i]->m_command == 0) { + for (; baselist_isize(); 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; } @@ -380,6 +397,14 @@ bool Keys::mergeTree(t_key *newtree, t_key *basetree) { 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 command) { key = key_; mod = mod_; diff --git a/src/Keys.hh b/src/Keys.hh index 75a8a68..6b393e7 100644 --- a/src/Keys.hh +++ b/src/Keys.hh @@ -26,6 +26,7 @@ #include #include +#include #include #include "FbTk/NotCopyable.hh" @@ -41,7 +42,7 @@ public: @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 @@ public: 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 @@ public: */ 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 @@ private: */ bool mergeTree(t_key *newtree, t_key *basetree=0); - keylist_t m_keylist; + typedef std::map keyspace_t; + keylist_t *m_keylist; + keyspace_t m_map; Display *m_display; ///< display connection unsigned int m_current_line; diff --git a/src/fluxbox.cc b/src/fluxbox.cc index fbb4203..5fcd4fe 100644 --- a/src/fluxbox.cc +++ b/src/fluxbox.cc @@ -383,7 +383,8 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile 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 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) { 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 -- cgit v0.11.2