fluxbox/src/Keys.cc

351 lines
9.4 KiB
C++
Raw Normal View History

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.
2004-11-19 11:37:27 +00:00
//$Id$
2001-12-11 20:47:02 +00:00
#include "Keys.hh"
2002-08-11 21:21:06 +00:00
#include "FbTk/StringUtil.hh"
#include "FbTk/App.hh"
#include "FbTk/Command.hh"
#include "CommandParser.hh"
2004-06-07 11:46:05 +00:00
#include "FbTk/I18n.hh"
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
#ifdef HAVE_CTYPE_H
#include <ctype.h>
2002-02-21 00:39:08 +00:00
#endif // HAVE_CTYPE_H
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
#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
#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
#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
#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/Xlib.h>
#include <X11/Xproto.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
2001-12-11 20:47:02 +00:00
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
2002-01-08 12:13:25 +00:00
#include <memory>
2001-12-11 20:47:02 +00:00
using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::ifstream;
using std::pair;
2001-12-11 20:47:02 +00:00
Keys::Keys():
m_display(FbTk::App::instance()->display())
{
2003-08-19 16:19:28 +00:00
2001-12-11 20:47:02 +00:00
}
Keys::~Keys() {
FbTk::KeyUtil::ungrabKeys();
2002-12-01 13:42:15 +00:00
deleteTree();
2001-12-11 20:47:02 +00:00
}
2003-08-19 16:19:28 +00:00
/// Destroys the keytree
2001-12-11 20:47:02 +00:00
void Keys::deleteTree() {
for (keyspace_t::iterator map_it = m_map.begin(); map_it != m_map.end(); ++map_it)
delete map_it->second;
2006-04-22 15:37:04 +00:00
m_map.clear();
2001-12-11 20:47:02 +00:00
}
/**
2003-02-28 23:55:37 +00:00
Load and grab keys
TODO: error checking
@return true on success else false
*/
bool Keys::load(const char *filename) {
2002-12-01 13:42:15 +00:00
if (!filename)
return false;
2002-12-01 13:42:15 +00:00
//free memory of previous grabs
deleteTree();
2002-08-11 21:21:06 +00:00
m_map["default:"] = new t_key(0,0);
2003-12-04 21:31:02 +00:00
FbTk::App::instance()->sync(false);
2002-12-01 13:42:15 +00:00
//open the file
ifstream infile(filename);
if (!infile)
return false; // faild to open file
2002-08-11 21:21:06 +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
current_line++;
2002-08-11 21:21:06 +00:00
if (!addBinding(linebuffer)) {
2006-12-20 16:22:10 +00:00
_FB_USES_NLS;
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
m_filename = filename;
keyMode("default");
2003-12-20 17:37:57 +00:00
return true;
}
bool Keys::save(const char *filename) const {
//!!
//!! TODO: fix keybinding saving
//!! (we probably need to save key actions
2003-12-20 17:37:57 +00:00
//!! as strings instead of creating new Commands)
// open file for writing
// ofstream outfile(filename);
// if (!outfile)
return false;
// return true;
}
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
if (val.size() <= 0)
return true; // empty lines are valid.
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.
2003-12-20 17:37:57 +00:00
unsigned int key = 0, mod = 0;
size_t argc = 0;
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 t_key(0,0);
current_key = m_map[val[0]];
}
// for each argument
for (; argc < val.size(); argc++) {
2003-12-20 17:37:57 +00:00
if (val[argc][0] != ':') { // parse key(s)
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())) {
// 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);
if (errno == EINVAL || errno == ERANGE)
key = 0;
} else // convert from string symbol
key = FbTk::KeyUtil::getKey(val[argc].c_str());
if (key == 0)
return false;
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);
current_key->keylist.push_back(temp_key);
current_key = temp_key;
2003-07-02 05:42:21 +00:00
}
mod = 0;
key = 0;
}
2003-06-30 19:42:20 +00:00
2003-12-20 17:37:57 +00:00
} else { // parse command line
if (!first_new_key)
2003-12-20 17:37:57 +00:00
return false;
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 (!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
}
// return true if bound to a command, else false
bool Keys::doAction(XKeyEvent &ke) {
2003-12-30 18:14:33 +00:00
ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
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 (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;
2002-12-01 13:42:15 +00:00
}
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;
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
deletes the tree and load configuration
returns true on success else false
*/
bool Keys::reconfigure(const char *filename) {
2002-12-01 13:42:15 +00:00
return load(filename);
2001-12-11 20:47:02 +00:00
}
void Keys::keyMode(string keyMode) {
keyspace_t::iterator it = m_map.find(keyMode + ":");
if (it == m_map.end())
setKeyMode(m_map["default:"]);
else
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) {
2002-12-01 13:42:15 +00:00
key = key_;
mod = mod_;
m_command = command;
2001-12-11 20:47:02 +00:00
}
Keys::t_key::t_key(t_key *k) {
2002-12-01 13:42:15 +00:00
key = k->key;
mod = k->mod;
m_command = k->m_command;
2001-12-11 20:47:02 +00:00
}
Keys::t_key::~t_key() {
for (keylist_t::iterator list_it = keylist.begin(); list_it != keylist.end(); ++list_it)
delete *list_it;
keylist.clear();
2001-12-11 20:47:02 +00:00
}