As mentioned in a previous posting to the blackbox mailing list, I offer
up a patch for bbkeys to support keyboard-mouse support. My patch is the
code only at this point. If it is acceptable, then some other stuff
needs to be tweaked (man pages, Perl config script, bbconf, etc.).
The basic idea is as described before:
>I added the following actions to bbkeys:
>
> MouseUp - move cursor up
> MouseDown - move cursor down
> MouseLeft - move cursor left
> MouseRight - move cursor right
>
> MouseButton1 - send button 1 click to front window
> MouseButton2 - send button 2 click to front window
> MouseButton3 - send button 3 click to front window
>
> RootMouseButton1 - send button 1 click to root window
> RootMouseButton2 - send button 1 click to root window
> RootMouseButton3 - send button 1 click to root window
Adding these things to the .bbkeysrc is easy. For example:
KeyToGrab(KP_0), WithModifier(None), WithAction(RootMouseButton3)
KeyToGrab(KP_Equal), WithModifier(None), WithAction(MouseButton1)
KeyToGrab(KP_Divide), WithModifier(None), WithAction(MouseButton2)
KeyToGrab(KP_Multiply), WithModifier(None), WithAction(MouseButton3)
The only tricky ones are the mouse motion actions, since they allow you
to specify a movement distance:
KeyToGrab(KP_8), WithModifier(None), WithAction(MouseUp), Delta(10)
KeyToGrab(KP_2), WithModifier(None), WithAction(MouseDown)
KeyToGrab(KP_6), WithModifier(None), WithAction(MouseRight),
Delta(30)
KeyToGrab(KP_4), WithModifier(None), WithAction(MouseLeft)
As mentioned before, the "Delta" value is crude at present, allowing you
to only specify vertical and horizontal movement deltas that apply to all
Mouse* actions. It is not possible (at the moment) to specify something
like alt+KP_8 moves up 10 pixels while control+KP_8 moves 20 pixels. It
is possible to have different horizontal and vertical motion amounts
though.
And the patches to grab_defs.hh, bbkeys.hh, and bbkeys.cc are as follows.
(This is small, so please excuse the inclusion here.)
Oh-- be sure to make clean before changing grab_defs.hh. The bbkeys
Makefile doesn't seem to track that file.
--- bbkeys-0.8.4/src/grab_defs.hh Sun Jan 13 13:59:39 2002
+++ bbkeys-mouse/src/grab_defs.hh Sun Jul 14 21:15:48 2002
@@ -75,6 +75,19 @@
grabVertDec,
grabToggleDecor,
+
+ grabMouseUp,
+ grabMouseDown,
+ grabMouseLeft,
+ grabMouseRight,
+
+ grabMouseButton1,
+ grabMouseButton2,
+ grabMouseButton3,
+
+ grabRootMouseButton1,
+ grabRootMouseButton2,
+ grabRootMouseButton3,
NUM_GRABS
};
--- bbkeys-0.8.4/src/bbkeys.hh Sun Jan 13 13:59:39 2002
+++ bbkeys-mouse/src/bbkeys.hh Sat Jul 13 22:41:22 2002
@@ -137,6 +137,10 @@
void saveMenuSearch(Window,Basemenu *);
void removeMenuSearch(Window);
+ // functions for mouse movement and button handling
+ void moveMouse(const int delta_x,const int delta_y);
+ void clickMouse(const unsigned int button,const Bool is_press,const
Bool sendToRoot = false);
+
// functions which return information
inline int getCurrentDesktopNr(void) {
return current_desktop?current_desktop->number:-1;
@@ -201,6 +205,8 @@
LinkedList<DesktopList> *desktopList; // list of all desktop windows
Window focus_window;
// window which has the focus
+ int mouseDeltaX,mouseDeltaY;
+
WMInterface *wminterface; // interface for communicating with the
// window manager
--- bbkeys-0.8.4/src/bbkeys.cc Mon Jan 14 22:21:25 2002
+++ bbkeys-mouse/src/bbkeys.cc Sun Jul 14 21:52:57 2002
@@ -618,6 +620,26 @@
if (!strcasecmp(action, "ToggleDecor"))
return grabToggleDecor;
+ if (!strcasecmp(action, "MouseUp"))
+ return grabMouseUp;
+ if (!strcasecmp(action, "MouseDown"))
+ return grabMouseDown;
+ if (!strcasecmp(action, "MouseLeft"))
+ return grabMouseLeft;
+ if (!strcasecmp(action, "MouseRight"))
+ return grabMouseRight;
+ if (!strcasecmp(action, "MouseButton1"))
+ return grabMouseButton1;
+ if (!strcasecmp(action, "MouseButton2"))
+ return grabMouseButton2;
+ if (!strcasecmp(action, "MouseButton3"))
+ return grabMouseButton3;
+ if (!strcasecmp(action, "RootMouseButton1"))
+ return grabRootMouseButton1;
+ if (!strcasecmp(action, "RootMouseButton2"))
+ return grabRootMouseButton2;
+ if (!strcasecmp(action, "RootMouseButton3"))
+ return grabRootMouseButton3;
return 0;
}
@@ -776,7 +798,8 @@
/* if we're supposed to having an execCommand and we
do have
* something to put into it
*/
- if (grabSet.KeyMap[count].action == grabExecute) {
+ if (grabSet.KeyMap[count].action == grabExecute)
+ {
execCmdBegin = strchr(actionBegin + 1, '(');
if (execCmdBegin) {
strncpy(execCommand,
execCmdBegin + 1,
@@ -784,8 +807,43 @@
grabSet.KeyMap[count].execCommand =
strdup(execCommand);
}
- } else {
- grabSet.KeyMap[count].execCommand = NULL;
+ }
+
+ else
+ {
+ grabSet.KeyMap[count].execCommand = NULL;
+
+
+ // If we are doing a mouse-movement
+action, the user can specify
the deltaX/Y
+
+ if (grabSet.KeyMap[count].action ==
+grabMouseUp ||
+ grabSet.KeyMap[count].action
+== grabMouseDown ||
+ grabSet.KeyMap[count].action
+== grabMouseLeft ||
+ grabSet.KeyMap[count].action
+== grabMouseRight)
+ {
+ execCmdBegin = strchr(actionBegin +
+1, '(');
+
+ if (execCmdBegin)
+ {
+ strncpy(execCommand,
+execCmdBegin + 1,strcspn(execCmdBegin + 1,
")"));
+
+ int delta = atoi(execCommand);
+
+ if (delta > 0)
+ {
+ if
+(grabSet.KeyMap[count].action == grabMouseLeft ||
+
+grabSet.KeyMap[count].action == grabMouseRight)
+ {
+ mouseDeltaX =
+delta;
+ }
+
+ else
+ {
+ mouseDeltaY =
+delta;
+ }
+ }
+ }
+ }
}
#ifdef DEBUG
@@ -861,6 +919,11 @@
desktop_count = 0;
doingCycling = False;
+ // hard-code this until someone tells me the elegant way to do this
(probably
+ // from the prefs file or the command line)
+ mouseDeltaX = 30;
+ mouseDeltaY = 10;
+
// make draw the bbkeys window
MakeWindow(False);
Redraw();
@@ -1762,8 +1825,61 @@
wminterface->decorateToggleWindow(focus_window);
}
break;
+
+ case grabMouseUp:
+ moveMouse(0,-mouseDeltaY);
+ break;
+
+ case grabMouseDown:
+ moveMouse(0,mouseDeltaY);
+ break;
+
+ case grabMouseLeft:
+ moveMouse(-mouseDeltaX,0);
+ break;
+
+ case grabMouseRight:
+ moveMouse(mouseDeltaX,0);
+ break;
+
+ case grabMouseButton1:
+ clickMouse(1,True,false);
+ usleep(100000);
+ clickMouse(1,False,false);
+ break;
+
+ case grabMouseButton2:
+ clickMouse(2,True,false);
+ usleep(100000);
+ clickMouse(2,False,false);
+ break;
+
+ case grabMouseButton3:
+ clickMouse(3,True,false);
+ usleep(100000);
+ clickMouse(3,False,false);
+ break;
+
+ case grabRootMouseButton1:
+ clickMouse(1,True,true);
+ usleep(100000);
+ clickMouse(1,False,true);
+ break;
+
+ case grabRootMouseButton2:
+ clickMouse(2,True,true);
+ usleep(100000);
+ clickMouse(2,False,true);
+ break;
+
+ case grabRootMouseButton3:
+ clickMouse(3,True,true);
+ usleep(100000);
+ clickMouse(3,False,true);
+ break;
}
}
+
timer->start();
break;
}
@@ -2294,3 +2410,218 @@
it.current()->desktop);
}
+
+
+/*************************************************************************
******
+
+ Mouse Simulation Code
+
+**************************************************************************
*****/
+
+void ToolWindow::moveMouse(const int delta_x,const int delta_y)
+{
+Display *display;
+Window root;
+Window root_return,child_return;
+int root_x, root_y, win_x, win_y;
+unsigned int modkey_mask;
+
+
+ display = getXDisplay();
+
+ root = getCurrentScreenInfo()->getRootWindow();
+
+ XQueryPointer(display, root, &root_return, &child_return, &root_x,
&root_y, &win_x, &win_y, &modkey_mask);
+
+#ifdef DEBUG
+ fprintf(stderr,"Current cursor = (%d,%d)\n",root_x,root_y);
+#endif
+
+ root_x += delta_x;
+ root_y += delta_y;
+
+ XWarpPointer(display, None, root, 0, 0, 0, 0, root_x, root_y);
+
+ XFlush(display);
+}
+
+
+
+void ToolWindow::clickMouse(const unsigned int buttonNum,const Bool
is_press,const Bool sendToRoot)
+{
+Display *display;
+Window root_id,child_id,root_return_id,window_id;
+int root_x, root_y, win_x, win_y;
+unsigned int modkey_mask;
+
+XEvent theEvent;
+
+unsigned int eventType;
+unsigned int sendMask;
+unsigned int stateMask;
+
+static unsigned int buttonMasks[] = { 0, Button1Mask, Button2Mask,
Button3Mask, Button4Mask, Button5Mask };
+static unsigned int buttonCodes[] = { 0, Button1, Button2, Button3,
Button4, Button5 };
+
+
+ // Sanity check
+
+ if (buttonNum < 1 || buttonNum > 5)
+ {
+#ifdef DEBUG
+ fprintf(stderr,"ToolWindow::clickMouse: Bad buttonNum =
%ud\n",buttonNum);
+#endif
+
+ return;
+ }
+
+
+#ifdef DEBUG
+ fprintf(stderr,"ToolWindow::clickMouse: Beginning....\n");
+#endif
+
+ // Get the active X display, root window, current cursor info
+
+ display = getXDisplay();
+
+ root_id = getCurrentScreenInfo()->getRootWindow();
+
+#ifdef DEBUG
+ fprintf(stderr,"root_id = 0x%lX\n",(unsigned long) root_id);
+#endif
+
+
+ if (XQueryPointer(display, root_id, &root_return_id, &child_id,
&root_x, &root_y, &win_x, &win_y, &modkey_mask) == False)
+ {
+#ifdef DEBUG
+ fprintf(stderr,"ToolWindow::clickMouse: while getting root-level info,
XQueryPointer() returned False\n");
+#endif
+
+ return;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"root_return_id = 0x%lX\n",(unsigned long)
root_return_id);
+ fprintf(stderr,"child_id = 0x%lX\n",(unsigned long) child_id);
+#endif
+
+
+ window_id = root_id;
+
+
+ // If we are not sending to the root window, then we have to drill down
to find the deepest child window
+
+ if (!sendToRoot)
+ {
+ while (child_id != None)
+ {
+ window_id = child_id;
+
+ if (XQueryPointer(display, window_id, &root_return_id,
+&child_id,
&root_x, &root_y, &win_x, &win_y, &modkey_mask) == False)
+ {
+#ifdef DEBUG
+ fprintf(stderr,"ToolWindow::clickMouse: while drilling
+down,
XQueryPointer() returned False\n");
+#endif
+
+ return;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"after drilling:\n");
+ fprintf(stderr,"window_id = 0x%lX\n",(unsigned long)
+window_id);
+ fprintf(stderr,"child_id = 0x%lX\n",(unsigned long) child_id);
+#endif
+ }
+ }
+
+
+ // Button press or release?
+
+ if (is_press)
+ {
+ eventType = ButtonPress;
+ stateMask = 0;
+
+ sendMask = ButtonPressMask | buttonMasks[buttonNum];
+ }
+
+ else
+ {
+ eventType = ButtonRelease;
+ stateMask = buttonMasks[buttonNum];
+
+ sendMask = ButtonReleaseMask | buttonMasks[buttonNum];
+ }
+
+
+#ifdef DEBUG
+ fprintf(stderr,"finally:\n");
+ fprintf(stderr,"root_id = 0x%lX\n",(unsigned long) root_id);
+ fprintf(stderr,"window_id = 0x%lX\n",(unsigned long) window_id);
+ fprintf(stderr,"child_id = 0x%lX\n",(unsigned long) child_id);
+#endif
+
+
+ // Finally, set up the XEvent we'll be sending
+
+ bzero(&theEvent,sizeof(XEvent));
+
+ theEvent.type = eventType;
+
+ theEvent.xbutton.type = theEvent.type;
+ theEvent.xbutton.serial = 0;
+ theEvent.xbutton.send_event = True;
+ theEvent.xbutton.display = display;
+ theEvent.xbutton.window = window_id;
+ theEvent.xbutton.root = root_id;
+ theEvent.xbutton.subwindow = child_id;
+ theEvent.xbutton.time = CurrentTime;
+ theEvent.xbutton.x = win_x;
+ theEvent.xbutton.y = win_y;
+ theEvent.xbutton.x_root = root_x;
+ theEvent.xbutton.y_root = root_y;
+ theEvent.xbutton.state = stateMask;
+ theEvent.xbutton.button = buttonCodes[buttonNum];
+ theEvent.xbutton.same_screen = True;
+
+
+ // Finally, send the event
+
+ if (XSendEvent(display, window_id, True, sendMask, &theEvent) == 0)
+ {
+#ifdef DEBUG
+ fprintf(stderr,"ToolWindow::clickMouse: XSendEvent Failed\n");
+#endif
+ }
+
+ XFlush(display);
+}