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.
This commit is contained in:
parent
7d4f711204
commit
6c057c6903
10 changed files with 137 additions and 111 deletions
|
@ -1,5 +1,14 @@
|
|||
(Format: Year/Month/Day)
|
||||
Changes for 0.9.13
|
||||
*05/05/05:
|
||||
* Fix #1160244, #1099704, #1094107 Mutiple keyboard layout (Mathias + thanx
|
||||
to Vadim)
|
||||
Switching to a secondary/third keyboard layout via the xkb-extensions
|
||||
leads to broken NextWindow/PrevWindow and broken fbrun/CommandDialog:
|
||||
- be aware of what xkb is doing to the event.state
|
||||
- minor cleaning
|
||||
CommandDialog.cc WorkspaceCmd.cc Keys.cc FbTk/KeyUtil.cc/hh
|
||||
FbTk/TextBox.cc fluxbox.cc FbRun.cc
|
||||
*05/05/03:
|
||||
* Fix drawing of no-title menus, plus updating of int menu items (Simon)
|
||||
IntResMenuItem.hh/cc MenuItem.hh Menu.cc Screen.cc ToggleMenu.hh
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "FbTk/ImageControl.hh"
|
||||
#include "FbTk/EventManager.hh"
|
||||
#include "FbTk/StringUtil.hh"
|
||||
#include "FbTk/KeyUtil.hh"
|
||||
#include "FbTk/App.hh"
|
||||
|
||||
#include <X11/keysym.h>
|
||||
|
@ -121,12 +122,13 @@ void CommandDialog::motionNotifyEvent(XMotionEvent &event) {
|
|||
}
|
||||
|
||||
void CommandDialog::keyPressEvent(XKeyEvent &event) {
|
||||
if (event.state)
|
||||
unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(event.state);
|
||||
if (state)
|
||||
return;
|
||||
|
||||
KeySym ks;
|
||||
char keychar[1];
|
||||
XLookupString(&event, keychar, 1, &ks, 0);
|
||||
char keychar;
|
||||
XLookupString(&event, &keychar, 1, &ks, 0);
|
||||
|
||||
if (ks == XK_Return) {
|
||||
hide(); // hide and return focus to a FluxboxWindow
|
||||
|
|
|
@ -26,6 +26,30 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
struct t_modlist{
|
||||
char *str;
|
||||
unsigned int mask;
|
||||
bool operator == (const char *modstr) const {
|
||||
return (strcasecmp(str, modstr) == 0 && mask !=0);
|
||||
}
|
||||
};
|
||||
|
||||
const struct t_modlist modlist[] = {
|
||||
{"SHIFT", ShiftMask},
|
||||
{"LOCK", LockMask},
|
||||
{"CONTROL", ControlMask},
|
||||
{"MOD1", Mod1Mask},
|
||||
{"MOD2", Mod2Mask},
|
||||
{"MOD3", Mod3Mask},
|
||||
{"MOD4", Mod4Mask},
|
||||
{"MOD5", Mod5Mask},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
namespace FbTk {
|
||||
|
||||
std::auto_ptr<KeyUtil> KeyUtil::s_keyutil;
|
||||
|
@ -57,18 +81,6 @@ void KeyUtil::loadModmap() {
|
|||
XFreeModifiermap(m_modmap);
|
||||
|
||||
m_modmap = XGetModifierMapping(App::instance()->display());
|
||||
// mask to use for modifier
|
||||
static const int mods[] = {
|
||||
ShiftMask,
|
||||
LockMask,
|
||||
ControlMask,
|
||||
Mod1Mask,
|
||||
Mod2Mask,
|
||||
Mod3Mask,
|
||||
Mod4Mask,
|
||||
Mod5Mask,
|
||||
0
|
||||
};
|
||||
|
||||
// find modifiers and set them
|
||||
for (int i=0, realkey=0; i<8; ++i) {
|
||||
|
@ -77,17 +89,18 @@ void KeyUtil::loadModmap() {
|
|||
if (m_modmap->modifiermap[realkey] == 0)
|
||||
continue;
|
||||
|
||||
KeySym ks = XKeycodeToKeysym(App::instance()->display(), m_modmap->modifiermap[realkey], 0);
|
||||
KeySym ks = XKeycodeToKeysym(App::instance()->display(),
|
||||
m_modmap->modifiermap[realkey], 0);
|
||||
|
||||
switch (ks) {
|
||||
case XK_Caps_Lock:
|
||||
m_capslock = mods[i];
|
||||
m_capslock = modlist[i].mask;
|
||||
break;
|
||||
case XK_Scroll_Lock:
|
||||
m_scrolllock = mods[i];
|
||||
m_scrolllock = modlist[i].mask;
|
||||
break;
|
||||
case XK_Num_Lock:
|
||||
m_numlock = mods[i];
|
||||
m_numlock = modlist[i].mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -164,30 +177,12 @@ unsigned int KeyUtil::getKey(const char *keystr) {
|
|||
}
|
||||
|
||||
|
||||
struct t_modlist{
|
||||
char *str;
|
||||
unsigned int mask;
|
||||
bool operator == (const char *modstr) const {
|
||||
return (strcasecmp(str, modstr) == 0 && mask !=0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@return the modifier for the modstr else zero on failure.
|
||||
*/
|
||||
unsigned int KeyUtil::getModifier(const char *modstr) {
|
||||
if (!modstr)
|
||||
return 0;
|
||||
const static struct t_modlist 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].str !=0; i++) {
|
||||
|
@ -210,7 +205,8 @@ void KeyUtil::ungrabKeys() {
|
|||
unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
|
||||
XModifierKeymap *modmap = instance().m_modmap;
|
||||
|
||||
if (!modmap) return 0;
|
||||
if (!modmap)
|
||||
return 0;
|
||||
|
||||
// search through modmap for this keycode
|
||||
for (int mod=0; mod < 8; mod++) {
|
||||
|
@ -218,7 +214,7 @@ unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
|
|||
// modifiermap is an array with 8 sets of keycodes
|
||||
// each max_keypermod long, but in a linear array.
|
||||
if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
|
||||
return (1<<mod);
|
||||
return modlist[mod].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,14 @@ public:
|
|||
return mods & ~(capslock() | numlock() );
|
||||
}
|
||||
|
||||
/**
|
||||
strip away everything which is actually not a modifier
|
||||
eg, xkb-keyboardgroups are encoded as bit 13 and 14
|
||||
*/
|
||||
unsigned int isolateModifierMask(unsigned int mods) {
|
||||
return mods & (ShiftMask|LockMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the specified key into appropriate modifier mask
|
||||
@return corresponding modifier mask
|
||||
|
@ -78,6 +86,7 @@ public:
|
|||
int numlock() const { return Mod2Mask; } //m_numlock; }
|
||||
int capslock() const { return LockMask; } //m_capslock; }
|
||||
int scrolllock() const { return Mod5Mask; } //m_scrolllock; }
|
||||
|
||||
private:
|
||||
void loadModmap();
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ void TextBox::buttonPressEvent(XButtonEvent &event) {
|
|||
}
|
||||
|
||||
void TextBox::keyPressEvent(XKeyEvent &event) {
|
||||
// strip numlock and scrolllock mask
|
||||
|
||||
event.state = KeyUtil::instance().cleanMods(event.state);
|
||||
|
||||
KeySym ks;
|
||||
|
@ -218,8 +218,8 @@ void TextBox::keyPressEvent(XKeyEvent &event) {
|
|||
// a modifier key by itself doesn't do anything
|
||||
if (IsModifierKey(ks)) return;
|
||||
|
||||
if (event.state) { // handle keybindings with state
|
||||
if (event.state == ControlMask) {
|
||||
if (FbTk::KeyUtil::instance().isolateModifierMask(event.state)) { // handle keybindings with state
|
||||
if ((event.state & ControlMask) == ControlMask) {
|
||||
|
||||
switch (ks) {
|
||||
case XK_b:
|
||||
|
@ -248,7 +248,8 @@ void TextBox::keyPressEvent(XKeyEvent &event) {
|
|||
m_end_pos = 0;
|
||||
break;
|
||||
}
|
||||
} else if (event.state == ShiftMask || event.state == 0x80) { // shif and altgr
|
||||
} else if ((event.state & ShiftMask)== ShiftMask ||
|
||||
(event.state & 0x80) == 0x80) { // shif and altgr
|
||||
if (isprint(keychar[0])) {
|
||||
std::string val;
|
||||
val += keychar[0];
|
||||
|
|
10
src/Keys.cc
10
src/Keys.cc
|
@ -27,7 +27,6 @@
|
|||
#include "FbTk/StringUtil.hh"
|
||||
#include "FbTk/App.hh"
|
||||
#include "FbTk/Command.hh"
|
||||
#include "FbTk/KeyUtil.hh"
|
||||
|
||||
#include "CommandParser.hh"
|
||||
#include "FbTk/I18n.hh"
|
||||
|
@ -81,6 +80,8 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/XKBlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
@ -263,10 +264,11 @@ bool Keys::addBinding(const std::string &linebuffer) {
|
|||
@return the KeyAction of the XKeyEvent
|
||||
*/
|
||||
void Keys::doAction(XKeyEvent &ke) {
|
||||
static t_key *next_key = 0;
|
||||
// Remove numlock, capslock and scrolllock
|
||||
|
||||
ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
|
||||
|
||||
static struct t_key* next_key = 0;
|
||||
|
||||
if (!next_key) {
|
||||
|
||||
for (unsigned int i=0; i<m_keylist.size(); i++) {
|
||||
|
@ -282,7 +284,7 @@ void Keys::doAction(XKeyEvent &ke) {
|
|||
}
|
||||
|
||||
} else { //check the nextkey
|
||||
t_key *temp_key = next_key->find(ke);
|
||||
t_key *temp_key = next_key->find(ke);
|
||||
if (temp_key) {
|
||||
if (temp_key->keylist.size()) {
|
||||
next_key = temp_key;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "FbTk/NotCopyable.hh"
|
||||
#include "FbTk/RefCount.hh"
|
||||
#include "FbTk/Command.hh"
|
||||
#include "FbTk/KeyUtil.hh"
|
||||
|
||||
class Keys:private FbTk::NotCopyable {
|
||||
public:
|
||||
|
@ -86,21 +87,22 @@ private:
|
|||
|
||||
inline t_key *find(unsigned int key_, unsigned int mod_) {
|
||||
for (unsigned int i=0; i<keylist.size(); i++) {
|
||||
if (keylist[i]->key == key_ && keylist[i]->mod == mod_)
|
||||
if (keylist[i]->key == key_ && keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(mod_))
|
||||
return keylist[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
inline t_key *find(XKeyEvent &ke) {
|
||||
for (unsigned int i=0; i<keylist.size(); i++) {
|
||||
if (keylist[i]->key == ke.keycode && keylist[i]->mod == ke.state)
|
||||
if (keylist[i]->key == ke.keycode &&
|
||||
keylist[i]->mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state))
|
||||
return keylist[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool operator == (XKeyEvent &ke) const {
|
||||
return (mod == ke.state && key == ke.keycode);
|
||||
return (mod == FbTk::KeyUtil::instance().isolateModifierMask(ke.state) && key == ke.keycode);
|
||||
}
|
||||
|
||||
FbTk::RefCount<FbTk::Command> m_command;
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
#include <iostream>
|
||||
|
||||
void NextWindowCmd::execute() {
|
||||
|
||||
BScreen *screen = Fluxbox::instance()->keyScreen();
|
||||
if (screen != 0) {
|
||||
Fluxbox *fb = Fluxbox::instance();
|
||||
// special case for commands from key events
|
||||
if (fb->lastEvent().type == KeyPress) {
|
||||
unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state);
|
||||
mods = FbTk::KeyUtil::instance().isolateModifierMask(mods);
|
||||
if (mods == 0) // can't stacked cycle unless there is a mod to grab
|
||||
screen->nextFocus(m_option | BScreen::CYCLELINEAR);
|
||||
else {
|
||||
|
@ -71,6 +71,7 @@ void PrevWindowCmd::execute() {
|
|||
// special case for commands from key events
|
||||
if (fb->lastEvent().type == KeyPress) {
|
||||
unsigned int mods = FbTk::KeyUtil::instance().cleanMods(fb->lastEvent().xkey.state);
|
||||
mods = FbTk::KeyUtil::instance().isolateModifierMask(mods);
|
||||
if (mods == 0) // can't stacked cycle unless there is a mod to grab
|
||||
screen->prevFocus(m_option | BScreen::CYCLELINEAR);
|
||||
else {
|
||||
|
|
|
@ -777,11 +777,13 @@ void Fluxbox::handleEvent(XEvent * const e) {
|
|||
#ifdef DEBUG
|
||||
cerr<<__FILE__<<"("<<__FUNCTION__<<"): MappingNotify"<<endl;
|
||||
#endif // DEBUG
|
||||
|
||||
FbTk::KeyUtil::instance().init(); // reinitialise the key utils
|
||||
// reconfigure keys (if the mapping changes, they don't otherwise update
|
||||
m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
|
||||
|
||||
if (e->xmapping.request == MappingKeyboard
|
||||
|| e->xmapping.request == MappingModifier) {
|
||||
XRefreshKeyboardMapping(&e->xmapping);
|
||||
FbTk::KeyUtil::instance().init(); // reinitialise the key utils
|
||||
// reconfigure keys (if the mapping changes, they don't otherwise update
|
||||
m_key->reconfigure(StringUtil::expandFilename(*m_rc_keyfile).c_str());
|
||||
}
|
||||
break;
|
||||
case CreateNotify:
|
||||
break;
|
||||
|
@ -1076,7 +1078,6 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
|
|||
if (keyScreen() == 0 || mouseScreen() == 0)
|
||||
return;
|
||||
|
||||
|
||||
switch (ke.type) {
|
||||
case KeyPress:
|
||||
m_key->doAction(ke);
|
||||
|
@ -1089,9 +1090,10 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
|
|||
if (m_watching_screen && m_watch_keyrelease) {
|
||||
// mask the mod of the released key out
|
||||
// won't mask anything if it isn't a mod
|
||||
ke.state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
|
||||
unsigned int state = FbTk::KeyUtil::instance().isolateModifierMask(ke.state);
|
||||
state &= ~FbTk::KeyUtil::instance().keycodeToModmask(ke.keycode);
|
||||
|
||||
if ((m_watch_keyrelease & ke.state) == 0) {
|
||||
if ((m_watch_keyrelease & state) == 0) {
|
||||
|
||||
m_watching_screen->notifyReleasedKeys(ke);
|
||||
XUngrabKeyboard(FbTk::App::instance()->display(), CurrentTime);
|
||||
|
@ -1107,8 +1109,6 @@ void Fluxbox::handleKeyEvent(XKeyEvent &ke) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// handle system signals
|
||||
|
@ -1951,12 +1951,15 @@ void Fluxbox::unfocusWindow(WinClient &client, bool full_revert, bool unfocus_fr
|
|||
|
||||
|
||||
void Fluxbox::watchKeyRelease(BScreen &screen, unsigned int mods) {
|
||||
|
||||
if (mods == 0) {
|
||||
cerr<<"WARNING: attempt to grab without modifiers!"<<endl;
|
||||
return;
|
||||
}
|
||||
m_watching_screen = &screen;
|
||||
m_watch_keyrelease = mods;
|
||||
|
||||
// just make sure we are saving the mods with any other flags (xkb)
|
||||
m_watch_keyrelease = FbTk::KeyUtil::instance().isolateModifierMask(mods);
|
||||
XGrabKeyboard(FbTk::App::instance()->display(),
|
||||
screen.rootWindow().window(), True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
|
|
|
@ -223,7 +223,7 @@ void FbRun::redrawLabel() {
|
|||
}
|
||||
|
||||
void FbRun::keyPressEvent(XKeyEvent &ke) {
|
||||
// strip numlock, capslock and scrolllock mask
|
||||
|
||||
ke.state = FbTk::KeyUtil::instance().cleanMods(ke.state);
|
||||
|
||||
int cp= cursorPosition();
|
||||
|
@ -232,10 +232,11 @@ void FbRun::keyPressEvent(XKeyEvent &ke) {
|
|||
char keychar[1];
|
||||
XLookupString(&ke, keychar, 1, &ks, 0);
|
||||
// a modifier key by itself doesn't do anything
|
||||
if (IsModifierKey(ks)) return;
|
||||
if (IsModifierKey(ks))
|
||||
return;
|
||||
|
||||
if (ke.state) { // a modifier key is down
|
||||
if (ke.state == ControlMask) {
|
||||
if (FbTk::KeyUtil::instance().isolateModifierMask(ke.state)) { // a modifier key is down
|
||||
if ((ke.state & ControlMask) == ControlMask) {
|
||||
switch (ks) {
|
||||
case XK_p:
|
||||
prevHistoryItem();
|
||||
|
@ -248,7 +249,7 @@ void FbRun::keyPressEvent(XKeyEvent &ke) {
|
|||
setCursorPosition(cp);
|
||||
break;
|
||||
}
|
||||
} else if (ke.state == (Mod1Mask | ShiftMask)) {
|
||||
} else if ((ke.state & (Mod1Mask|ShiftMask)) == (Mod1Mask | ShiftMask)) {
|
||||
switch (ks) {
|
||||
case XK_less:
|
||||
firstHistoryItem();
|
||||
|
|
Loading…
Reference in a new issue