implemented 'MoveN' and 'ClickN' support in keys file.

the hardcoded 'OnTitlebar Mouse1 :Raise' (see Window.cc, FluxboxWindow::buttonPressEvent())
is disabled for now, should be added to fluxbox-update_configs
This commit is contained in:
Mathias Gumz 2009-12-18 08:05:07 +01:00
parent 79859c9448
commit 46261a8284
8 changed files with 216 additions and 98 deletions

View file

@ -1,6 +1,10 @@
(Format: Year/Month/Day)
Changes for 1.1.2
*09/12/18:
* Implemented new 'MoveN' and 'ClickN' support for keys file (Mathias)
Keys.cc Window.cc/hh CurrentWindowCmd.cc FbTk/KeyUtil.cc
*09/12/15:
* Updated fluxbox-keys documentation, added 'Fullscreen' (thanx Paul Tagliamonte)

View file

@ -55,7 +55,7 @@ are most commonly used:
where *Mod1* is the Alt key on the PC keyboard and *Mod4* is usually a key
branded with a familiar company logo.
There are also some special modifiers that refer to mouse button presses:::
There are also some special modifiers that refer to mouse button events:::
*OnDesktop*;;
The mouse cursor is over the desktop (root window), and not any
window.
@ -84,13 +84,21 @@ the key, and see the name in the output. If you have some "special" keys that
do not produce a key name in the output of *xev(1)*, you can just use the
keycode (NOT the keysym!) in your keys file.
Commands can also be bound to mouse button presses, for which the proper "key"
name is *Mouse*'n' where 'n' is the number of the mouse button. For example,
*Mouse1* is the primary button, and *Mouse4* / *Mouse5* are the scroll wheel
events, in normal configurations. *xev(1)* can also be used to tell the button
number.
Commands can also be bound to mouse events ('N' denotes the number of the
button, eg. '1' is the primary button, '4'/'5' are the wheel buttons):
*MouseN*;;
The mouse button 'N' is pressed down and holded.
*ClickN*;;
The mouse button 'N' is clicked (pressed and released with no
movement in between)
*MoveN*;;
The mouse button 'N' is currently holded, the binded action is triggered
as often as the mouse moves.
There are some special "keys" that let you bind events to non-keyboard events:
There are some special "keys" that let you bind events to non-keyboard events:::
*ChangeWorkspace*;;
Fires when the workspace changes. This can be used to change backgrounds or
do anything else you like when you switch to a new workspace. See the

View file

@ -2,12 +2,12 @@
.\" Title: fluxbox-keys
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.75.1 <http://docbook.sf.net/>
.\" Date: 12/14/2009
.\" Date: 12/17/2009
.\" Manual: Fluxbox Manual
.\" Source: fluxbox-keys.txt
.\" Language: English
.\"
.TH "FLUXBOX\-KEYS" "5" "12/14/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual"
.TH "FLUXBOX\-KEYS" "5" "12/17/2009" "fluxbox\-keys\&.txt" "Fluxbox Manual"
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
@ -53,7 +53,7 @@ You can get a list of possible modifiers by calling \(oqxmodmap \-pm\(cq\&. This
.sp
where \fBMod1\fR is the Alt key on the PC keyboard and \fBMod4\fR is usually a key branded with a familiar company logo\&.
.PP
There are also some special modifiers that refer to mouse button presses
There are also some special modifiers that refer to mouse button events
.RS 4
.PP
\fBOnDesktop\fR
@ -90,10 +90,30 @@ You may specify a key by its key name (for example, \fBa\fR or \fBspace\fR) or b
.sp
If you don\(cqt know the name of a key, you can run \fBxev(1)\fR in a terminal, push the key, and see the name in the output\&. If you have some "special" keys that do not produce a key name in the output of \fBxev(1)\fR, you can just use the keycode (NOT the keysym!) in your keys file\&.
.sp
Commands can also be bound to mouse button presses, for which the proper "key" name is \fBMouse\fR\fIn\fR where \fIn\fR is the number of the mouse button\&. For example, \fBMouse1\fR is the primary button, and \fBMouse4\fR / \fBMouse5\fR are the scroll wheel events, in normal configurations\&. \fBxev(1)\fR can also be used to tell the button number\&.
Commands can also be bound to mouse events (\fIN\fR denotes the number of the button, eg\&. \fI1\fR is the primary button, \fI4\fR/\fI5\fR are the wheel buttons):
.PP
There are some special "keys" that let you bind events to non\-keyboard events
\fBMouseN\fR
.RS 4
The mouse button
\fIN\fR
is pressed down and holded\&.
.RE
.PP
\fBClickN\fR
.RS 4
The mouse button
\fIN\fR
is clicked (pressed and released with no movement in between)
.RE
.PP
\fBMoveN\fR
.RS 4
The mouse button
\fIN\fR
is currently holded, the binded action is triggered as often as the mouse moves\&.
.RE
.sp
There are some special "keys" that let you bind events to non\-keyboard events:
.PP
\fBChangeWorkspace\fR
.RS 4
@ -101,7 +121,6 @@ Fires when the workspace changes\&. This can be used to change backgrounds or do
\fBEXAMPLES\fR
below for one idea\&.
.RE
.RE
.if n \{\
.sp
.\}

View file

@ -262,11 +262,26 @@ void GoToTabCmd::real_execute() {
REGISTER_COMMAND(startmoving, StartMovingCmd, void);
void StartMovingCmd::real_execute() {
int x;
int y;
const XEvent &last = Fluxbox::instance()->lastEvent();
if (last.type == ButtonPress) {
const XButtonEvent &be = last.xbutton;
fbwindow().startMoving(be.x_root, be.y_root);
switch (last.type) {
case ButtonPress:
x = last.xbutton.x_root;
y = last.xbutton.y_root;
break;
case MotionNotify:
x = last.xmotion.x_root;
y = last.xmotion.y_root;
break;
default:
return;
}
fbwindow().startMoving(x, y);
}
FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args,
@ -305,15 +320,27 @@ FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &ar
REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void);
void StartResizingCmd::real_execute() {
int x;
int y;
const XEvent &last = Fluxbox::instance()->lastEvent();
if (last.type == ButtonPress) {
const XButtonEvent &be = last.xbutton;
int x = be.x_root - fbwindow().x()
- fbwindow().frame().window().borderWidth();
int y = be.y_root - fbwindow().y()
- fbwindow().frame().window().borderWidth();
fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
switch (last.type) {
case ButtonPress:
x = last.xbutton.x_root;
y = last.xbutton.y_root;
break;
case MotionNotify:
x = last.xmotion.x_root;
y = last.xmotion.y_root;
break;
default:
return;
}
x -= fbwindow().x() - fbwindow().frame().window().borderWidth();
y -= fbwindow().y() - fbwindow().frame().window().borderWidth();
fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
}
REGISTER_COMMAND(starttabbing, StartTabbingCmd, void);

View file

@ -42,16 +42,16 @@ struct t_modlist{
};
const struct t_modlist modlist[] = {
{"SHIFT", ShiftMask},
{"LOCK", LockMask},
{"CONTROL", ControlMask},
{"MOD1", Mod1Mask},
{"MOD2", Mod2Mask},
{"MOD3", Mod3Mask},
{"MOD4", Mod4Mask},
{"MOD5", Mod5Mask},
{"ALT", Mod1Mask},
{"CTRL", ControlMask},
{"shift", ShiftMask},
{"lock", LockMask},
{"control", ControlMask},
{"mod1", Mod1Mask},
{"mod2", Mod2Mask},
{"mod3", Mod3Mask},
{"mod4", Mod4Mask},
{"mod5", Mod5Mask},
{"alt", Mod1Mask},
{"ctrl", ControlMask},
{0, 0}
};
@ -88,7 +88,7 @@ void KeyUtil::loadModmap() {
XFreeModifiermap(m_modmap);
m_modmap = XGetModifierMapping(App::instance()->display());
// 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) {
@ -96,7 +96,7 @@ void KeyUtil::loadModmap() {
if (m_modmap->modifiermap[realkey] == 0)
continue;
KeySym ks = XKeycodeToKeysym(App::instance()->display(),
KeySym ks = XKeycodeToKeysym(App::instance()->display(),
m_modmap->modifiermap[realkey], 0);
switch (ks) {
@ -154,12 +154,18 @@ void KeyUtil::grabButton(unsigned int button, unsigned int mod, Window win,
*/
unsigned int KeyUtil::getKey(const char *keystr) {
if (!keystr)
return 0;
KeySym sym = XStringToKeysym(keystr);
if (sym==NoSymbol)
return 0;
return XKeysymToKeycode(App::instance()->display(), sym);
KeyCode code = 0;
if (keystr) {
KeySym sym = XStringToKeysym(keystr);
if (sym != NoSymbol) {
code = XKeysymToKeycode(App::instance()->display(), sym);
}
}
return code;
}
@ -169,14 +175,14 @@ unsigned int KeyUtil::getKey(const char *keystr) {
unsigned int KeyUtil::getModifier(const char *modstr) {
if (!modstr)
return 0;
// find mod mask string
for (unsigned int i=0; modlist[i].str !=0; i++) {
if (modlist[i] == modstr)
return modlist[i].mask;
if (modlist[i] == modstr)
return modlist[i].mask;
}
return 0;
return 0;
}
/// Ungrabs the keys
@ -193,7 +199,7 @@ void KeyUtil::ungrabButtons(Window win) {
unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
XModifierKeymap *modmap = instance().m_modmap;
if (!modmap)
if (!modmap)
return 0;
// search through modmap for this keycode
@ -204,7 +210,7 @@ unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
return modlist[mod].mask;
}
}
}
}
// no luck
return 0;

View file

@ -106,6 +106,28 @@ using std::pair;
using FbTk::STLUtil::destroyAndClearSecond;
namespace {
// candidate for FbTk::StringUtil ?
int extractKeyFromString(const std::string& in, const char* start_pattern, unsigned int& key) {
int ret = 0;
if (strstr(in.c_str(), start_pattern) != 0) {
unsigned int tmp_key = 0;
if (FbTk::StringUtil::extractNumber(in.substr(strlen(start_pattern)), tmp_key)) {
key = tmp_key;
ret = 1;
}
}
return ret;
}
} // end of anonymouse namespace
// helper class 'keytree'
class Keys::t_key {
public:
@ -254,10 +276,12 @@ void Keys::grabWindow(Window win) {
if ((win_it->second & Keys::GLOBAL) > 0 && (*it)->type == KeyPress)
FbTk::KeyUtil::grabKey((*it)->key, (*it)->mod, win);
// ON_DESKTOP buttons don't need to be grabbed
else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0 &&
(*it)->type == ButtonPress)
FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win,
ButtonPressMask|ButtonReleaseMask);
else if ((win_it->second & (*it)->context & ~Keys::ON_DESKTOP) > 0) {
if ((*it)->type == ButtonPress || (*it)->type == ButtonRelease || (*it)->type == MotionNotify) {
FbTk::KeyUtil::grabButton((*it)->key, (*it)->mod, win, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask);
}
}
}
}
@ -363,85 +387,84 @@ bool Keys::addBinding(const string &linebuffer) {
// for each argument
for (; argc < val.size(); argc++) {
if (val[argc][0] != ':') { // parse key(s)
std::string arg = FbTk::StringUtil::toLower(val[argc]);
int tmpmod = FbTk::KeyUtil::getModifier(val[argc].c_str());
if (arg[0] != ':') { // parse key(s)
int tmpmod = FbTk::KeyUtil::getModifier(arg.c_str());
if(tmpmod)
mod |= tmpmod; //If it's a modifier
else if (strcasecmp("ondesktop", val[argc].c_str()) == 0)
else if (arg == "ondesktop")
context |= ON_DESKTOP;
else if (strcasecmp("ontoolbar", val[argc].c_str()) == 0)
else if (arg == "ontoolbar")
context |= ON_TOOLBAR;
else if (strcasecmp("onwindow", val[argc].c_str()) == 0)
else if (arg == "onwindow")
context |= ON_WINDOW;
else if (strcasecmp("ontitlebar", val[argc].c_str()) == 0)
else if (arg == "ontitlebar")
context |= ON_TITLEBAR;
else if (strcasecmp("double", val[argc].c_str()) == 0)
else if (arg == "double")
isdouble = true;
else if (strcasecmp("NONE",val[argc].c_str())) {
// check if it's a mouse button
if (strcasecmp("focusin", val[argc].c_str()) == 0) {
else if (arg != "none") {
if (arg == "focusin") {
context = ON_WINDOW;
mod = key = 0;
type = FocusIn;
} else if (strcasecmp("focusout", val[argc].c_str()) == 0) {
} else if (arg == "focusout") {
context = ON_WINDOW;
mod = key = 0;
type = FocusOut;
} else if (strcasecmp("changeworkspace",
val[argc].c_str()) == 0) {
} else if (arg == "changeworkspace") {
context = ON_DESKTOP;
mod = key = 0;
type = FocusIn;
} else if (strcasecmp("mouseover", val[argc].c_str()) == 0) {
} else if (arg == "mouseover") {
type = EnterNotify;
if (!(context & (ON_WINDOW|ON_TOOLBAR)))
context |= ON_WINDOW;
key = 0;
} else if (strcasecmp("mouseout", val[argc].c_str()) == 0) {
} else if (arg == "mouseout") {
type = LeaveNotify;
if (!(context & (ON_WINDOW|ON_TOOLBAR)))
context |= ON_WINDOW;
key = 0;
} else if (strcasecmp(val[argc].substr(0,5).c_str(),
"mouse") == 0 &&
val[argc].length() > 5) {
// check if it's a mouse button
} else if (extractKeyFromString(arg, "mouse", key)) {
type = ButtonPress;
key = atoi(val[argc].substr(5,
val[argc].length()-5).c_str());
// fluxconf mangles things like OnWindow Mouse# to Mouse#ow
if (strstr(val[argc].c_str(), "top"))
if (strstr(arg.c_str(), "top"))
context = ON_DESKTOP;
else if (strstr(val[argc].c_str(), "ebar"))
else if (strstr(arg.c_str(), "ebar"))
context = ON_TITLEBAR;
else if (strstr(val[argc].c_str(), "bar"))
else if (strstr(arg.c_str(), "bar"))
context = ON_TOOLBAR;
else if (strstr(val[argc].c_str(), "ow"))
else if (strstr(arg.c_str(), "ow"))
context = ON_WINDOW;
} else if (extractKeyFromString(arg, "click", key)) {
type = ButtonRelease;
} else if (extractKeyFromString(arg, "move", key)) {
type = MotionNotify;
} else if (key = FbTk::KeyUtil::getKey(val[argc].c_str())) { // convert from string symbol
type = KeyPress;
// keycode covers the following three two-byte cases:
// 0x - hex
// +[1-9] - number between +1 and +9
// numbers 10 and above
//
} else if (!val[argc].empty() && ((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);
type = KeyPress;
if (errno == EINVAL || errno == ERANGE)
key = 0;
} else { // convert from string symbol
key = FbTk::KeyUtil::getKey(val[argc].c_str());
} else {
FbTk::StringUtil::extractNumber(arg, key);
type = KeyPress;
}
if (key == 0 && (type == KeyPress || type == ButtonPress))
if (key == 0 && (type == KeyPress || type == ButtonPress || type == ButtonRelease))
return false;
if (type != ButtonPress)
isdouble = false;
if (!first_new_key) {
first_new_keylist = current_key;
current_key = current_key->find(type, mod, key, context,
@ -470,7 +493,7 @@ bool Keys::addBinding(const string &linebuffer) {
return false;
const char *str = FbTk::StringUtil::strcasestr(linebuffer.c_str(),
val[argc].c_str());
val[argc].c_str());
if (str) // +1 to skip ':'
current_key->m_command = FbTk::CommandParser<void>::instance().parse(str + 1);
@ -504,10 +527,11 @@ bool Keys::doAction(int type, unsigned int mods, unsigned int key,
bool isdouble = false;
if (type == ButtonPress) {
if (time > last_button_time)
if (time > last_button_time) {
double_click = (time - last_button_time <
Fluxbox::instance()->getDoubleClickInterval()) &&
last_button == key;
}
last_button_time = time;
last_button = key;
isdouble = double_click;

View file

@ -280,6 +280,7 @@ FluxboxWindow::FluxboxWindow(WinClient &client):
m_button_grab_x(0), m_button_grab_y(0),
m_last_move_x(0), m_last_move_y(0),
m_last_resize_h(1), m_last_resize_w(1),
m_last_pressed_button(0),
m_workspace_number(0),
m_current_state(0),
m_old_decoration_mask(0),
@ -1073,7 +1074,6 @@ void FluxboxWindow::grabButtons() {
GrabModeSync, GrabModeSync, None, None);
XUngrabButton(display, Button1, Mod1Mask|Mod2Mask|Mod3Mask,
frame().window().window());
}
@ -1478,7 +1478,7 @@ void FluxboxWindow::setFullscreenLayer() {
FluxboxWindow *foc = FocusControl::focusedFbWindow();
// if another window on the same head is focused, make sure we can see it
if (isFocused() || !foc || &foc->screen() != &screen() ||
getOnHead() != foc->getOnHead() ||
getOnHead() != foc->getOnHead() ||
(foc->winClient().isTransient() &&
foc->winClient().transientFor()->fbwindow() == this)) {
moveToLayer(::Layer::ABOVE_DOCK);
@ -2370,13 +2370,16 @@ bool FluxboxWindow::isTyping() const {
void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
m_last_button_x = be.x_root;
m_last_button_y = be.y_root;
m_last_pressed_button = be.button;
bool onTitlebar =
frame().insideTitlebar( be.window ) &&
frame().handle().window() != be.window;
#if 0 // disabled
if (onTitlebar && be.button == 1)
raise();
#endif
// check keys file first
Keys *k = Fluxbox::instance()->keys();
@ -2412,19 +2415,27 @@ void FluxboxWindow::buttonPressEvent(XButtonEvent &be) {
void FluxboxWindow::buttonReleaseEvent(XButtonEvent &re) {
if (m_last_pressed_button == re.button) {
m_last_pressed_button = 0;
}
if (isMoving())
stopMoving();
else if (isResizing())
stopResizing();
else if (m_attaching_tab)
attachTo(re.x_root, re.y_root);
else
frame().tabcontainer().tryButtonReleaseEvent(re);
else if (!frame().tabcontainer().tryButtonReleaseEvent(re)) {
if (m_last_button_x == re.x_root && m_last_button_y == re.y_root) {
Fluxbox::instance()->keys()->doAction(re.type, re.state, re.button, Keys::ON_WINDOW, &winClient(), re.time);
}
}
}
void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
if (isMoving() && me.window == parent()) {
me.window = frame().window().window();
}
@ -2452,6 +2463,13 @@ void FluxboxWindow::motionNotifyEvent(XMotionEvent &me) {
}
}
// in case someone put MoveX :StartMoving etc into keys, we have
// to activate it before doing the actual motionNotify code
Fluxbox::instance()->keys()->doAction(me.type, me.state, m_last_pressed_button,
inside_titlebar ? Keys::ON_TITLEBAR : Keys::ON_WINDOW,
&winClient(), me.time);
if (moving || ((me.state & Button1Mask) && functions.move &&
inside_titlebar && !isResizing() && m_attaching_tab == 0)) {
@ -2818,8 +2836,14 @@ void FluxboxWindow::setDecorationMask(unsigned int mask, bool apply) {
}
void FluxboxWindow::startMoving(int x, int y) {
if (s_num_grabs > 0)
if (isMoving()) {
return;
}
if (s_num_grabs > 0) {
return;
}
if (isMaximized() && screen().getMaxDisableMove())
return;
@ -3062,6 +3086,7 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
ResizeModel model) const {
int cx = frame().width() / 2;
int cy = frame().height() / 2;
if (model == CENTERRESIZE)
@ -3088,6 +3113,9 @@ FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
void FluxboxWindow::startResizing(int x, int y, ReferenceCorner dir) {
if (isResizing())
return;
if (s_num_grabs > 0 || isShaded() || isIconic() )
return;
@ -3550,7 +3578,7 @@ void FluxboxWindow::updateButtons() {
need_update = true;
}
}
}
if (!need_update)
@ -3680,6 +3708,7 @@ void FluxboxWindow::grabPointer(Window grab_window,
Window confine_to,
Cursor cursor,
Time time) {
XGrabPointer(FbTk::App::instance()->display(),
grab_window,
owner_events,
@ -3870,7 +3899,7 @@ void FluxboxWindow::setWindowType(WindowState::WindowType type) {
*/
}
void FluxboxWindow::focusedWindowChanged(BScreen &screen,
void FluxboxWindow::focusedWindowChanged(BScreen &screen,
FluxboxWindow *focused_win, WinClient* client) {
if (focused_win) {
setFullscreenLayer();

View file

@ -547,6 +547,7 @@ private:
int m_last_resize_x, m_last_resize_y; // handles last button press event for resize
int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving
int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window"
int m_last_pressed_button;
timeval m_last_keypress_time;