fluxbox/src/Keys.cc

723 lines
22 KiB
C++
Raw Normal View History

2002-01-08 21:45:49 +00:00
// Keys.cc for Fluxbox - an X11 Window manager
2003-06-10 12:18:26 +00:00
// Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen(at)users.sourceforge.net)
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.
2003-06-10 12:18:26 +00:00
//$Id: Keys.cc,v 1.30 2003/06/10 12:18:26 fluxgen Exp $
2001-12-11 20:47:02 +00:00
#include "Keys.hh"
2002-08-11 21:21:06 +00:00
#include "StringUtil.hh"
2003-02-28 23:55:37 +00:00
#include "App.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
2002-08-11 21:21:06 +00:00
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
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 <iostream>
#include <fstream>
#include <vector>
#include <cassert>
2002-01-08 12:13:25 +00:00
#include <memory>
2001-12-11 20:47:02 +00:00
using namespace std;
Keys::t_actionstr Keys::m_actionlist[] = {
2002-12-01 13:42:15 +00:00
{"Minimize", ICONIFY},
{"Raise", RAISE},
{"Lower", LOWER},
{"RaiseLayer", RAISELAYER},
{"LowerLayer", LOWERLAYER},
{"TopLayer", TOPLAYER},
{"BottomLayer", BOTTOMLAYER},
{"AlwaysOnTop", TOPLAYER},
{"AlwaysOnBottom", BOTTOMLAYER},
2002-12-01 13:42:15 +00:00
{"Close", CLOSE},
{"AbortKeychain", ABORTKEYCHAIN},
{"Workspace", WORKSPACE},
{"Workspace1", WORKSPACE1},
{"Workspace2", WORKSPACE2},
{"Workspace3", WORKSPACE3},
{"Workspace4", WORKSPACE4},
{"Workspace5", WORKSPACE5},
{"Workspace6", WORKSPACE6},
{"Workspace7", WORKSPACE7},
{"Workspace8", WORKSPACE8},
{"Workspace9", WORKSPACE9},
{"Workspace10", WORKSPACE10},
{"Workspace11", WORKSPACE11},
{"Workspace12", WORKSPACE12},
{"SendToWorkspace", SENDTOWORKSPACE},
{"NextWorkspace", NEXTWORKSPACE},
{"PrevWorkspace", PREVWORKSPACE},
{"LeftWorkspace", LEFTWORKSPACE},
{"RightWorkspace", RIGHTWORKSPACE},
{"KillWindow", KILLWINDOW},
{"NextWindow", NEXTWINDOW},
{"PrevWindow", PREVWINDOW},
{"NextTab", NEXTTAB},
{"PrevTab", PREVTAB},
{"FirstTab", FIRSTTAB},
{"LastTab", LASTTAB},
{"MoveTabPrev", MOVETABPREV},
{"MoveTabNext", MOVETABNEXT},
2003-04-14 12:13:36 +00:00
{"AttachLast", ATTACHLAST},
{"DetachClient", DETACHCLIENT},
{"FocusUp", FOCUSUP},
{"FocusDown", FOCUSDOWN},
{"FocusLeft", FOCUSLEFT},
{"FocusRight", FOCUSRIGHT},
2002-12-01 13:42:15 +00:00
{"ShadeWindow", SHADE},
{"MaximizeWindow", MAXIMIZE},
{"StickWindow", STICK},
{"ExecCommand", EXECUTE},
{"MaximizeVertical", VERTMAX},
{"MaximizeHorizontal", HORIZMAX},
{"NudgeRight", NUDGERIGHT},
{"NudgeLeft", NUDGELEFT},
{"NudgeUp", NUDGEUP},
{"NudgeDown", NUDGEDOWN},
{"BigNudgeRight", BIGNUDGERIGHT},
{"BigNudgeLeft", BIGNUDGELEFT},
{"BigNudgeUp", BIGNUDGEUP},
{"BigNudgeDown", BIGNUDGEDOWN},
{"HorizontalIncrement", HORIZINC},
{"VerticalIncrement", VERTINC},
{"HorizontalDecrement", HORIZDEC},
{"VerticalDecrement", VERTDEC},
{"ToggleDecor", TOGGLEDECOR},
{"ToggleTab", TOGGLETAB},
{"RootMenu", ROOTMENU},
2003-06-08 14:32:28 +00:00
{"Reconfigure", RECONFIGURE},
{"Restart", RESTART},
{"Quit", QUIT},
2002-12-01 13:42:15 +00:00
{0, LASTKEYGRAB}
};
2001-12-11 20:47:02 +00:00
2003-02-28 23:55:37 +00:00
Keys::Keys(const char *filename):
2002-12-01 13:42:15 +00:00
m_capslock_mod(0),
m_numlock_mod(0),
m_scrolllock_mod(0),
m_abortkey(0),
m_display(FbTk::App::instance()->display()),
m_modmap(0)
{
loadModmap();
2002-12-01 13:42:15 +00:00
if (filename != 0)
load(filename);
2001-12-11 20:47:02 +00:00
}
2002-01-08 21:45:49 +00:00
Keys::~Keys() {
if (m_modmap) {
XFreeModifiermap(m_modmap);
}
2002-12-01 13:42:15 +00:00
ungrabKeys();
deleteTree();
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/// Destroys the keytree and m_abortkey
2001-12-11 20:47:02 +00:00
void Keys::deleteTree() {
2002-12-01 13:42:15 +00:00
while (!m_keylist.empty()) {
if (m_keylist.back() && m_keylist.back() != 0)
delete m_keylist.back();
m_keylist.pop_back();
}
if (m_abortkey) {
delete m_abortkey;
m_abortkey=0;
}
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/// Ungrabs the keys
void Keys::ungrabKeys() {
2002-12-01 13:42:15 +00:00
for (int screen=0; screen<ScreenCount(m_display); screen++) {
XUngrabKey(m_display, AnyKey, AnyModifier,
RootWindow(m_display, screen));
}
}
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;
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
//ungrab all keys
ungrabKeys();
2002-08-11 21:21:06 +00:00
2002-12-01 13:42:15 +00:00
//free memory of previous grabs
deleteTree();
2002-08-11 21:21:06 +00:00
2002-12-01 13:42:15 +00:00
XSync(m_display, False);
2001-12-11 20:47:02 +00:00
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
2002-12-01 13:42:15 +00:00
int line=0;//current line, 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
2002-12-01 13:42:15 +00:00
line++;
vector<string> val;
//Parse arguments
2003-04-26 18:27:56 +00:00
FbTk::StringUtil::stringtok(val, linebuffer.c_str());
2002-08-11 21:21:06 +00:00
2002-12-01 13:42:15 +00:00
//must have at least 1 argument
if (val.size() <= 0)
continue;
2002-12-01 13:42:15 +00:00
if (val[0][0] == '#') //the line is commented
continue;
2002-12-01 13:42:15 +00:00
unsigned int key=0, mod=0;
char keyarg=0;
t_key *current_key=0, *last_key=0;
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
for (unsigned int argc=0; argc<val.size(); argc++) {
2003-02-28 23:55:37 +00:00
if (val[argc][0] != ':') {
2002-12-01 13:42:15 +00:00
keyarg++;
if (keyarg==1) //first arg is modifier
mod = getModifier(val[argc].c_str());
else if (keyarg>1) {
//keyarg=0;
2003-02-28 23:55:37 +00:00
int tmpmod = getModifier(val[argc].c_str());
2002-12-01 13:42:15 +00:00
if(tmpmod)
mod|=tmpmod; //If it's a modifier
else {
key = getKey(val[argc].c_str()); // else get the key
if (key == 0) {
cerr<<"["<<filename<<"]: Invalid key/modifier on line("<<
line<<"): "<<linebuffer<<endl;
break; // get next line
}
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;
}
}
}
} else {
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
unsigned int i=0;
for (i=0; i< LASTKEYGRAB; i++) {
// +1 on the val[argc] because we dont want to compare the ':'
if (strcasecmp(m_actionlist[i].string, val[argc].c_str()+1) == 0) {
2002-12-01 13:42:15 +00:00
break;
}
2002-12-01 13:42:15 +00:00
}
if (i < LASTKEYGRAB ) {
if (!current_key) {
cerr<<"Error on line: "<<line<<endl;
cerr<<linebuffer<<endl;
delete current_key;
current_key = 0;
last_key = 0;
break; //break out and read next line
}
//special case for grabAbortKeychain
if (m_actionlist[i].action == ABORTKEYCHAIN) {
if (last_key!=current_key)
cerr<<"Keys: "<<m_actionlist[i].string<<" cant be in chained mode"<<endl;
else if (m_abortkey)
cerr<<"Keys: "<<m_actionlist[i].string<<" is already bound."<<endl;
else
m_abortkey = new t_key(current_key->key, current_key->mod, ABORTKEYCHAIN);
delete current_key;
current_key = 0;
last_key = 0;
break; //break out and read next line
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
last_key->action = m_actionlist[i].action;
2003-06-10 12:18:26 +00:00
2002-12-01 13:42:15 +00:00
switch(last_key->action) {
2003-06-08 14:32:28 +00:00
case Keys::RESTART:
2003-06-08 14:54:05 +00:00
case Keys::EXECUTE: {
// skip past the command
const char *str =
FbTk::StringUtil::strcasestr(
2003-06-08 14:32:28 +00:00
linebuffer.c_str(),
getActionStr(last_key->action))
2003-06-08 14:54:05 +00:00
+ strlen(getActionStr(last_key->action));
int i=0;
// skip past any trailing whitespace
while (str[i] == ' ' || str[i] == '\t')
++i;
last_key->execcommand = str + i;
} break;
2002-12-01 13:42:15 +00:00
case WORKSPACE:
case SENDTOWORKSPACE:
if (argc + 1 < val.size())
last_key->param = atoi( val[argc+1].c_str());
else
last_key->param = 0;
break;
case NEXTWINDOW:
case PREVWINDOW:
if (argc + 1 < val.size())
last_key->param = atoi( val[argc+1].c_str());
else
last_key->param = 0;
break;
case LEFTWORKSPACE:
case RIGHTWORKSPACE:
case NEXTWORKSPACE:
case PREVWORKSPACE:
if (argc + 1 < val.size())
last_key->param = atoi( val[argc+1].c_str());
else
last_key->param = 1;
break;
case NUDGERIGHT:
case NUDGELEFT:
case NUDGEUP:
case NUDGEDOWN:
if (argc + 1 < val.size())
last_key->param = atoi( val[argc+1].c_str());
else
last_key->param = 2;
break;
default:
break;
}
//add the keychain to list
if (!mergeTree(current_key))
cerr<<"Keys: Failed to merge keytree!"<<endl;
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
//clear keypointers now that we have them in m_keylist
delete current_key;
current_key = 0;
last_key = 0;
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
} else { //destroy list if no action is found
2002-08-11 21:21:06 +00:00
#ifdef DEBUG
2002-12-01 13:42:15 +00:00
cerr<<"Didnt find action="<<val[argc]<<endl;
2002-08-11 21:21:06 +00:00
#endif // DEBUG
2002-12-01 13:42:15 +00:00
//destroy current_key ... this will also destroy the last_key
delete current_key;
current_key = 0;
last_key = 0;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
break; //dont process this linebuffer more
2003-02-28 23:55:37 +00:00
} // end if
} // end for
} // end while
2002-12-01 13:42:15 +00:00
return true;
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
Grabs a key with the modifier
and with numlock,capslock and scrollock
*/
2001-12-11 20:47:02 +00:00
void Keys::grabKey(unsigned int key, unsigned int mod) {
2002-12-01 13:42:15 +00:00
for (int screen=0; screen<ScreenCount(m_display); screen++) {
2002-12-01 13:42:15 +00:00
Window root = RootWindow(m_display, screen);
2002-12-01 13:42:15 +00:00
XGrabKey(m_display, key, mod,
root, True,
GrabModeAsync, GrabModeAsync);
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
// Grab with numlock, capslock and scrlock
//numlock
XGrabKey(m_display, key, mod|m_numlock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
//scrolllock
XGrabKey(m_display, key, mod|m_scrolllock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
//capslock
XGrabKey(m_display, key, mod|m_capslock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
//capslock+numlock
XGrabKey(m_display, key, mod|m_capslock_mod|m_numlock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
//capslock+scrolllock
XGrabKey(m_display, key, mod|m_capslock_mod|m_scrolllock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
//capslock+numlock+scrolllock
XGrabKey(m_display, key, mod|m_capslock_mod|m_scrolllock_mod|m_numlock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
//numlock+scrollLock
XGrabKey(m_display, key, mod|m_numlock_mod|m_scrolllock_mod,
root, True,
GrabModeAsync, GrabModeAsync);
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
}
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
@return the modifier for the modstr else zero on failure.
TODO fix more masks
*/
unsigned int Keys::getModifier(const char *modstr) {
2002-12-01 13:42:15 +00:00
if (!modstr)
return 0;
struct t_modlist{
char *string;
unsigned int mask;
bool operator == (const char *modstr) {
return (strcasecmp(string, modstr) == 0 && mask !=0);
}
} modlist[] = {
{"SHIFT", ShiftMask},
{"CONTROL", ControlMask},
{"MOD1", Mod1Mask},
{"MOD2", Mod2Mask},
{"MOD3", Mod3Mask},
{"MOD4", Mod4Mask},
{"MOD5", Mod5Mask},
{0, 0}
};
// find mod mask string
for (unsigned int i=0; modlist[i].string!=0; i++) {
if (modlist[i] == modstr)
return modlist[i].mask;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
return 0;
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
@return keycode of keystr on success else 0
*/
unsigned int Keys::getKey(const char *keystr) {
2002-12-01 13:42:15 +00:00
if (!keystr)
return 0;
return XKeysymToKeycode(m_display,
XStringToKeysym(keystr));
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
@return the KeyAction of the XKeyEvent
*/
2001-12-11 20:47:02 +00:00
Keys::KeyAction Keys::getAction(XKeyEvent *ke) {
2002-12-01 13:42:15 +00:00
static t_key *next_key = 0;
//remove numlock, capslock and scrolllock
ke->state = cleanMods(ke->state);
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
if (m_abortkey && *m_abortkey==ke) { //abort current keychain
next_key = 0;
return m_abortkey->action;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
if (!next_key) {
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
for (unsigned int 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 {
2003-06-08 14:32:28 +00:00
if (m_keylist[i]->action == Keys::EXECUTE ||
m_keylist[i]->action == Keys::RESTART)
2002-12-01 13:42:15 +00:00
m_execcmdstring = m_keylist[i]->execcommand; //update execcmdstring if action is grabExecute
m_param = m_keylist[i]->param;
return m_keylist[i]->action;
}
}
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
} 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;
2003-06-08 14:32:28 +00:00
if (temp_key->action == Keys::EXECUTE ||
temp_key->action == Keys::RESTART)
2002-12-01 13:42:15 +00:00
m_execcmdstring = temp_key->execcommand; //update execcmdstring if action is grabExecute
return temp_key->action;
}
} else {
temp_key = next_key;
next_key = 0;
2003-06-08 14:32:28 +00:00
if (temp_key->action == Keys::EXECUTE ||
temp_key->action == Keys::RESTART)
2002-12-01 13:42:15 +00:00
m_execcmdstring = temp_key->execcommand; //update execcmdstring if action is grabExecute
return temp_key->action;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
return Keys::LASTKEYGRAB;
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
deleteTree();
return load(filename);
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
Tries to find the action for the key
@return actionstring on success else 0 on failure
*/
2001-12-11 20:47:02 +00:00
const char *Keys::getActionStr(KeyAction action) {
2002-12-01 13:42:15 +00:00
for (unsigned int i=0; m_actionlist[i].string!=0 ; i++) {
if (m_actionlist[i].action == action)
return m_actionlist[i].string;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
return 0;
2001-12-11 20:47:02 +00:00
}
#ifdef DEBUG
2003-02-28 23:55:37 +00:00
/*
Debug function that show the
keytree. Starts with the rootlist
*/
2001-12-11 20:47:02 +00:00
void Keys::showTree() {
2002-12-01 13:42:15 +00:00
for (unsigned int i=0; i<m_keylist.size(); i++) {
if (m_keylist[i]) {
cerr<<i<<" ";
showKeyTree(m_keylist[i]);
} else
cerr<<"Null @ "<<i<<endl;
}
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
Debug function to show t_key tree
*/
2001-12-11 20:47:02 +00:00
void Keys::showKeyTree(t_key *key, unsigned int w) {
2002-12-01 13:42:15 +00:00
for (unsigned int i=0; i<w+1; i++)
cerr<<"-";
if (!key->keylist.empty()) {
for (unsigned int i=0; i<key->keylist.size(); i++) {
cerr<<"( "<<(int)key->key<<" "<<(int)key->mod<<" )";
showKeyTree(key->keylist[i], 4);
cerr<<endl;
}
} else
cerr<<"( "<<(int)key->key<<" "<<(int)key->mod<<" ) {"<<getActionStr(key->action)<<"}"<<endl;
2001-12-11 20:47:02 +00:00
}
#endif //DEBUG
2002-08-11 21:21:06 +00:00
2003-02-28 23:55:37 +00:00
/**
Merges two chains and binds new keys
@return true on success else false.
*/
2001-12-11 20:47:02 +00:00
bool Keys::mergeTree(t_key *newtree, t_key *basetree) {
2002-12-01 13:42:15 +00:00
if (basetree==0) {
unsigned int baselist_i=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]->action == LASTKEYGRAB) {
//assumes the newtree only have one branch
return mergeTree(newtree->keylist[0], m_keylist[baselist_i]);
} else
break;
}
}
if (baselist_i == m_keylist.size()) {
grabKey(newtree->key, newtree->mod);
m_keylist.push_back(new t_key(newtree));
if (newtree->keylist.size())
return mergeTree(newtree->keylist[0], m_keylist.back());
return true;
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
} else {
unsigned int baselist_i = 0;
for (; baselist_i<basetree->keylist.size(); baselist_i++) {
if (basetree->keylist[baselist_i]->mod == newtree->mod &&
basetree->keylist[baselist_i]->key == newtree->key) {
if (newtree->keylist.size()) {
//assumes the newtree only have on branch
return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]);
} else
return false;
}
}
//if it wasn't in the list grab the key and add it to the list
if (baselist_i==basetree->keylist.size()) {
grabKey(newtree->key, newtree->mod);
basetree->keylist.push_back(new t_key(newtree));
if (newtree->keylist.size())
return mergeTree(newtree->keylist[0], basetree->keylist.back());
return true;
}
}
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
return false;
2001-12-11 20:47:02 +00:00
}
Keys::t_key::t_key(unsigned int key_, unsigned int mod_, KeyAction action_) {
2002-12-01 13:42:15 +00:00
action = action_;
key = key_;
mod = mod_;
param = 0;
2001-12-11 20:47:02 +00:00
}
Keys::t_key::t_key(t_key *k) {
2002-12-01 13:42:15 +00:00
action = k->action;
key = k->key;
mod = k->mod;
execcommand = k->execcommand;
param = k-> param;
2001-12-11 20:47:02 +00:00
}
Keys::t_key::~t_key() {
2002-12-01 13:42:15 +00:00
while (!keylist.empty()) {
t_key *k = keylist.back();
if (k != 0) { // make sure we don't have a bad key pointer
delete k;
keylist.pop_back();
}
}
2001-12-11 20:47:02 +00:00
}
2002-11-13 14:35:01 +00:00
2003-02-28 23:55:37 +00:00
/**
* load state relating to the modifier map
*/
void Keys::loadModmap() {
if (m_modmap) {
XFreeModifiermap(m_modmap);
}
m_modmap = XGetModifierMapping(m_display);
2002-12-01 13:42:15 +00:00
// mask to use for modifier
int mods[] = {
ShiftMask,
LockMask,
ControlMask,
Mod1Mask,
Mod2Mask,
Mod3Mask,
Mod4Mask,
Mod5Mask,
0
};
2002-11-13 14:35:01 +00:00
2002-12-01 13:42:15 +00:00
// find modifiers and set them
for (int i=0, realkey=0; i<8; ++i) {
for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
2002-12-01 13:42:15 +00:00
if (m_modmap->modifiermap[realkey] == 0)
2002-12-01 13:42:15 +00:00
continue;
KeySym ks = XKeycodeToKeysym(m_display, m_modmap->modifiermap[realkey], 0);
2002-12-01 13:42:15 +00:00
switch (ks) {
case XK_Caps_Lock:
m_capslock_mod = mods[i];
break;
case XK_Scroll_Lock:
m_scrolllock_mod = mods[i];
break;
case XK_Num_Lock:
m_numlock_mod = mods[i];
break;
}
}
}
}
unsigned int Keys::keycodeToModmask(unsigned int keycode) {
if (!m_modmap) return 0;
// search through modmap for this keycode
for (int mod=0; mod < 8; mod++) {
for (int key=0; key < m_modmap->max_keypermod; ++key) {
// modifiermap is an array with 8 sets of keycodes
// each max_keypermod long, but in a linear array.
if (m_modmap->modifiermap[m_modmap->max_keypermod*mod + key] == keycode) {
return (1<<mod);
}
}
}
// no luck
return 0;
2002-11-13 14:35:01 +00:00
}