aboutsummaryrefslogtreecommitdiff
path: root/src/Keys.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Keys.cc')
-rw-r--r--src/Keys.cc583
1 files changed, 583 insertions, 0 deletions
diff --git a/src/Keys.cc b/src/Keys.cc
new file mode 100644
index 0000000..fad11af
--- /dev/null
+++ b/src/Keys.cc
@@ -0,0 +1,583 @@
1// Key2.cc for Fluxbox - an X11 Window manager
2// Copyright (c) 2001 Henrik Kinnunen (fluxgen@linuxmail.org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22
23#ifdef HAVE_CONFIG_H
24# include "config.h"
25#endif
26
27#ifdef HAVE_STDIO_H
28# include <stdio.h>
29#endif // HAVE_STDIO_H
30
31#ifdef HAVE_CTYPE_H
32# include <ctype.h>
33#endif // HAVE_CTYPE_H
34
35#ifdef STDC_HEADERS
36# include <stdlib.h>
37# include <string.h>
38# include <errno.h>
39#endif // STDC_HEADERS
40
41#if HAVE_STRINGS_H
42# include <strings.h>
43#endif
44
45#ifdef HAVE_SYS_TYPES_H
46# include <sys/types.h>
47#endif // HAVE_SYS_TYPES_H
48
49#ifdef HAVE_SYS_WAIT_H
50# include <sys/wait.h>
51#endif // HAVE_SYS_WAIT_H
52
53#ifdef HAVE_UNISTD_H
54# include <unistd.h>
55#endif // HAVE_UNISTD_H
56
57#ifdef HAVE_SYS_STAT_H
58# include <sys/stat.h>
59#endif // HAVE_SYS_STAT_H
60
61#include <X11/Xlib.h>
62#include <X11/Xproto.h>
63#include <X11/keysym.h>
64
65#include "Keys.hh"
66#include "fluxbox.hh"
67
68#include <iostream>
69#include <fstream>
70
71using namespace std;
72
73Keys::t_actionstr Keys::m_actionlist[] = {
74 {"Minimize", grabIconify},
75 {"Raise", grabRaise},
76 {"Lower", grabLower},
77 {"Close", grabClose},
78 {"AbortKeychain", grabAbortKeychain},
79 {"Workspace1", grabWorkspace1},
80 {"Workspace2", grabWorkspace2},
81 {"Workspace3", grabWorkspace3},
82 {"Workspace4", grabWorkspace4},
83 {"Workspace5", grabWorkspace5},
84 {"Workspace6", grabWorkspace6},
85 {"Workspace7", grabWorkspace7},
86 {"Workspace8", grabWorkspace8},
87 {"Workspace9", grabWorkspace9},
88 {"Workspace10", grabWorkspace10},
89 {"Workspace11", grabWorkspace11},
90 {"Workspace12", grabWorkspace12},
91 {"NextWorkspace", grabNextWorkspace},
92 {"PrevWorkspace", grabPrevWorkspace},
93 {"LeftWorkspace", grabLeftWorkspace},
94 {"RightWorkspace", grabRightWorkspace},
95 {"KillWindow", grabKillWindow},
96 {"NextWindow", grabNextWindow},
97 {"PrevWindow", grabPrevWindow},
98 {"NextTab", grabNextTab},
99 {"PrevTab", grabPrevTab},
100 {"ShadeWindow", grabShade},
101 {"MaximizeWindow", grabMaximize},
102 {"StickWindow", grabStick},
103 {"ExecCommand", grabExecute},
104 {"MaximizeVertical", grabVertMax},
105 {"MaximizeHorizontal", grabHorizMax},
106 {"NudgeRight", grabNudgeRight},
107 {"NudgeLeft", grabNudgeLeft},
108 {"NudgeUp", grabNudgeUp},
109 {"NudgeDown", grabNudgeDown},
110 {"BigNudgeRight", grabBigNudgeRight},
111 {"BigNudgeLeft", grabBigNudgeLeft},
112 {"BigNudgeUp", grabBigNudgeUp},
113 {"BigNudgeDown", grabBigNudgeDown},
114 {"HorizontalIncrement", grabHorizInc},
115 {"VerticalIncrement", grabVertInc},
116 {"HorizontalDecrement", grabHorizDec},
117 {"VerticalDecrement", grabVertDec},
118 {"ToggleDecor", grabToggleDecor},
119 {0, lastKeygrab}
120 };
121
122Keys::Keys(char *filename) {
123 m_abortkey=0;
124 load(filename);
125}
126
127Keys::~Keys() {
128 deleteTree();
129}
130//--------- deleteTree -----------
131// Destroys the keytree and m_abortkey
132//--------------------------------
133void Keys::deleteTree() {
134 while (!m_keylist.empty()) {
135 if (m_keylist.back())
136 delete m_keylist.back();
137 m_keylist.pop_back();
138 }
139 if (m_abortkey) {
140 delete m_abortkey;
141 m_abortkey=0;
142 }
143}
144//-------------- load ----------------
145// Load and grab keys
146// Returns true on success else false
147// TODO: error checking and nls on them?
148// and possible replacement of strtok
149//------------------------------------
150bool Keys::load(char *filename) {
151 if (!filename)
152 return false;
153
154 Fluxbox *fluxbox = Fluxbox::instance();
155 Display *display = fluxbox->getXDisplay();
156 ScreenInfo *screeninfo=0;
157 //ungrab all keys
158 int screen=0;
159 while ((screeninfo = fluxbox->getScreenInfo(screen++)) ) {
160 XUngrabKey(display, AnyKey, AnyModifier,
161 screeninfo->getRootWindow());
162 }
163
164 XSync(display, False);
165
166 //open the file
167 ifstream infile(filename);
168 if (!infile)
169 return false;
170
171
172 char *linebuffer = new char[1024];
173 int line=0;
174 int linepos=0; //position in the line
175
176 while (!infile.eof()) {
177 infile.getline(linebuffer, 1024);
178
179 line++;
180 char *val = strtok(linebuffer, " ");
181 linepos = (val==0 ? 0 : strlen(val) + 1);
182
183 int numarg = 1;
184 unsigned int key=0, mod=0;
185 char keyarg=0;
186 t_key *current_key=0, *last_key=0;
187
188 while (val) {
189
190 if (val[0]!=':') {
191 keyarg++;
192 if (keyarg==1) //first arg is modifier
193 mod = getModifier(val);
194 else if (keyarg>1) {
195
196 //keyarg=0;
197 key = getKey(val);
198 if (!key){ //if no keycode was found try the modifier
199 int tmpmod = getModifier(val);
200 if (tmpmod)
201 mod |= tmpmod; //add it to modifier
202
203 } else if (!current_key) {
204
205 current_key = new t_key(key, mod);
206 last_key = current_key;
207
208 } else {
209
210 t_key *temp_key = new t_key(key, mod);
211 last_key->keylist.push_back(temp_key);
212 last_key = temp_key;
213 }
214
215 }
216
217 } else {
218
219 val++; //ignore the ':'
220
221 unsigned int i=0;
222
223 for (i=0; i< lastKeygrab; i++) {
224 if (strcasecmp(m_actionlist[i].string, val) == 0)
225 break;
226 }
227
228 if (i < lastKeygrab ) {
229 if (!current_key) {
230 cerr<<"Error on line: "<<line<<endl;
231 cerr<<linebuffer<<endl;
232 delete current_key;
233 current_key = 0;
234 last_key = 0;
235 break; //break out and read next line
236 }
237
238 //special case for grabAbortKeychain
239 if (m_actionlist[i].action == grabAbortKeychain) {
240 if (last_key!=current_key)
241 cerr<<"Keys: "<<m_actionlist[i].string<<" cant be in chained mode"<<endl;
242 else if (m_abortkey)
243 cerr<<"Keys: "<<m_actionlist[i].string<<" is already bound."<<endl;
244 else
245 m_abortkey = new t_key(current_key->key, current_key->mod, grabAbortKeychain);
246
247 delete current_key;
248 current_key = 0;
249 last_key = 0;
250 break; //break out and read next line
251 }
252
253 last_key->action = m_actionlist[i].action;
254 if (last_key->action == grabExecute)
255 last_key->execcommand = &linebuffer[linepos];
256
257 //add the keychain to list
258 if (!mergeTree(current_key))
259 cerr<<"Keys: Faild to merge keytree!"<<endl;
260
261 #ifdef DEBUG
262 if (m_actionlist[i].action == Keys::grabExecute) {
263
264 cerr<<"linepos:"<<linepos<<endl;
265 cerr<<"buffer:"<<&linebuffer[linepos]<<endl;
266 cerr<<"command:"<<last_key->execcommand<<endl;
267
268 }
269 #endif
270
271 //clear keypointers now that we have them in m_keylist
272 delete current_key;
273 current_key = 0;
274 last_key = 0;
275
276 } else { //destroy list if no action is found
277 #ifdef DEBUG
278 cerr<<"Didnt find action="<<val<<endl;
279 #endif
280 //destroy current_key ... this will also destroy the last_key
281 delete current_key;
282 current_key = 0;
283 last_key = 0;
284 }
285
286 break; //dont process this linebuffer more
287 }
288 numarg++;
289 val = strtok(0, " ");
290 linepos += (val == 0 ? 0 : strlen(val) + 1);
291 }
292 }
293
294 delete linebuffer;
295 #ifdef DEBUG
296 showTree();
297 #endif
298 return true;
299}
300
301//--------- grabKey ---------------
302// Grabs a key with the modifier
303// and with numlock,capslock and scrollock
304//---------------------------------
305void Keys::grabKey(unsigned int key, unsigned int mod) {
306
307 Fluxbox *fluxbox = Fluxbox::instance();
308 Display *display = fluxbox->getXDisplay();
309
310 #ifdef DEBUG
311 cerr<<__FILE__<<"("<<__LINE__<<"): keycode "<<key<<" mod "<<hex<<mod<<dec<<endl;
312 #endif
313 int i=0;
314 ScreenInfo *screeninfo=0;
315
316 while ((screeninfo = fluxbox->getScreenInfo(i++)) ) {
317 Window root = screeninfo->getRootWindow();
318 XGrabKey(display, key, mod,
319 root, True,
320 GrabModeAsync, GrabModeAsync);
321
322 // Grab with numlock, capslock and scrlock
323
324 //numlock
325 XGrabKey(display, key, mod|Mod2Mask,
326 root, True,
327 GrabModeAsync, GrabModeAsync);
328 //scrolllock
329 XGrabKey(display, key, mod|Mod5Mask,
330 root, True,
331 GrabModeAsync, GrabModeAsync);
332 //capslock
333 XGrabKey(display, key, mod|LockMask,
334 root, True,
335 GrabModeAsync, GrabModeAsync);
336
337 //capslock+numlock
338 XGrabKey(display, key, mod|LockMask|Mod2Mask,
339 root, True,
340 GrabModeAsync, GrabModeAsync);
341
342 //capslock+scrolllock
343 XGrabKey(display, key, mod|LockMask|Mod5Mask,
344 root, True,
345 GrabModeAsync, GrabModeAsync);
346
347 //capslock+numlock+scrolllock
348 XGrabKey(display, key, mod|Mod2Mask|Mod5Mask|LockMask,
349 root, True,
350 GrabModeAsync, GrabModeAsync);
351
352 //numlock+scrollLock
353 XGrabKey(display, key, mod|Mod2Mask|Mod5Mask,
354 root, True,
355 GrabModeAsync, GrabModeAsync);
356
357 }
358
359}
360
361//------------ getModifier ---------------
362// Returns the modifier for the modstr
363// else zero on failure.
364// TODO fix more masks
365//----------------------------------------
366unsigned int Keys::getModifier(char *modstr) {
367 if (!modstr)
368 return 0;
369 struct t_modlist{
370 char *string;
371 unsigned int mask;
372 bool operator == (char *modstr) {
373 return (strcasecmp(string, modstr) == 0 && mask !=0);
374 }
375 } modlist[] = {
376 {"SHIFT", ShiftMask},
377 {"CONTROL", ControlMask},
378 {"MOD1", Mod1Mask},
379 {"MOD2", Mod2Mask},
380 {"MOD3", Mod3Mask},
381 {"MOD4", Mod4Mask},
382 {"MOD5", Mod5Mask},
383 {0, 0}
384 };
385
386 for (unsigned int i=0; modlist[i].string!=0; i++) {
387 if (modlist[i]==modstr)
388 return modlist[i].mask;
389 }
390
391 return 0;
392}
393
394//----------- getKey ----------------
395// Returns keycode of keystr on success
396// else it returns zero
397//-----------------------------------
398unsigned int Keys::getKey(char *keystr) {
399 if (!keystr)
400 return 0;
401 return XKeysymToKeycode(Fluxbox::instance()->getXDisplay(),
402 XStringToKeysym
403 (keystr));
404}
405
406//--------- getAction -----------------
407// returns the KeyAction of the XKeyEvent
408//-------------------------------------
409Keys::KeyAction Keys::getAction(XKeyEvent *ke) {
410 static t_key *next_key = 0;
411 //remove numlock, capslock and scrolllock
412 ke->state &= ~Mod2Mask & ~Mod5Mask & ~LockMask;
413
414 if (m_abortkey && *m_abortkey==ke) { //abort current keychain
415 next_key = 0;
416 return m_abortkey->action;
417 }
418
419 if (!next_key) {
420
421 for (unsigned int i=0; i<m_keylist.size(); i++) {
422 if (*m_keylist[i] == ke) {
423 if (m_keylist[i]->keylist.size()) {
424 next_key = m_keylist[i];
425 break; //end for-loop
426 } else {
427 if (m_keylist[i]->action == grabExecute)
428 m_execcmdstring = m_keylist[i]->execcommand; //update execcmdstring if action is grabExecute
429 return m_keylist[i]->action;
430 }
431 }
432 }
433
434 } else { //check the nextkey
435 t_key *temp_key = next_key->find(ke);
436 if (temp_key) {
437 if (temp_key->keylist.size()) {
438 next_key = temp_key;
439 } else {
440 next_key = 0;
441 if (temp_key->action == grabExecute)
442 m_execcmdstring = temp_key->execcommand; //update execcmdstring if action is grabExecute
443 return temp_key->action;
444 }
445 } else {
446 temp_key = next_key;
447 next_key = 0;
448 if (temp_key->action == grabExecute)
449 m_execcmdstring = temp_key->execcommand; //update execcmdstring if action is grabExecute
450 return temp_key->action;
451 }
452
453 }
454
455 return lastKeygrab;
456}
457
458//--------- reconfigure -------------
459// deletes the tree and load configuration
460// returns true on success else false
461//-----------------------------------
462bool Keys::reconfigure(char *filename) {
463 deleteTree();
464 return load(filename);
465}
466
467//------------- getActionStr ------------------
468// Tries to find the action for the key
469// Returns actionstring on success else
470// 0 on failure
471//---------------------------------------------
472const char *Keys::getActionStr(KeyAction action) {
473 for (unsigned int i=0; m_actionlist[i].string!=0 ; i++) {
474 if (m_actionlist[i].action == action)
475 return m_actionlist[i].string;
476 }
477
478 return 0;
479}
480
481#ifdef DEBUG
482//--------- showTree -----------
483// Debug function that show the
484// keytree. Starts with the
485// rootlist
486//------------------------------
487void Keys::showTree() {
488 for (unsigned int i=0; i<m_keylist.size(); i++) {
489 if (m_keylist[i]) {
490 cerr<<i<<" ";
491 showKeyTree(m_keylist[i]);
492 } else
493 cerr<<"Null @ "<<i<<endl;
494 }
495}
496
497//---------- showKeyTree --------
498// Debug function to show t_key tree
499//-------------------------------
500void Keys::showKeyTree(t_key *key, unsigned int w) {
501 for (unsigned int i=0; i<w+1; i++)
502 cerr<<"-";
503 if (!key->keylist.empty()) {
504 for (unsigned int i=0; i<key->keylist.size(); i++) {
505 cerr<<"( "<<(int)key->key<<" "<<(int)key->mod<<" )";
506 showKeyTree(key->keylist[i], 4);
507 cerr<<endl;
508 }
509 } else
510 cerr<<"( "<<(int)key->key<<" "<<(int)key->mod<<" ) {"<<getActionStr(key->action)<<"}"<<endl;
511}
512#endif //DEBUG
513//------------ mergeTree ---------------
514// Merges two chains and binds new keys
515// Returns true on success else false.
516//---------------------------------------
517bool Keys::mergeTree(t_key *newtree, t_key *basetree) {
518 if (basetree==0) {
519 unsigned int baselist_i=0;
520 for (; baselist_i<m_keylist.size(); baselist_i++) {
521 if (m_keylist[baselist_i]->mod == newtree->mod &&
522 m_keylist[baselist_i]->key == newtree->key) {
523 if (newtree->keylist.size() && m_keylist[baselist_i]->action == lastKeygrab) {
524 //assumes the newtree only have one branch
525 return mergeTree(newtree->keylist[0], m_keylist[baselist_i]);
526 } else
527 break;
528 }
529 }
530
531 if (baselist_i == m_keylist.size()) {
532 grabKey(newtree->key, newtree->mod);
533 m_keylist.push_back(new t_key(newtree));
534 if (newtree->keylist.size())
535 return mergeTree(newtree->keylist[0], m_keylist.back());
536 return true;
537 }
538
539 } else {
540 unsigned int baselist_i = 0;
541 for (; baselist_i<basetree->keylist.size(); baselist_i++) {
542 if (basetree->keylist[baselist_i]->mod == newtree->mod &&
543 basetree->keylist[baselist_i]->key == newtree->key) {
544 if (newtree->keylist.size()) {
545 //assumes the newtree only have on branch
546 return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]);
547 } else
548 return false;
549 }
550 }
551 //if it wasn't in the list grab the key and add it to the list
552 if (baselist_i==basetree->keylist.size()) {
553 grabKey(newtree->key, newtree->mod);
554 basetree->keylist.push_back(new t_key(newtree));
555 if (newtree->keylist.size())
556 return mergeTree(newtree->keylist[0], basetree->keylist.back());
557 return true;
558 }
559 }
560
561 return false;
562}
563
564Keys::t_key::t_key(unsigned int key_, unsigned int mod_, KeyAction action_) {
565 action = action_;
566 key = key_;
567 mod = mod_;
568}
569
570Keys::t_key::t_key(t_key *k) {
571 action = k->action;
572 key = k->key;
573 mod = k->mod;
574 execcommand = k->execcommand;
575}
576
577Keys::t_key::~t_key() {
578 while (!keylist.empty()) {
579 t_key *k = keylist.back();
580 delete k;
581 keylist.pop_back();
582 }
583}