2002-01-08 21:45:49 +00:00
|
|
|
// Keys.cc for Fluxbox - an X11 Window manager
|
2006-02-16 06:53:05 +00:00
|
|
|
// Copyright (c) 2001 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
|
2001-12-11 20:47:02 +00:00
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2001-12-29 10:32:04 +00:00
|
|
|
#include "Keys.hh"
|
2002-08-11 21:21:06 +00:00
|
|
|
|
2007-01-05 16:54:34 +00:00
|
|
|
#include "fluxbox.hh"
|
|
|
|
#include "Screen.hh"
|
2008-02-11 18:17:45 +00:00
|
|
|
#include "WinClient.hh"
|
|
|
|
#include "WindowCmd.hh"
|
2007-01-05 16:54:34 +00:00
|
|
|
|
2007-11-05 17:45:05 +00:00
|
|
|
#include "FbTk/EventManager.hh"
|
2003-09-06 13:58:06 +00:00
|
|
|
#include "FbTk/StringUtil.hh"
|
|
|
|
#include "FbTk/App.hh"
|
|
|
|
#include "FbTk/Command.hh"
|
2008-01-02 08:28:00 +00:00
|
|
|
#include "FbTk/RefCount.hh"
|
|
|
|
#include "FbTk/KeyUtil.hh"
|
2008-01-11 07:41:22 +00:00
|
|
|
#include "FbTk/CommandParser.hh"
|
2004-06-07 11:46:05 +00:00
|
|
|
#include "FbTk/I18n.hh"
|
2008-08-14 05:53:38 +00:00
|
|
|
#include "FbTk/AutoReloadHelper.hh"
|
2001-12-29 10:32:04 +00:00
|
|
|
|
2002-08-11 21:21:06 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2003-04-26 18:27:56 +00:00
|
|
|
#include "config.h"
|
2002-08-11 21:21:06 +00:00
|
|
|
#endif // HAVE_CONFIG_H
|
|
|
|
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2007-04-17 07:52:40 +00:00
|
|
|
#ifdef HAVE_CCTYPE
|
|
|
|
#include <cctype>
|
|
|
|
#else
|
|
|
|
#include <ctype.h>
|
|
|
|
#endif // HAVE_CCTYPE
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2004-08-31 15:26:40 +00:00
|
|
|
#ifdef HAVE_CSTDIO
|
|
|
|
#include <cstdio>
|
|
|
|
#else
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CSTDLIB
|
|
|
|
#include <cstdlib>
|
|
|
|
#else
|
|
|
|
#include <stdlib.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CERRNO
|
|
|
|
#include <cerrno>
|
|
|
|
#else
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CSTRING
|
|
|
|
#include <cstring>
|
|
|
|
#else
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2002-05-02 07:10:03 +00:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
#include <sys/types.h>
|
2002-02-21 00:39:08 +00:00
|
|
|
#endif // HAVE_SYS_TYPES_H
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2002-05-02 07:10:03 +00:00
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
|
|
#include <sys/wait.h>
|
2002-02-21 00:39:08 +00:00
|
|
|
#endif // HAVE_SYS_WAIT_H
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2002-05-02 07:10:03 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
2002-02-21 00:39:08 +00:00
|
|
|
#endif // HAVE_UNISTD_H
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2002-05-02 07:10:03 +00:00
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
#include <sys/stat.h>
|
2002-02-21 00:39:08 +00:00
|
|
|
#endif // HAVE_SYS_STAT_H
|
2001-12-11 20:47:02 +00:00
|
|
|
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <X11/keysym.h>
|
2005-05-06 09:22:53 +00:00
|
|
|
#include <X11/Xutil.h>
|
|
|
|
#include <X11/XKBlib.h>
|
2001-12-11 20:47:02 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2008-01-02 08:28:00 +00:00
|
|
|
#include <list>
|
2002-01-07 23:44:09 +00:00
|
|
|
#include <vector>
|
2002-01-08 12:13:25 +00:00
|
|
|
#include <memory>
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2006-10-27 06:57:43 +00:00
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
using std::ifstream;
|
2006-12-19 18:08:33 +00:00
|
|
|
using std::pair;
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2008-01-02 08:28:00 +00:00
|
|
|
// helper class 'keytree'
|
|
|
|
class Keys::t_key {
|
|
|
|
public:
|
|
|
|
|
|
|
|
// typedefs
|
|
|
|
typedef std::list<t_key*> keylist_t;
|
|
|
|
|
|
|
|
// constructor / destructor
|
|
|
|
t_key(int type, unsigned int mod, unsigned int key, int context,
|
|
|
|
bool isdouble);
|
|
|
|
t_key(t_key *k);
|
|
|
|
~t_key();
|
|
|
|
|
|
|
|
t_key *find(int type_, unsigned int mod_, unsigned int key_,
|
|
|
|
int context_, bool isdouble_) {
|
|
|
|
// t_key ctor sets context_ of 0 to GLOBAL, so we must here too
|
|
|
|
context_ = context_ ? context_ : GLOBAL;
|
|
|
|
keylist_t::iterator it = keylist.begin(), it_end = keylist.end();
|
|
|
|
for (; it != it_end; it++) {
|
2008-02-03 20:17:42 +00:00
|
|
|
if (*it && (*it)->type == type_ && (*it)->key == key_ &&
|
2008-01-02 08:28:00 +00:00
|
|
|
((*it)->context & context_) > 0 &&
|
|
|
|
isdouble_ == (*it)->isdouble && (*it)->mod ==
|
|
|
|
FbTk::KeyUtil::instance().isolateModifierMask(mod_))
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// member variables
|
2008-08-14 05:53:38 +00:00
|
|
|
|
2008-01-02 08:28:00 +00:00
|
|
|
int type; // KeyPress or ButtonPress
|
|
|
|
unsigned int mod;
|
|
|
|
unsigned int key; // key code or button number
|
|
|
|
int context; // ON_TITLEBAR, etc.: bitwise-or of all desired contexts
|
|
|
|
bool isdouble;
|
2008-01-11 07:41:22 +00:00
|
|
|
FbTk::RefCount<FbTk::Command<void> > m_command;
|
2008-01-02 08:28:00 +00:00
|
|
|
|
|
|
|
keylist_t keylist;
|
|
|
|
};
|
|
|
|
|
|
|
|
Keys::t_key::t_key(int type_, unsigned int mod_, unsigned int key_,
|
|
|
|
int context_, bool isdouble_) :
|
|
|
|
type(type_),
|
|
|
|
mod(mod_),
|
|
|
|
key(key_),
|
|
|
|
context(context_),
|
|
|
|
isdouble(isdouble_),
|
|
|
|
m_command(0) {
|
|
|
|
context = context_ ? context_ : GLOBAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Keys::t_key::t_key(t_key *k) {
|
|
|
|
key = k->key;
|
|
|
|
mod = k->mod;
|
|
|
|
type = k->type;
|
|
|
|
context = k->context;
|
|
|
|
isdouble = k->isdouble;
|
|
|
|
m_command = k->m_command;
|
|
|
|
}
|
|
|
|
|
|
|
|
Keys::t_key::~t_key() {
|
|
|
|
for (keylist_t::iterator list_it = keylist.begin(); list_it != keylist.end(); ++list_it)
|
|
|
|
delete *list_it;
|
|
|
|
keylist.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-08-14 05:53:38 +00:00
|
|
|
Keys::Keys(): next_key(0), m_reloader(new FbTk::AutoReloadHelper()) {
|
|
|
|
m_reloader->setReloadCmd(FbTk::RefCount<FbTk::Command<void> >(new FbTk::SimpleCommand<Keys>(*this, &Keys::reload)));
|
2008-05-12 19:16:37 +00:00
|
|
|
}
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2005-05-06 09:22:53 +00:00
|
|
|
Keys::~Keys() {
|
2007-01-05 16:54:34 +00:00
|
|
|
ungrabKeys();
|
2007-02-09 18:13:01 +00:00
|
|
|
ungrabButtons();
|
2002-12-01 13:42:15 +00:00
|
|
|
deleteTree();
|
2008-08-14 05:53:38 +00:00
|
|
|
delete m_reloader;
|
2001-12-11 20:47:02 +00:00
|
|
|
}
|
2001-12-29 10:32:04 +00:00
|
|
|
|
2003-08-19 16:19:28 +00:00
|
|
|
/// Destroys the keytree
|
2001-12-11 20:47:02 +00:00
|
|
|
void Keys::deleteTree() {
|
2006-12-19 18:08:33 +00:00
|
|
|
for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it)
|
2006-04-12 15:51:37 +00:00
|
|
|
delete map_it->second;
|
2006-04-22 15:37:04 +00:00
|
|
|
m_map.clear();
|
2008-02-04 17:33:17 +00:00
|
|
|
next_key = 0;
|
2001-12-11 20:47:02 +00:00
|
|
|
}
|
2001-12-29 10:32:04 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
// keys are only grabbed in global context
|
2007-01-05 16:54:34 +00:00
|
|
|
void Keys::grabKey(unsigned int key, unsigned int mod) {
|
2007-10-13 21:51:37 +00:00
|
|
|
WindowMap::iterator it = m_window_map.begin();
|
|
|
|
WindowMap::iterator it_end = m_window_map.end();
|
2007-01-05 16:54:34 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((it->second & Keys::GLOBAL) > 0)
|
|
|
|
FbTk::KeyUtil::grabKey(key, mod, it->first);
|
|
|
|
}
|
2007-01-05 16:54:34 +00:00
|
|
|
}
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
// keys are only grabbed in global context
|
2007-01-05 16:54:34 +00:00
|
|
|
void Keys::ungrabKeys() {
|
2007-10-13 21:51:37 +00:00
|
|
|
WindowMap::iterator it = m_window_map.begin();
|
|
|
|
WindowMap::iterator it_end = m_window_map.end();
|
2007-01-05 16:54:34 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((it->second & Keys::GLOBAL) > 0)
|
|
|
|
FbTk::KeyUtil::ungrabKeys(it->first);
|
|
|
|
}
|
2007-01-05 16:54:34 +00:00
|
|
|
}
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
// ON_DESKTOP context doesn't need to be grabbed
|
|
|
|
void Keys::grabButton(unsigned int button, unsigned int mod, int context) {
|
|
|
|
WindowMap::iterator it = m_window_map.begin();
|
|
|
|
WindowMap::iterator it_end = m_window_map.end();
|
2007-02-09 18:13:01 +00:00
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((context & it->second & ~Keys::ON_DESKTOP) > 0)
|
|
|
|
FbTk::KeyUtil::grabButton(button, mod, it->first,
|
|
|
|
ButtonPressMask|ButtonReleaseMask);
|
|
|
|
}
|
2007-02-09 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Keys::ungrabButtons() {
|
2007-10-13 21:51:37 +00:00
|
|
|
WindowMap::iterator it = m_window_map.begin();
|
|
|
|
WindowMap::iterator it_end = m_window_map.end();
|
2007-02-09 18:13:01 +00:00
|
|
|
|
|
|
|
for (; it != it_end; ++it)
|
2007-10-13 21:51:37 +00:00
|
|
|
FbTk::KeyUtil::ungrabButtons(it->first);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keys::grabWindow(Window win) {
|
|
|
|
if (!m_keylist)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// make sure the window is in our list
|
|
|
|
WindowMap::iterator win_it = m_window_map.find(win);
|
|
|
|
if (win_it == m_window_map.end())
|
|
|
|
return;
|
|
|
|
|
2007-11-20 19:01:45 +00:00
|
|
|
m_handler_map[win]->grabButtons();
|
2008-01-02 08:28:00 +00:00
|
|
|
t_key::keylist_t::iterator it = m_keylist->keylist.begin();
|
|
|
|
t_key::keylist_t::iterator it_end = m_keylist->keylist.end();
|
2007-10-13 21:51:37 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
// keys are only grabbed in global context
|
|
|
|
if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress)
|
|
|
|
FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win);
|
|
|
|
// ON_DESKTOP buttons don't need to be grabbed
|
|
|
|
else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 &&
|
|
|
|
(*it)->type == ButtonPress)
|
|
|
|
FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win,
|
|
|
|
ButtonPressMask|ButtonReleaseMask);
|
|
|
|
}
|
2007-02-09 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 09:22:53 +00:00
|
|
|
/**
|
2003-02-28 23:55:37 +00:00
|
|
|
Load and grab keys
|
|
|
|
TODO: error checking
|
|
|
|
*/
|
2008-05-12 19:16:37 +00:00
|
|
|
void Keys::reload() {
|
2007-09-30 11:35:20 +00:00
|
|
|
// an intentionally empty file will still have one root mapping
|
|
|
|
bool firstload = m_map.empty();
|
2002-08-11 21:21:06 +00:00
|
|
|
|
2008-05-12 19:16:37 +00:00
|
|
|
if (m_filename.empty()) {
|
2007-09-30 11:35:20 +00:00
|
|
|
if (firstload)
|
|
|
|
loadDefaults();
|
2008-05-12 19:16:37 +00:00
|
|
|
return;
|
2007-09-30 11:35:20 +00:00
|
|
|
}
|
2006-04-12 15:51:37 +00:00
|
|
|
|
2003-12-04 21:31:02 +00:00
|
|
|
FbTk::App::instance()->sync(false);
|
2005-05-06 09:22:53 +00:00
|
|
|
|
2007-09-30 11:35:20 +00:00
|
|
|
// open the file
|
2008-05-12 19:16:37 +00:00
|
|
|
ifstream infile(m_filename.c_str());
|
2007-09-30 11:35:20 +00:00
|
|
|
if (!infile) {
|
|
|
|
if (firstload)
|
|
|
|
loadDefaults();
|
2008-05-12 19:16:37 +00:00
|
|
|
return; // failed to open file
|
2007-09-30 11:35:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// free memory of previous grabs
|
|
|
|
deleteTree();
|
|
|
|
|
2007-12-09 20:47:41 +00:00
|
|
|
m_map["default:"] = new t_key(0,0,0,0,false);
|
2007-09-30 11:35:20 +00:00
|
|
|
|
|
|
|
unsigned int current_line = 0; //so we can tell the user where the fault is
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2002-12-01 13:42:15 +00:00
|
|
|
while (!infile.eof()) {
|
|
|
|
string linebuffer;
|
2002-08-11 21:21:06 +00:00
|
|
|
|
2002-12-01 13:42:15 +00:00
|
|
|
getline(infile, linebuffer);
|
2001-12-11 20:47:02 +00:00
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
current_line++;
|
2002-08-11 21:21:06 +00:00
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!addBinding(linebuffer)) {
|
2006-12-20 16:22:10 +00:00
|
|
|
_FB_USES_NLS;
|
2006-12-19 18:08:33 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-12-20 17:37:57 +00:00
|
|
|
} // end while eof
|
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
keyMode("default");
|
2003-12-20 17:37:57 +00:00
|
|
|
}
|
|
|
|
|
2007-09-30 11:35:20 +00:00
|
|
|
/**
|
|
|
|
* Load critical key/mouse bindings for when there are fatal errors reading the keyFile.
|
|
|
|
*/
|
|
|
|
void Keys::loadDefaults() {
|
|
|
|
#ifdef DEBUG
|
|
|
|
cerr<<"Loading default key bindings"<<endl;
|
|
|
|
#endif
|
|
|
|
deleteTree();
|
2007-12-09 20:47:41 +00:00
|
|
|
m_map["default:"] = new t_key(0,0,0,0,false);
|
2007-09-30 11:35:20 +00:00
|
|
|
addBinding("OnDesktop Mouse1 :HideMenus");
|
|
|
|
addBinding("OnDesktop Mouse2 :WorkspaceMenu");
|
|
|
|
addBinding("OnDesktop Mouse3 :RootMenu");
|
|
|
|
keyMode("default");
|
|
|
|
}
|
|
|
|
|
2006-10-27 06:57:43 +00:00
|
|
|
bool Keys::addBinding(const string &linebuffer) {
|
2003-12-20 17:37:57 +00:00
|
|
|
|
|
|
|
vector<string> val;
|
|
|
|
// Parse arguments
|
|
|
|
FbTk::StringUtil::stringtok(val, linebuffer.c_str());
|
|
|
|
|
|
|
|
// must have at least 1 argument
|
2008-01-02 08:28:00 +00:00
|
|
|
if (val.empty())
|
2003-12-20 17:37:57 +00:00
|
|
|
return true; // empty lines are valid.
|
2005-05-06 09:22:53 +00:00
|
|
|
|
2004-02-20 09:29:07 +00:00
|
|
|
if (val[0][0] == '#' || val[0][0] == '!' ) //the line is commented
|
2003-12-20 17:37:57 +00:00
|
|
|
return true; // still a valid line.
|
2005-05-06 09:22:53 +00:00
|
|
|
|
2003-12-20 17:37:57 +00:00
|
|
|
unsigned int key = 0, mod = 0;
|
2007-02-09 18:13:01 +00:00
|
|
|
int type = 0, context = 0;
|
2007-12-09 20:47:41 +00:00
|
|
|
bool isdouble = false;
|
2006-04-12 15:51:37 +00:00
|
|
|
size_t argc = 0;
|
2006-12-19 18:08:33 +00:00
|
|
|
t_key *current_key=m_map["default:"];
|
|
|
|
t_key *first_new_keylist = current_key, *first_new_key=0;
|
2006-04-12 15:51:37 +00:00
|
|
|
|
|
|
|
if (val[0][val[0].length()-1] == ':') {
|
|
|
|
argc++;
|
|
|
|
keyspace_t::iterator it = m_map.find(val[0]);
|
|
|
|
if (it == m_map.end())
|
2007-12-09 20:47:41 +00:00
|
|
|
m_map[val[0]] = new t_key(0,0,0,0,false);
|
2006-12-19 18:08:33 +00:00
|
|
|
current_key = m_map[val[0]];
|
2006-04-12 15:51:37 +00:00
|
|
|
}
|
2005-05-06 09:22:53 +00:00
|
|
|
// for each argument
|
2006-04-12 15:51:37 +00:00
|
|
|
for (; argc < val.size(); argc++) {
|
2003-12-20 17:37:57 +00:00
|
|
|
|
|
|
|
if (val[argc][0] != ':') { // parse key(s)
|
2006-04-12 15:51:37 +00:00
|
|
|
|
|
|
|
int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str());
|
|
|
|
if(tmpmod)
|
|
|
|
mod |= tmpmod; //If it's a modifier
|
2007-02-09 18:13:01 +00:00
|
|
|
else if (strcasecmp("ondesktop", val[argc].c_str()) == 0)
|
|
|
|
context |= ON_DESKTOP;
|
2007-10-13 21:51:37 +00:00
|
|
|
else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0)
|
|
|
|
context |= ON_TOOLBAR;
|
2007-10-15 18:05:28 +00:00
|
|
|
else if (strcasecmp("onwindow", val[argc].c_str()) == 0)
|
|
|
|
context |= ON_WINDOW;
|
2007-12-09 20:47:41 +00:00
|
|
|
else if (strcasecmp("ontitlebar", val[argc].c_str()) == 0)
|
|
|
|
context |= ON_TITLEBAR;
|
|
|
|
else if (strcasecmp("double", val[argc].c_str()) == 0)
|
|
|
|
isdouble = true;
|
2006-12-19 18:08:33 +00:00
|
|
|
else if (strcasecmp("NONE",val[argc].c_str())) {
|
2007-02-09 18:13:01 +00:00
|
|
|
// check if it's a mouse button
|
2007-11-22 20:21:47 +00:00
|
|
|
if (strcasecmp("focusin", val[argc].c_str()) == 0) {
|
|
|
|
context = ON_WINDOW;
|
|
|
|
mod = key = 0;
|
|
|
|
type = FocusIn;
|
|
|
|
} else if (strcasecmp("focusout", val[argc].c_str()) == 0) {
|
|
|
|
context = ON_WINDOW;
|
|
|
|
mod = key = 0;
|
|
|
|
type = FocusOut;
|
|
|
|
} else if (strcasecmp("changeworkspace",
|
|
|
|
val[argc].c_str()) == 0) {
|
|
|
|
context = ON_DESKTOP;
|
|
|
|
mod = key = 0;
|
|
|
|
type = FocusIn;
|
|
|
|
} else if (strcasecmp("mouseover", val[argc].c_str()) == 0) {
|
|
|
|
type = EnterNotify;
|
|
|
|
if (!(context & (ON_WINDOW|ON_TOOLBAR)))
|
|
|
|
context |= ON_WINDOW;
|
|
|
|
key = 0;
|
|
|
|
} else if (strcasecmp("mouseout", val[argc].c_str()) == 0) {
|
|
|
|
type = LeaveNotify;
|
|
|
|
if (!(context & (ON_WINDOW|ON_TOOLBAR)))
|
|
|
|
context |= ON_WINDOW;
|
|
|
|
key = 0;
|
|
|
|
} else if (strcasecmp(val[argc].substr(0,5).c_str(),
|
|
|
|
"mouse") == 0 &&
|
|
|
|
val[argc].length() > 5) {
|
2007-02-09 18:13:01 +00:00
|
|
|
type = ButtonPress;
|
2007-11-22 20:21:47 +00:00
|
|
|
key = atoi(val[argc].substr(5,
|
|
|
|
val[argc].length()-5).c_str());
|
2008-04-30 15:31:04 +00:00
|
|
|
if (strstr(val[argc].c_str(), "top"))
|
|
|
|
context = ON_DESKTOP;
|
2006-04-12 15:51:37 +00:00
|
|
|
// keycode covers the following three two-byte cases:
|
|
|
|
// 0x - hex
|
|
|
|
// +[1-9] - number between +1 and +9
|
|
|
|
// numbers 10 and above
|
|
|
|
//
|
2008-01-02 08:28:00 +00:00
|
|
|
} else if (!val[argc].empty() && (isdigit(val[argc][0]) &&
|
2007-02-09 18:13:01 +00:00
|
|
|
(isdigit(val[argc][1]) || val[argc][1] == 'x') ||
|
|
|
|
val[argc][0] == '+' && isdigit(val[argc][1])) ) {
|
2006-10-27 06:57:43 +00:00
|
|
|
|
2006-04-12 15:51:37 +00:00
|
|
|
key = strtoul(val[argc].c_str(), NULL, 0);
|
2007-02-09 18:13:01 +00:00
|
|
|
type = KeyPress;
|
2005-05-20 22:25:22 +00:00
|
|
|
|
2006-04-12 15:51:37 +00:00
|
|
|
if (errno == EINVAL || errno == ERANGE)
|
|
|
|
key = 0;
|
2005-05-20 22:25:22 +00:00
|
|
|
|
2007-02-09 18:13:01 +00:00
|
|
|
} else { // convert from string symbol
|
2006-10-27 06:57:43 +00:00
|
|
|
key = FbTk::KeyUtil::getKey(val[argc].c_str());
|
2007-02-09 18:13:01 +00:00
|
|
|
type = KeyPress;
|
|
|
|
}
|
2005-05-20 22:25:22 +00:00
|
|
|
|
2007-11-22 20:21:47 +00:00
|
|
|
if (key == 0 && (type == KeyPress || type == ButtonPress))
|
2006-04-12 15:51:37 +00:00
|
|
|
return false;
|
2007-12-09 20:47:41 +00:00
|
|
|
if (type != ButtonPress)
|
|
|
|
isdouble = false;
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!first_new_key) {
|
|
|
|
first_new_keylist = current_key;
|
2007-12-09 20:47:41 +00:00
|
|
|
current_key = current_key->find(type, mod, key, context,
|
|
|
|
isdouble);
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!current_key) {
|
2007-12-09 20:47:41 +00:00
|
|
|
first_new_key = new t_key(type, mod, key, context,
|
|
|
|
isdouble);
|
2006-12-19 18:08:33 +00:00
|
|
|
current_key = first_new_key;
|
|
|
|
} else if (*current_key->m_command) // already being used
|
|
|
|
return false;
|
2006-04-12 15:51:37 +00:00
|
|
|
} else {
|
2007-12-09 20:47:41 +00:00
|
|
|
t_key *temp_key = new t_key(type, mod, key, context,
|
|
|
|
isdouble);
|
2006-12-19 18:08:33 +00:00
|
|
|
current_key->keylist.push_back(temp_key);
|
|
|
|
current_key = temp_key;
|
2003-07-02 05:42:21 +00:00
|
|
|
}
|
2006-12-19 18:08:33 +00:00
|
|
|
mod = 0;
|
|
|
|
key = 0;
|
2007-02-09 18:13:01 +00:00
|
|
|
type = 0;
|
|
|
|
context = 0;
|
2007-12-09 20:47:41 +00:00
|
|
|
isdouble = false;
|
2005-05-06 09:22:53 +00:00
|
|
|
}
|
2003-06-30 19:42:20 +00:00
|
|
|
|
2003-12-20 17:37:57 +00:00
|
|
|
} else { // parse command line
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!first_new_key)
|
2003-12-20 17:37:57 +00:00
|
|
|
return false;
|
2003-06-30 14:57:14 +00:00
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(),
|
|
|
|
val[argc].c_str() + 1); // +1 to skip ':'
|
|
|
|
if (str)
|
2008-01-11 07:41:22 +00:00
|
|
|
current_key->m_command = FbTk::CommandParser<void>::instance().parse(str);
|
2002-01-21 01:48:47 +00:00
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!str || *current_key->m_command == 0 || mod) {
|
|
|
|
delete first_new_key;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// success
|
|
|
|
first_new_keylist->keylist.push_back(first_new_key);
|
|
|
|
return true;
|
2003-12-20 17:37:57 +00:00
|
|
|
} // end if
|
|
|
|
} // end for
|
|
|
|
|
|
|
|
return false;
|
2001-12-11 20:47:02 +00:00
|
|
|
}
|
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
// return true if bound to a command, else false
|
2007-10-13 21:51:37 +00:00
|
|
|
bool Keys::doAction(int type, unsigned int mods, unsigned int key,
|
2008-02-11 18:17:45 +00:00
|
|
|
int context, WinClient *current, Time time) {
|
2007-12-09 20:47:41 +00:00
|
|
|
|
|
|
|
static Time last_button_time = 0;
|
|
|
|
static unsigned int last_button = 0;
|
|
|
|
|
|
|
|
// need to remember whether or not this is a double-click, e.g. when
|
|
|
|
// double-clicking on the titlebar when there's an OnWindow Double command
|
|
|
|
// we just don't update it if timestamp is the same
|
|
|
|
static bool double_click = false;
|
|
|
|
|
|
|
|
// actual value used for searching
|
|
|
|
bool isdouble = false;
|
|
|
|
|
|
|
|
if (type == ButtonPress) {
|
|
|
|
if (time > last_button_time)
|
|
|
|
double_click = (time - last_button_time <
|
|
|
|
Fluxbox::instance()->getDoubleClickInterval()) &&
|
|
|
|
last_button == key;
|
|
|
|
last_button_time = time;
|
|
|
|
last_button = key;
|
|
|
|
isdouble = double_click;
|
|
|
|
}
|
2005-05-06 09:22:53 +00:00
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!next_key)
|
|
|
|
next_key = m_keylist;
|
|
|
|
|
2007-02-09 18:13:01 +00:00
|
|
|
mods = FbTk::KeyUtil::instance().cleanMods(mods);
|
2007-12-09 20:47:41 +00:00
|
|
|
t_key *temp_key = next_key->find(type, mods, key, context, isdouble);
|
|
|
|
|
|
|
|
// just because we double-clicked doesn't mean we shouldn't look for single
|
|
|
|
// click commands
|
|
|
|
if (!temp_key && isdouble)
|
|
|
|
temp_key = next_key->find(type, mods, key, context, false);
|
2006-12-19 18:08:33 +00:00
|
|
|
|
|
|
|
// need to save this for emacs-style keybindings
|
|
|
|
static t_key *saved_keymode = 0;
|
|
|
|
|
2007-02-09 18:13:01 +00:00
|
|
|
// grab "None Escape" to exit keychain in the middle
|
|
|
|
unsigned int esc = FbTk::KeyUtil::getKey("Escape");
|
|
|
|
|
2007-11-05 17:05:58 +00:00
|
|
|
// if focus changes, windows will get NotifyWhileGrabbed,
|
|
|
|
// which they tend to ignore
|
2007-11-05 17:45:05 +00:00
|
|
|
if (temp_key && type == KeyPress &&
|
|
|
|
!FbTk::EventManager::instance()->grabbingKeyboard())
|
2007-11-05 17:05:58 +00:00
|
|
|
XUngrabKeyboard(Fluxbox::instance()->display(), CurrentTime);
|
|
|
|
|
2007-02-27 17:46:48 +00:00
|
|
|
if (temp_key && !temp_key->keylist.empty()) { // emacs-style
|
2007-02-09 18:13:01 +00:00
|
|
|
if (!saved_keymode)
|
|
|
|
saved_keymode = m_keylist;
|
2006-12-19 18:08:33 +00:00
|
|
|
next_key = temp_key;
|
|
|
|
setKeyMode(next_key);
|
2007-01-05 16:54:34 +00:00
|
|
|
grabKey(esc,0);
|
2006-04-12 15:51:37 +00:00
|
|
|
return true;
|
2002-12-01 13:42:15 +00:00
|
|
|
}
|
2006-12-19 18:08:33 +00:00
|
|
|
if (!temp_key || *temp_key->m_command == 0) {
|
2007-02-09 18:13:01 +00:00
|
|
|
if (type == KeyPress && key == esc && mods == 0) {
|
|
|
|
// if we're in the middle of an emacs-style keychain, exit it
|
|
|
|
next_key = 0;
|
|
|
|
if (saved_keymode) {
|
|
|
|
setKeyMode(saved_keymode);
|
|
|
|
saved_keymode = 0;
|
|
|
|
}
|
2006-12-19 18:08:33 +00:00
|
|
|
}
|
2006-04-12 15:51:37 +00:00
|
|
|
return false;
|
2006-12-19 18:08:33 +00:00
|
|
|
}
|
2007-02-09 18:13:01 +00:00
|
|
|
|
2008-02-11 18:17:45 +00:00
|
|
|
WinClient *old = WindowCmd<void>::client();
|
|
|
|
WindowCmd<void>::setClient(current);
|
2006-04-12 15:51:37 +00:00
|
|
|
temp_key->m_command->execute();
|
2008-02-11 18:17:45 +00:00
|
|
|
WindowCmd<void>::setClient(old);
|
|
|
|
|
2006-12-19 18:08:33 +00:00
|
|
|
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;
|
2006-04-12 15:51:37 +00:00
|
|
|
return true;
|
2001-12-11 20:47:02 +00:00
|
|
|
}
|
|
|
|
|
2007-10-13 21:51:37 +00:00
|
|
|
/// adds the window to m_window_map, so we know to grab buttons on it
|
2007-11-20 19:01:45 +00:00
|
|
|
void Keys::registerWindow(Window win, FbTk::EventHandler &h, int context) {
|
2007-10-13 21:51:37 +00:00
|
|
|
m_window_map[win] = context;
|
2007-11-20 19:01:45 +00:00
|
|
|
m_handler_map[win] = &h;
|
2007-10-13 21:51:37 +00:00
|
|
|
grabWindow(win);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// remove the window from the window map, probably being deleted
|
|
|
|
void Keys::unregisterWindow(Window win) {
|
|
|
|
FbTk::KeyUtil::ungrabKeys(win);
|
|
|
|
FbTk::KeyUtil::ungrabButtons(win);
|
2007-11-20 19:01:45 +00:00
|
|
|
m_handler_map.erase(win);
|
2007-10-13 21:51:37 +00:00
|
|
|
m_window_map.erase(win);
|
|
|
|
}
|
|
|
|
|
2003-02-28 23:55:37 +00:00
|
|
|
/**
|
|
|
|
deletes the tree and load configuration
|
|
|
|
returns true on success else false
|
|
|
|
*/
|
2008-05-12 19:16:37 +00:00
|
|
|
void Keys::reconfigure() {
|
|
|
|
m_filename = FbTk::StringUtil::expandFilename(Fluxbox::instance()->getKeysFilename());
|
2008-08-14 05:53:38 +00:00
|
|
|
m_reloader->setMainFile(m_filename);
|
|
|
|
m_reloader->checkReload();
|
2001-12-11 20:47:02 +00:00
|
|
|
}
|
|
|
|
|
2008-01-02 08:28:00 +00:00
|
|
|
void Keys::keyMode(const string& keyMode) {
|
2006-04-12 15:51:37 +00:00
|
|
|
keyspace_t::iterator it = m_map.find(keyMode + ":");
|
|
|
|
if (it == m_map.end())
|
2006-12-19 18:08:33 +00:00
|
|
|
setKeyMode(m_map["default:"]);
|
2006-04-12 15:51:37 +00:00
|
|
|
else
|
2006-12-19 18:08:33 +00:00
|
|
|
setKeyMode(it->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keys::setKeyMode(t_key *keyMode) {
|
2007-01-05 16:54:34 +00:00
|
|
|
ungrabKeys();
|
2007-02-09 18:13:01 +00:00
|
|
|
ungrabButtons();
|
2007-11-20 19:01:45 +00:00
|
|
|
|
|
|
|
// notify handlers that their buttons have been ungrabbed
|
|
|
|
HandlerMap::iterator h_it = m_handler_map.begin(),
|
|
|
|
h_it_end = m_handler_map.end();
|
|
|
|
for (; h_it != h_it_end; ++h_it)
|
|
|
|
h_it->second->grabButtons();
|
|
|
|
|
2008-01-02 08:28:00 +00:00
|
|
|
t_key::keylist_t::iterator it = keyMode->keylist.begin();
|
|
|
|
t_key::keylist_t::iterator it_end = keyMode->keylist.end();
|
2007-02-09 18:13:01 +00:00
|
|
|
for (; it != it_end; ++it) {
|
|
|
|
if ((*it)->type == KeyPress)
|
2007-10-13 21:51:37 +00:00
|
|
|
grabKey((*it)->key, (*it)->mod);
|
|
|
|
else
|
|
|
|
grabButton((*it)->key, (*it)->mod, (*it)->context);
|
2007-02-09 18:13:01 +00:00
|
|
|
}
|
2006-12-19 18:08:33 +00:00
|
|
|
m_keylist = keyMode;
|
2006-04-12 15:51:37 +00:00
|
|
|
}
|
2001-12-11 20:47:02 +00:00
|
|
|
|
|
|
|
|