aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathias <mathias>2005-05-06 09:22:53 (GMT)
committermathias <mathias>2005-05-06 09:22:53 (GMT)
commit6c057c6903151aab92309310087d5af455ecefce (patch)
tree1d4c98ad1637df09b89593b3e6a4a70245db4602
parent7d4f711204ab0b51d45eaff332708f529c11c9f5 (diff)
downloadfluxbox-6c057c6903151aab92309310087d5af455ecefce.zip
fluxbox-6c057c6903151aab92309310087d5af455ecefce.tar.bz2
Fix for #1160244, #1099704, #1094107:
if the xkb-extension is enabled and the user switches between his/her keyboardlayouts fluxbox's keybhandling doesn't work well anymore because xkeyevent.state contains also xkb-related flags and thus we have to handle that with caution. KeyUtils now contain 'isolateModifierMask()' to really work only on the modifiers. why not as part of cleanMods() ? because the XLookupString return false results, eg TextBox's would only print chars from the first keyboardlayout.
-rw-r--r--ChangeLog9
-rw-r--r--src/CommandDialog.cc24
-rw-r--r--src/FbTk/KeyUtil.cc72
-rw-r--r--src/FbTk/KeyUtil.hh9
-rw-r--r--src/FbTk/TextBox.cc9
-rw-r--r--src/Keys.cc76
-rw-r--r--src/Keys.hh8
-rw-r--r--src/WorkspaceCmd.cc3
-rw-r--r--src/fluxbox.cc27
-rw-r--r--util/fbrun/FbRun.cc11
10 files changed, 137 insertions, 111 deletions
diff --git a/ChangeLog b/ChangeLog
index c763691..d5072d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
1(Format: Year/Month/Day) 1(Format: Year/Month/Day)
2Changes for 0.9.13 2Changes for 0.9.13
3*05/05/05:
4 * Fix #1160244, #1099704, #1094107 Mutiple keyboard layout (Mathias + thanx
5 to Vadim)
6 Switching to a secondary/third keyboard layout via the xkb-extensions
7 leads to broken NextWindow/PrevWindow and broken fbrun/CommandDialog:
8 - be aware of what xkb is doing to the event.state
9 - minor cleaning
10 CommandDialog.cc WorkspaceCmd.cc Keys.cc FbTk/KeyUtil.cc/hh
11 FbTk/TextBox.cc fluxbox.cc FbRun.cc
3*05/05/03: 12*05/05/03:
4 * Fix drawing of no-title menus, plus updating of int menu items (Simon) 13 * Fix drawing of no-title menus, plus updating of int menu items (Simon)
5 IntResMenuItem.hh/cc MenuItem.hh Menu.cc Screen.cc ToggleMenu.hh 14 IntResMenuItem.hh/cc MenuItem.hh Menu.cc Screen.cc ToggleMenu.hh
diff --git a/src/CommandDialog.cc b/src/CommandDialog.cc
index 317f7ef..80c8962 100644
--- a/src/CommandDialog.cc
+++ b/src/CommandDialog.cc
@@ -33,6 +33,7 @@
33#include "FbTk/ImageControl.hh" 33#include "FbTk/ImageControl.hh"
34#include "FbTk/EventManager.hh" 34#include "FbTk/EventManager.hh"
35#include "FbTk/StringUtil.hh" 35#include "FbTk/StringUtil.hh"
36#include "FbTk/KeyUtil.hh"
36#include "FbTk/App.hh" 37#include "FbTk/App.hh"
37 38
38#include <X11/keysym.h> 39#include <X11/keysym.h>
@@ -43,11 +44,11 @@
43#include <stdexcept> 44#include <stdexcept>
44using namespace std; 45using namespace std;
45 46
46CommandDialog::CommandDialog(BScreen &screen, 47CommandDialog::CommandDialog(BScreen &screen,
47 const std::string &title, const std::string precommand) : 48 const std::string &title, const std::string precommand) :
48 FbTk::FbWindow(screen.rootWindow().screenNumber(), 0, 0, 200, 1, ExposureMask), 49 FbTk::FbWindow(screen.rootWindow().screenNumber(), 0, 0, 200, 1, ExposureMask),
49 m_textbox(*this, screen.winFrameTheme().font(), ""), 50 m_textbox(*this, screen.winFrameTheme().font(), ""),
50 m_label(*this, screen.winFrameTheme().font(), title), 51 m_label(*this, screen.winFrameTheme().font(), title),
51 m_gc(m_textbox), 52 m_gc(m_textbox),
52 m_screen(screen), 53 m_screen(screen),
53 m_move_x(0), 54 m_move_x(0),
@@ -121,12 +122,13 @@ void CommandDialog::motionNotifyEvent(XMotionEvent &event) {
121} 122}
122 123
123void CommandDialog::keyPressEvent(XKeyEvent &event) { 124void CommandDialog::keyPressEvent(XKeyEvent &event) {
124 if (event.state) 125 unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(event.state);
126 if (state)
125 return; 127 return;
126 128
127 KeySym ks; 129 KeySym ks;
128 char keychar[1]; 130 char keychar;
129 XLookupString(&event, keychar, 1, &ks, 0); 131 XLookupString(&event, &keychar, 1, &ks, 0);
130 132
131 if (ks == XK_Return) { 133 if (ks == XK_Return) {
132 hide(); // hide and return focus to a FluxboxWindow 134 hide(); // hide and return focus to a FluxboxWindow
@@ -135,7 +137,7 @@ void CommandDialog::keyPressEvent(XKeyEvent &event) {
135 parseLine(m_precommand + m_textbox.text())); 137 parseLine(m_precommand + m_textbox.text()));
136 if (cmd.get()) 138 if (cmd.get())
137 cmd->execute(); 139 cmd->execute();
138 // post execute 140 // post execute
139 if (*m_postcommand != 0) 141 if (*m_postcommand != 0)
140 m_postcommand->execute(); 142 m_postcommand->execute();
141 143
@@ -152,7 +154,7 @@ void CommandDialog::tabComplete() {
152 try { 154 try {
153 string::size_type first = m_textbox.text().find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ" 155 string::size_type first = m_textbox.text().find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
154 "abcdefghijklmnopqrstuvwxyz" 156 "abcdefghijklmnopqrstuvwxyz"
155 "0123456789", 157 "0123456789",
156 m_textbox.cursorPosition()); 158 m_textbox.cursorPosition());
157 if (first == string::npos) 159 if (first == string::npos)
158 first = 0; 160 first = 0;
@@ -173,7 +175,7 @@ void CommandDialog::tabComplete() {
173 175
174 if (!matches.empty()) { 176 if (!matches.empty()) {
175 // sort and apply larges match 177 // sort and apply larges match
176 std::sort(matches.begin(), matches.end(), less<string>()); 178 std::sort(matches.begin(), matches.end(), less<string>());
177 m_textbox.setText(m_textbox.text() + matches[0].substr(prefix.size())); 179 m_textbox.setText(m_textbox.text() + matches[0].substr(prefix.size()));
178 } else 180 } else
179 XBell(FbTk::App::instance()->display(), 0); 181 XBell(FbTk::App::instance()->display(), 0);
@@ -204,7 +206,7 @@ void CommandDialog::init() {
204 206
205 // setup label 207 // setup label
206 // we listen to motion notify too 208 // we listen to motion notify too
207 m_label.setEventMask(m_label.eventMask() | ButtonPressMask | ButtonMotionMask); 209 m_label.setEventMask(m_label.eventMask() | ButtonPressMask | ButtonMotionMask);
208 m_label.setGC(m_screen.winFrameTheme().labelTextFocusGC()); 210 m_label.setGC(m_screen.winFrameTheme().labelTextFocusGC());
209 m_label.show(); 211 m_label.show();
210 212
@@ -234,7 +236,7 @@ void CommandDialog::init() {
234void CommandDialog::updateSizes() { 236void CommandDialog::updateSizes() {
235 m_label.moveResize(0, 0, 237 m_label.moveResize(0, 0,
236 width(), m_textbox.font().height() + 2); 238 width(), m_textbox.font().height() + 2);
237 239
238 m_textbox.moveResize(2, m_label.height(), 240 m_textbox.moveResize(2, m_label.height(),
239 width() - 4, m_textbox.font().height() + 2); 241 width() - 4, m_textbox.font().height() + 2);
240} 242}
diff --git a/src/FbTk/KeyUtil.cc b/src/FbTk/KeyUtil.cc
index 7760254..05e5413 100644
--- a/src/FbTk/KeyUtil.cc
+++ b/src/FbTk/KeyUtil.cc
@@ -26,6 +26,30 @@
26 26
27#include <string> 27#include <string>
28 28
29namespace {
30
31struct t_modlist{
32 char *str;
33 unsigned int mask;
34 bool operator == (const char *modstr) const {
35 return (strcasecmp(str, modstr) == 0 && mask !=0);
36 }
37};
38
39const struct t_modlist modlist[] = {
40 {"SHIFT", ShiftMask},
41 {"LOCK", LockMask},
42 {"CONTROL", ControlMask},
43 {"MOD1", Mod1Mask},
44 {"MOD2", Mod2Mask},
45 {"MOD3", Mod3Mask},
46 {"MOD4", Mod4Mask},
47 {"MOD5", Mod5Mask},
48 {0, 0}
49};
50
51};
52
29namespace FbTk { 53namespace FbTk {
30 54
31std::auto_ptr<KeyUtil> KeyUtil::s_keyutil; 55std::auto_ptr<KeyUtil> KeyUtil::s_keyutil;
@@ -57,19 +81,7 @@ void KeyUtil::loadModmap() {
57 XFreeModifiermap(m_modmap); 81 XFreeModifiermap(m_modmap);
58 82
59 m_modmap = XGetModifierMapping(App::instance()->display()); 83 m_modmap = XGetModifierMapping(App::instance()->display());
60 // mask to use for modifier 84
61 static const int mods[] = {
62 ShiftMask,
63 LockMask,
64 ControlMask,
65 Mod1Mask,
66 Mod2Mask,
67 Mod3Mask,
68 Mod4Mask,
69 Mod5Mask,
70 0
71 };
72
73 // find modifiers and set them 85 // find modifiers and set them
74 for (int i=0, realkey=0; i<8; ++i) { 86 for (int i=0, realkey=0; i<8; ++i) {
75 for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) { 87 for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
@@ -77,17 +89,18 @@ void KeyUtil::loadModmap() {
77 if (m_modmap->modifiermap[realkey] == 0) 89 if (m_modmap->modifiermap[realkey] == 0)
78 continue; 90 continue;
79 91
80 KeySym ks = XKeycodeToKeysym(App::instance()->display(), m_modmap->modifiermap[realkey], 0); 92 KeySym ks = XKeycodeToKeysym(App::instance()->display(),
93 m_modmap->modifiermap[realkey], 0);
81 94
82 switch (ks) { 95 switch (ks) {
83 case XK_Caps_Lock: 96 case XK_Caps_Lock:
84 m_capslock = mods[i]; 97 m_capslock = modlist[i].mask;
85 break; 98 break;
86 case XK_Scroll_Lock: 99 case XK_Scroll_Lock:
87 m_scrolllock = mods[i]; 100 m_scrolllock = modlist[i].mask;
88 break; 101 break;
89 case XK_Num_Lock: 102 case XK_Num_Lock:
90 m_numlock = mods[i]; 103 m_numlock = modlist[i].mask;
91 break; 104 break;
92 } 105 }
93 } 106 }
@@ -164,31 +177,13 @@ unsigned int KeyUtil::getKey(const char *keystr) {
164} 177}
165 178
166 179
167struct t_modlist{
168 char *str;
169 unsigned int mask;
170 bool operator == (const char *modstr) const {
171 return (strcasecmp(str, modstr) == 0 && mask !=0);
172 }
173};
174
175/** 180/**
176 @return the modifier for the modstr else zero on failure. 181 @return the modifier for the modstr else zero on failure.
177*/ 182*/
178unsigned int KeyUtil::getModifier(const char *modstr) { 183unsigned int KeyUtil::getModifier(const char *modstr) {
179 if (!modstr) 184 if (!modstr)
180 return 0; 185 return 0;
181 const static struct t_modlist modlist[] = { 186
182 {"SHIFT", ShiftMask},
183 {"CONTROL", ControlMask},
184 {"MOD1", Mod1Mask},
185 {"MOD2", Mod2Mask},
186 {"MOD3", Mod3Mask},
187 {"MOD4", Mod4Mask},
188 {"MOD5", Mod5Mask},
189 {0, 0}
190 };
191
192 // find mod mask string 187 // find mod mask string
193 for (unsigned int i=0; modlist[i].str !=0; i++) { 188 for (unsigned int i=0; modlist[i].str !=0; i++) {
194 if (modlist[i] == modstr) 189 if (modlist[i] == modstr)
@@ -210,7 +205,8 @@ void KeyUtil::ungrabKeys() {
210unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) { 205unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
211 XModifierKeymap *modmap = instance().m_modmap; 206 XModifierKeymap *modmap = instance().m_modmap;
212 207
213 if (!modmap) return 0; 208 if (!modmap)
209 return 0;
214 210
215 // search through modmap for this keycode 211 // search through modmap for this keycode
216 for (int mod=0; mod < 8; mod++) { 212 for (int mod=0; mod < 8; mod++) {
@@ -218,7 +214,7 @@ unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
218 // modifiermap is an array with 8 sets of keycodes 214 // modifiermap is an array with 8 sets of keycodes
219 // each max_keypermod long, but in a linear array. 215 // each max_keypermod long, but in a linear array.
220 if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) { 216 if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
221 return (1<<mod); 217 return modlist[mod].mask;
222 } 218 }
223 } 219 }
224 } 220 }
diff --git a/src/FbTk/KeyUtil.hh b/src/FbTk/KeyUtil.hh
index 4cafcdd..e32384f 100644
--- a/src/FbTk/KeyUtil.hh
+++ b/src/FbTk/KeyUtil.hh
@@ -70,6 +70,14 @@ public:
70 return mods & ~(capslock() | numlock() ); 70 return mods & ~(capslock() | numlock() );
71 } 71 }
72 72
73 /**
74 strip away everything which is actually not a modifier
75 eg, xkb-keyboardgroups are encoded as bit 13 and 14
76 */
77 unsigned int isolateModifierMask(unsigned int mods) {
78 return mods & (ShiftMask|LockMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask);
79 }
80
73 /** 81 /**
74 Convert the specified key into appropriate modifier mask 82 Convert the specified key into appropriate modifier mask
75 @return corresponding modifier mask 83 @return corresponding modifier mask
@@ -78,6 +86,7 @@ public:
78 int numlock() const { return Mod2Mask; } //m_numlock; } 86 int numlock() const { return Mod2Mask; } //m_numlock; }
79 int capslock() const { return LockMask; } //m_capslock; } 87 int capslock() const { return LockMask; } //m_capslock; }
80 int scrolllock() const { return Mod5Mask; } //m_scrolllock; } 88 int scrolllock() const { return Mod5Mask; } //m_scrolllock; }
89
81private: 90private:
82 void loadModmap(); 91 void loadModmap();
83 92
diff --git a/src/FbTk/TextBox.cc b/src/FbTk/TextBox.cc
index 0db8856..2ebd6c0 100644
--- a/src/FbTk/TextBox.cc
+++ b/src/FbTk/TextBox.cc
@@ -209,7 +209,7 @@ void TextBox::buttonPressEvent(XButtonEvent &event) {
209} 209}
210 210
211void TextBox::keyPressEvent(XKeyEvent &event) { 211void TextBox::keyPressEvent(XKeyEvent &event) {
212 // strip numlock and scrolllock mask 212
213 event.state = KeyUtil::instance().cleanMods(event.state); 213 event.state = KeyUtil::instance().cleanMods(event.state);
214 214
215 KeySym ks; 215 KeySym ks;
@@ -218,8 +218,8 @@ void TextBox::keyPressEvent(XKeyEvent &event) {
218 // a modifier key by itself doesn't do anything 218 // a modifier key by itself doesn't do anything
219 if (IsModifierKey(ks)) return; 219 if (IsModifierKey(ks)) return;
220 220
221 if (event.state) { // handle keybindings with state 221 if (FbTk::KeyUtil::instance().isolateModifierMask(event.state)) { // handle keybindings with state
222 if (event.state == ControlMask) { 222 if ((event.state & ControlMask) == ControlMask) {
223 223
224 switch (ks) { 224 switch (ks) {
225 case XK_b: 225 case XK_b:
@@ -248,7 +248,8 @@ void TextBox::keyPressEvent(XKeyEvent &event) {
248 m_end_pos = 0; 248 m_end_pos = 0;
249 break; 249 break;
250 } 250 }
251 } else if (event.state == ShiftMask || event.state == 0x80) { // shif and altgr 251 } else if ((event.state & ShiftMask)== ShiftMask ||
252 (event.state & 0x80) == 0x80) { // shif and altgr
252 if (isprint(keychar[0])) { 253 if (isprint(keychar[0])) {
253 std::string val; 254 std::string val;
254 val += keychar[0]; 255 val += keychar[0];
diff --git a/src/Keys.cc b/src/Keys.cc
index 96f57cb..0d3eecd 100644
--- a/src/Keys.cc
+++ b/src/Keys.cc
@@ -27,7 +27,6 @@
27#include "FbTk/StringUtil.hh" 27#include "FbTk/StringUtil.hh"
28#include "FbTk/App.hh" 28#include "FbTk/App.hh"
29#include "FbTk/Command.hh" 29#include "FbTk/Command.hh"
30#include "FbTk/KeyUtil.hh"
31 30
32#include "CommandParser.hh" 31#include "CommandParser.hh"
33#include "FbTk/I18n.hh" 32#include "FbTk/I18n.hh"
@@ -81,6 +80,8 @@
81#include <X11/Xlib.h> 80#include <X11/Xlib.h>
82#include <X11/Xproto.h> 81#include <X11/Xproto.h>
83#include <X11/keysym.h> 82#include <X11/keysym.h>
83#include <X11/Xutil.h>
84#include <X11/XKBlib.h>
84 85
85#include <iostream> 86#include <iostream>
86#include <fstream> 87#include <fstream>
@@ -102,7 +103,7 @@ Keys::Keys(const char *filename):
102 load(filename); 103 load(filename);
103} 104}
104 105
105Keys::~Keys() { 106Keys::~Keys() {
106 107
107 FbTk::KeyUtil::ungrabKeys(); 108 FbTk::KeyUtil::ungrabKeys();
108 deleteTree(); 109 deleteTree();
@@ -112,12 +113,12 @@ Keys::~Keys() {
112void Keys::deleteTree() { 113void Keys::deleteTree() {
113 while (!m_keylist.empty()) { 114 while (!m_keylist.empty()) {
114 if (m_keylist.back()) 115 if (m_keylist.back())
115 delete m_keylist.back(); 116 delete m_keylist.back();
116 m_keylist.pop_back(); 117 m_keylist.pop_back();
117 } 118 }
118} 119}
119 120
120/** 121/**
121 Load and grab keys 122 Load and grab keys
122 TODO: error checking 123 TODO: error checking
123 @return true on success else false 124 @return true on success else false
@@ -125,7 +126,7 @@ void Keys::deleteTree() {
125bool Keys::load(const char *filename) { 126bool Keys::load(const char *filename) {
126 if (!filename) 127 if (!filename)
127 return false; 128 return false;
128 129
129 //ungrab all keys 130 //ungrab all keys
130 FbTk::KeyUtil::ungrabKeys(); 131 FbTk::KeyUtil::ungrabKeys();
131 132
@@ -133,7 +134,7 @@ bool Keys::load(const char *filename) {
133 deleteTree(); 134 deleteTree();
134 135
135 FbTk::App::instance()->sync(false); 136 FbTk::App::instance()->sync(false);
136 137
137 //open the file 138 //open the file
138 ifstream infile(filename); 139 ifstream infile(filename);
139 if (!infile) 140 if (!infile)
@@ -158,8 +159,8 @@ bool Keys::load(const char *filename) {
158 159
159bool Keys::save(const char *filename) const { 160bool Keys::save(const char *filename) const {
160 //!! 161 //!!
161 //!! TODO: fix keybinding saving 162 //!! TODO: fix keybinding saving
162 //!! (we probably need to save key actions 163 //!! (we probably need to save key actions
163 //!! as strings instead of creating new Commands) 164 //!! as strings instead of creating new Commands)
164 165
165 // open file for writing 166 // open file for writing
@@ -178,16 +179,16 @@ bool Keys::addBinding(const std::string &linebuffer) {
178 // must have at least 1 argument 179 // must have at least 1 argument
179 if (val.size() <= 0) 180 if (val.size() <= 0)
180 return true; // empty lines are valid. 181 return true; // empty lines are valid.
181 182
182 if (val[0][0] == '#' || val[0][0] == '!' ) //the line is commented 183 if (val[0][0] == '#' || val[0][0] == '!' ) //the line is commented
183 return true; // still a valid line. 184 return true; // still a valid line.
184 185
185 unsigned int key = 0, mod = 0; 186 unsigned int key = 0, mod = 0;
186 char keyarg = 0; 187 char keyarg = 0;
187 t_key *current_key=0, *last_key=0; 188 t_key *current_key=0, *last_key=0;
188 189
189 _FB_USES_NLS; 190 _FB_USES_NLS;
190 // for each argument 191 // for each argument
191 for (unsigned int argc=0; argc<val.size(); argc++) { 192 for (unsigned int argc=0; argc<val.size(); argc++) {
192 193
193 if (val[argc][0] != ':') { // parse key(s) 194 if (val[argc][0] != ':') { // parse key(s)
@@ -199,7 +200,7 @@ bool Keys::addBinding(const std::string &linebuffer) {
199 int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str()); 200 int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str());
200 if(tmpmod) 201 if(tmpmod)
201 mod |= tmpmod; //If it's a modifier 202 mod |= tmpmod; //If it's a modifier
202 else { 203 else {
203 key = FbTk::KeyUtil::getKey(val[argc].c_str()); // else get the key 204 key = FbTk::KeyUtil::getKey(val[argc].c_str()); // else get the key
204 if (key == 0) { 205 if (key == 0) {
205 cerr<<_FBTEXT(Keys, InvalidKeyMod, "Keys: Invalid key/modifier on line", "A bad key/modifier string was found on line (number following)")<<" "<< 206 cerr<<_FBTEXT(Keys, InvalidKeyMod, "Keys: Invalid key/modifier on line", "A bad key/modifier string was found on line (number following)")<<" "<<
@@ -209,13 +210,13 @@ bool Keys::addBinding(const std::string &linebuffer) {
209 if (!current_key) { 210 if (!current_key) {
210 current_key = new t_key(key, mod); 211 current_key = new t_key(key, mod);
211 last_key = current_key; 212 last_key = current_key;
212 } else { 213 } else {
213 t_key *temp_key = new t_key(key, mod); 214 t_key *temp_key = new t_key(key, mod);
214 last_key->keylist.push_back(temp_key); 215 last_key->keylist.push_back(temp_key);
215 last_key = temp_key; 216 last_key = temp_key;
216 } 217 }
217 } 218 }
218 } 219 }
219 220
220 } else { // parse command line 221 } else { // parse command line
221 if (last_key == 0) { 222 if (last_key == 0) {
@@ -224,7 +225,7 @@ bool Keys::addBinding(const std::string &linebuffer) {
224 return false; 225 return false;
225 } 226 }
226 bool ret_val = true; 227 bool ret_val = true;
227 const char *str = 228 const char *str =
228 FbTk::StringUtil::strcasestr(linebuffer.c_str(), 229 FbTk::StringUtil::strcasestr(linebuffer.c_str(),
229 val[argc].c_str() + 1); // +1 to skip ':' 230 val[argc].c_str() + 1); // +1 to skip ':'
230 if (str == 0) { 231 if (str == 0) {
@@ -263,41 +264,42 @@ bool Keys::addBinding(const std::string &linebuffer) {
263 @return the KeyAction of the XKeyEvent 264 @return the KeyAction of the XKeyEvent
264*/ 265*/
265void Keys::doAction(XKeyEvent &ke) { 266void Keys::doAction(XKeyEvent &ke) {
266 static t_key *next_key = 0; 267
267 // Remove numlock, capslock and scrolllock
268 ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); 268 ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
269 269
270 static struct t_key* next_key = 0;
271
270 if (!next_key) { 272 if (!next_key) {
271 273
272 for (unsigned int i=0; i<m_keylist.size(); i++) { 274 for (unsigned int i=0; i<m_keylist.size(); i++) {
273 if (*m_keylist[i] == ke) { 275 if (*m_keylist[i] == ke) {
274 if (m_keylist[i]->keylist.size()) { 276 if (m_keylist[i]->keylist.size()) {
275 next_key = m_keylist[i]; 277 next_key = m_keylist[i];
276 break; //end for-loop 278 break; //end for-loop
277 } else { 279 } else {
278 if (*m_keylist[i]->m_command != 0) 280 if (*m_keylist[i]->m_command != 0)
279 m_keylist[i]->m_command->execute(); 281 m_keylist[i]->m_command->execute();
280 } 282 }
281 } 283 }
282 } 284 }
283 285
284 } else { //check the nextkey 286 } else { //check the nextkey
285 t_key *temp_key = next_key->find(ke); 287 t_key *temp_key = next_key->find(ke);
286 if (temp_key) { 288 if (temp_key) {
287 if (temp_key->keylist.size()) { 289 if (temp_key->keylist.size()) {
288 next_key = temp_key; 290 next_key = temp_key;
289 } else { 291 } else {
290 next_key = 0; 292 next_key = 0;
291 if (*temp_key->m_command != 0) 293 if (*temp_key->m_command != 0)
292 temp_key->m_command->execute(); 294 temp_key->m_command->execute();
293 } 295 }
294 } else { 296 } else {
295 temp_key = next_key; 297 temp_key = next_key;
296 next_key = 0; 298 next_key = 0;
297 if (*temp_key->m_command != 0) 299 if (*temp_key->m_command != 0)
298 temp_key->m_command->execute(); 300 temp_key->m_command->execute();
299 301
300 } 302 }
301 } 303 }
302} 304}
303 305
@@ -318,7 +320,7 @@ bool Keys::mergeTree(t_key *newtree, t_key *basetree) {
318 if (basetree==0) { 320 if (basetree==0) {
319 unsigned int baselist_i=0; 321 unsigned int baselist_i=0;
320 for (; baselist_i<m_keylist.size(); baselist_i++) { 322 for (; baselist_i<m_keylist.size(); baselist_i++) {
321 if (m_keylist[baselist_i]->mod == newtree->mod && 323 if (m_keylist[baselist_i]->mod == newtree->mod &&
322 m_keylist[baselist_i]->key == newtree->key) { 324 m_keylist[baselist_i]->key == newtree->key) {
323 if (newtree->keylist.size() && *m_keylist[baselist_i]->m_command == 0) { 325 if (newtree->keylist.size() && *m_keylist[baselist_i]->m_command == 0) {
324 //assumes the newtree only have one branch 326 //assumes the newtree only have one branch
@@ -330,12 +332,12 @@ bool Keys::mergeTree(t_key *newtree, t_key *basetree) {
330 332
331 if (baselist_i == m_keylist.size()) { 333 if (baselist_i == m_keylist.size()) {
332 FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); 334 FbTk::KeyUtil::grabKey(newtree->key, newtree->mod);
333 m_keylist.push_back(new t_key(newtree)); 335 m_keylist.push_back(new t_key(newtree));
334 if (newtree->keylist.size()) 336 if (newtree->keylist.size())
335 return mergeTree(newtree->keylist[0], m_keylist.back()); 337 return mergeTree(newtree->keylist[0], m_keylist.back());
336 return true; 338 return true;
337 } 339 }
338 340
339 } else { 341 } else {
340 unsigned int baselist_i = 0; 342 unsigned int baselist_i = 0;
341 for (; baselist_i<basetree->keylist.size(); baselist_i++) { 343 for (; baselist_i<basetree->keylist.size(); baselist_i++) {
@@ -346,24 +348,24 @@ bool Keys::mergeTree(t_key *newtree, t_key *basetree) {
346 return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]); 348 return mergeTree(newtree->keylist[0], basetree->keylist[baselist_i]);
347 } else 349 } else
348 return false; 350 return false;
349 } 351 }
350 } 352 }
351 //if it wasn't in the list grab the key and add it to the list 353 //if it wasn't in the list grab the key and add it to the list
352 if (baselist_i==basetree->keylist.size()) { 354 if (baselist_i==basetree->keylist.size()) {
353 FbTk::KeyUtil::grabKey(newtree->key, newtree->mod); 355 FbTk::KeyUtil::grabKey(newtree->key, newtree->mod);
354 basetree->keylist.push_back(new t_key(newtree)); 356 basetree->keylist.push_back(new t_key(newtree));
355 if (newtree->keylist.size()) 357 if (newtree->keylist.size())
356 return mergeTree(newtree->keylist[0], basetree->keylist.back()); 358 return mergeTree(newtree->keylist[0], basetree->keylist.back());
357 return true; 359 return true;
358 } 360 }
359 } 361 }
360 362
361 return false; 363 return false;
362} 364}
363 365
364Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) { 366Keys::t_key::t_key(unsigned int key_, unsigned int mod_, FbTk::RefCount<FbTk::Command> command) {
365 key = key_; 367 key = key_;
366 mod = mod_; 368 mod = mod_;
367 m_command = command; 369 m_command = command;
368} 370}
369 371
@@ -373,8 +375,8 @@ Keys::t_key::t_key(t_key *k) {
373 m_command = k->m_command; 375 m_command = k->m_command;
374} 376}
375 377
376Keys::t_key::~t_key() { 378Keys::t_key::~t_key() {
377 while (!keylist.empty()) { 379 while (!keylist.empty()) {
378 t_key *k = keylist.back(); 380 t_key *k = keylist.back();
379 if (k != 0) { // make sure we don't have a bad key pointer 381 if (k != 0) { // make sure we don't have a bad key pointer
380 delete k; 382 delete k;
diff --git a/src/Keys.hh b/src/Keys.hh
index c9c53b5..f83f6e8 100644
--- a/src/Keys.hh
+++ b/src/Keys.hh
@@ -31,6 +31,7 @@
31#include "FbTk/NotCopyable.hh" 31#include "FbTk/NotCopyable.hh"
32#include "FbTk/RefCount.hh" 32#include "FbTk/RefCount.hh"
33#include "FbTk/Command.hh" 33#include "FbTk/Command.hh"
34#include "FbTk/KeyUtil.hh"
34 35
35class Keys:private FbTk::NotCopyable { 36class Keys:private FbTk::NotCopyable {
36public: 37public:
@@ -86,21 +87,22 @@ private:
86 87
87 inline t_key *find(unsigned int key_, unsigned int mod_) { 88 inline t_key *find(unsigned int key_, unsigned int mod_) {
88 for (unsigned int i=0; i<keylist.size(); i++) { 89 for (unsigned int i=0; i<keylist.size(); i++) {
89 if (keylist[i]->key == key_ && keylist[i]->mod == mod_) 90 if (keylist[i]->key == key_ && keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(mod_))
90 return keylist[i]; 91 return keylist[i];
91 } 92 }
92 return 0; 93 return 0;
93 } 94 }
94 inline t_key *find(XKeyEvent &ke) { 95 inline t_key *find(XKeyEvent &ke) {
95 for (unsigned int i=0; i<keylist.size(); i++) { 96 for (unsigned int i=0; i<keylist.size(); i++) {
96 if (keylist[i]->key == ke.keycode && keylist[i]->mod == ke.state) 97 if (keylist[i]->key == ke.keycode &&
98 keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state))
97 return keylist[i]; 99 return keylist[i];
98 } 100 }
99 return 0; 101 return 0;
100 } 102 }
101 103
102 inline bool operator == (XKeyEvent &ke) const { 104 inline bool operator == (XKeyEvent &ke) const {
103 return (mod == ke.state && key == ke.keycode); 105 return (mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state) && key == ke.keycode);
104 } 106 }
105 107
106 FbTk::RefCount<FbTk::Command> m_command; 108 FbTk::RefCount<FbTk::Command> m_command;
diff --git a/src/WorkspaceCmd.cc b/src/WorkspaceCmd.cc
index 3e6d128..08473df 100644
--- a/src/WorkspaceCmd.cc
+++ b/src/WorkspaceCmd.cc
@@ -42,13 +42,13 @@
42#include <iostream> 42#include <iostream>
43 43
44void NextWindowCmd::execute() { 44void NextWindowCmd::execute() {
45
46 BScreen *screen = Fluxbox::instance()->keyScreen(); 45 BScreen *screen = Fluxbox::instance()->keyScreen();
47 if (screen != 0) { 46 if (screen != 0) {
48 Fluxbox *fb = Fluxbox::instance(); 47 Fluxbox *fb = Fluxbox::instance();
49 // special case for commands from key events 48 // special case for commands from key events
50 if (fb->lastEvent().type == KeyPress) { 49 if (fb->lastEvent().type == KeyPress) {
51 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state); 50 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state);
51 mods = FbTk::KeyUtil::instance().isolateModifierMask(mods);
52 if (mods == 0) // can't stacked cycle unless there is a mod to grab 52 if (mods == 0) // can't stacked cycle unless there is a mod to grab
53 screen->nextFocus(m_option | BScreen::CYCLELINEAR); 53 screen->nextFocus(m_option | BScreen::CYCLELINEAR);
54 else { 54 else {
@@ -71,6 +71,7 @@ void PrevWindowCmd::execute() {
71 // special case for commands from key events 71 // special case for commands from key events
72 if (fb->lastEvent().type == KeyPress) { 72 if (fb->lastEvent().type == KeyPress) {
73 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state); 73 unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state);
74 mods = FbTk::KeyUtil::instance().isolateModifierMask(mods);
74 if (mods == 0) // can't stacked cycle unless there is a mod to grab 75 if (mods == 0) // can't stacked cycle unless there is a mod to grab
75 screen->prevFocus(m_option | BScreen::CYCLELINEAR); 76 screen->prevFocus(m_option | BScreen::CYCLELINEAR);
76 else { 77 else {
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index cd289ed..271d93f 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -777,11 +777,13 @@ void Fluxbox::handleEvent(XEvent * const e) {
777#ifdef DEBUG 777#ifdef DEBUG
778 cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl; 778 cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
779#endif // DEBUG 779#endif // DEBUG
780 780 if (e->xmapping.request == MappingKeyboard
781 FbTk::KeyUtil::instance().init(); // reinitialise the key utils 781 || e->xmapping.request == MappingModifier) {
782 // reconfigure keys (if the mapping changes, they don't otherwise update 782 XRefreshKeyboardMapping(&e->xmapping);
783 m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str()); 783 FbTk::KeyUtil::instance().init(); // reinitialise the key utils
784 784 // reconfigure keys (if the mapping changes, they don't otherwise update
785 m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
786 }
785 break; 787 break;
786 case CreateNotify: 788 case CreateNotify:
787 break; 789 break;
@@ -1076,7 +1078,6 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1076 if (keyScreen() == 0 || mouseScreen() == 0) 1078 if (keyScreen() == 0 || mouseScreen() == 0)
1077 return; 1079 return;
1078 1080
1079
1080 switch (ke.type) { 1081 switch (ke.type) {
1081 case KeyPress: 1082 case KeyPress:
1082 m_key->doAction(ke); 1083 m_key->doAction(ke);
@@ -1089,9 +1090,10 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1089 if (m_watching_screen && m_watch_keyrelease) { 1090 if (m_watching_screen && m_watch_keyrelease) {
1090 // mask the mod of the released key out 1091 // mask the mod of the released key out
1091 // won't mask anything if it isn't a mod 1092 // won't mask anything if it isn't a mod
1092 ke.state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode); 1093 unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(ke.state);
1093 1094 state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
1094 if ((m_watch_keyrelease & ke.state) == 0) { 1095
1096 if ((m_watch_keyrelease & state) == 0) {
1095 1097
1096 m_watching_screen->notifyReleasedKeys(ke); 1098 m_watching_screen->notifyReleasedKeys(ke);
1097 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime); 1099 XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
@@ -1107,8 +1109,6 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
1107 default: 1109 default:
1108 break; 1110 break;
1109 } 1111 }
1110
1111
1112} 1112}
1113 1113
1114/// handle system signals 1114/// handle system signals
@@ -1951,12 +1951,15 @@ void Fluxbox::unfocusWindow(WinClient &client, bool full_revert, bool unfocus_fr
1951 1951
1952 1952
1953void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) { 1953void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
1954
1954 if (mods == 0) { 1955 if (mods == 0) {
1955 cerr<<"WARNING: attempt to grab without modifiers!"<<endl; 1956 cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
1956 return; 1957 return;
1957 } 1958 }
1958 m_watching_screen = &screen; 1959 m_watching_screen = &screen;
1959 m_watch_keyrelease = mods; 1960
1961 // just make sure we are saving the mods with any other flags (xkb)
1962 m_watch_keyrelease = FbTk::KeyUtil::instance().isolateModifierMask(mods);
1960 XGrabKeyboard(FbTk::App::instance()->display(), 1963 XGrabKeyboard(FbTk::App::instance()->display(),
1961 screen.rootWindow().window(), True, 1964 screen.rootWindow().window(), True,
1962 GrabModeAsync, GrabModeAsync, CurrentTime); 1965 GrabModeAsync, GrabModeAsync, CurrentTime);
diff --git a/util/fbrun/FbRun.cc b/util/fbrun/FbRun.cc
index b14321b..d72d1bf 100644
--- a/util/fbrun/FbRun.cc
+++ b/util/fbrun/FbRun.cc
@@ -223,7 +223,7 @@ void FbRun::redrawLabel() {
223} 223}
224 224
225void FbRun::keyPressEvent(XKeyEvent &ke) { 225void FbRun::keyPressEvent(XKeyEvent &ke) {
226 // strip numlock, capslock and scrolllock mask 226
227 ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state); 227 ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
228 228
229 int cp= cursorPosition(); 229 int cp= cursorPosition();
@@ -232,10 +232,11 @@ void FbRun::keyPressEvent(XKeyEvent &ke) {
232 char keychar[1]; 232 char keychar[1];
233 XLookupString(&ke, keychar, 1, &ks, 0); 233 XLookupString(&ke, keychar, 1, &ks, 0);
234 // a modifier key by itself doesn't do anything 234 // a modifier key by itself doesn't do anything
235 if (IsModifierKey(ks)) return; 235 if (IsModifierKey(ks))
236 return;
236 237
237 if (ke.state) { // a modifier key is down 238 if (FbTk::KeyUtil::instance().isolateModifierMask(ke.state)) { // a modifier key is down
238 if (ke.state == ControlMask) { 239 if ((ke.state & ControlMask) == ControlMask) {
239 switch (ks) { 240 switch (ks) {
240 case XK_p: 241 case XK_p:
241 prevHistoryItem(); 242 prevHistoryItem();
@@ -248,7 +249,7 @@ void FbRun::keyPressEvent(XKeyEvent &ke) {
248 setCursorPosition(cp); 249 setCursorPosition(cp);
249 break; 250 break;
250 } 251 }
251 } else if (ke.state == (Mod1Mask | ShiftMask)) { 252 } else if ((ke.state & (Mod1Mask|ShiftMask)) == (Mod1Mask | ShiftMask)) {
252 switch (ks) { 253 switch (ks) {
253 case XK_less: 254 case XK_less:
254 firstHistoryItem(); 255 firstHistoryItem();