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

This commit is contained in:
simonb 2006-04-12 15:51:37 +00:00
parent 48579408d1
commit 33079d2593
8 changed files with 181 additions and 99 deletions

View file

@ -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

View file

@ -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")

View file

@ -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)

View file

@ -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();

View file

@ -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);
}

View file

@ -86,6 +86,7 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#ifdef HAVE_CASSERT
#include <cassert>
#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<<"): "<<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 @@ bool Keys::addBinding(const std::string &linebuffer) {
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 @@ bool Keys::addBinding(const std::string &linebuffer) {
/**
@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::reconfigure(const char *filename) {
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;
}
@ -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<FbTk::Command> command) {
key = key_;
mod = mod_;

View file

@ -26,6 +26,7 @@
#include <string>
#include <vector>
#include <map>
#include <X11/Xlib.h>
#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<std::string, keylist_t *> keyspace_t;
keylist_t *m_keylist;
keyspace_t m_map;
Display *m_display; ///< display connection
unsigned int m_current_line;

View file

@ -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