#|
Summary
Activate buttons on motionbox without jostling it.
Toggle primary button for "press" or "release",
f.e. drag'n drop without accidental drop.
Buttonboard bindings for numeric pad.
|#
#|
This emerges in the universe on its own, as all has.
|#
#|
Content outline
* Requirements
* General function use and naming conventions
* Commands.
* stumpwm:defcommand pointer-button-activate.nu
Activate the pointer button of a motionbox.
Obsoletes #'ratclick and #'*-fake-click functions.
* stumpwm:defcommand pointer-button-toggle.nu
Press or release the pointer button of a motionbox.
Specifically: drag'n drop without accidental drops.
* Buttonboard bindings for pointer activation
|#
#|#
Requirements
This was experienced within:
* stumpwm tiled-view manager
It was a lisp image of SBCL
(Steel Bank Common Lisp 2.1.0).
stumpwm.github.io
sbcl.org
* Common Lisp X Interface (CLX) 0.7.5
The CLX had the XTEST extension (or similar)
for activating the pointer in the Xserver.
github.com/sharplispers/clx
* Xserver
x.org
|#
#|
Hereafter, there be code.
|#
#|#
General function use and naming conventions
"pointer-button": Collective name for symbols.
".nu": Arbitrary suffix for preventing name collisions,
as in "named uniquely" or "now unique".
Trace the source of variables by prefixing a letter
representing that source.
defun args prefix: F for "function"
let args prefix: L for "let"
lambda args prefix: A for "anonymous function"
Combine A and L prefixes by depth, thereby revealing scope
and discouraging perplexation. For example:
defun args -> F prefix
defun > let args -> L prefix
defun > let > let > lambda args -> LLA prefix
Favoring using the special operator 'multiple-value-call
instead of the macro 'multiple-value-list for results
from Common Lisp funicles returning multiple values.
Consider replacing any funicles returning multiple values
with new funicles returning a list, thereby eliminating
the use of 'multiple-value-call, too.
The stumpwm source tends to have variables and functions
prefixed with an "x" when referring to an instance from
the Common Lisp X Interface library, like an xlib class
or structure. For example: xwin. Do the same.
See also:
* Notes from the documentation for stumpwm and CLX.
|#
#|
Commands.
|#
;#
(stumpwm:defcommand
pointer-button-activate.nu
(&optional
(Fbutton 1))
;;The values were ignored from the keybinding
;; when nothing declared for a prompt.
;; No prompt needed, but value type seems needed.
((:number"Pointer button to activate (1-5): "))
#|
Replace functions for activating pointer buttons.
Function stumpwm:ratclick
> stumpwm:send-fake-click
> stumpwm:xlib-fake-click
> xlib:send-event
Fails.
Consider ratclick and *fake-click as obsolete.
Use xlib/xtest:fake-button-event.
Tested and works for button 1 (primary)
and button 3 (secondary).
|#
"Activate the Xserver pointer button.
Fbutton is a number representing a button on a motionbox,
typically 1 through 5. Default is 1.
Send two events for the button to the Xserver:
a button-press event, then a button-release event."
#|
Required by #'xlib/xtest:fake-button-event function:
display; button number; t for press, nil for release.
|#
;;Press the button.
(xlib/xtest:fake-button-event stumpwm:*display* Fbutton t)
;;Release the button.
(xlib/xtest:fake-button-event stumpwm:*display* Fbutton()))
;#
(stumpwm:defcommand
pointer-button-toggle.nu
(&optional
(Fbutton 1))
((:number"Pointer button to toggle (1-5): "))
"Press or release the Xserver pointer button.
Fbutton is a number representing a button on a motionbox,
with 1 through 5 supported by an Xserver. Default is 1.
Release the pointer button for the cursor when it
is already pressed, otherwise press it.
That is, it is like a toggle switch, so no need to hold
a button, and the same command be used because it finds out
whether that button is currently considered by the Xserver
as pressed.
Specifically intended for drag-and-drop without needing to
hold a button while dragging, regardless of positioning
the cursor with a motionbox or by some other means.
In other words:
1. Move the motionbox to position the cursor for pickup
(or position the cursor by any other means).
2. Type the button on the buttonboard for this command.
No need to hold the button on buttonboard,
and no need to use the buttocks on the rodent.
3. Move the motionbox to reposition cursor for drop
with no worries of accidentally releasing a button.
4. Type the same button on the buttonboard for
this command to complete the drag'n drop.
Be aware some computer programmers made their programs
purposely disable the keyboard when a pointer button
is detected as pressed, regardless of how it is toggled.
Or, their programs might temporarily remap the keyboard
when a pointer button is detected as pressed.
Either way, the bindings for any personalized commands
might become inaccessible, thereby making the person
operating the computer become artificially disabled
by the program of those computer programmers.
In that case, either complete the drag'n drop action with
a motionbox, or try to cancel by using the Esc button."
#|
Send a button-release event for the button to the Xserver
when the button is known to be pressed, otherwise send
a button-press event.
The function #'xlib:query-pointer returns multiple values,
with the fifth element as the keyboard/button mask.
The first byte represents the modifier buttons on
the keyboard. The next five bits are for the five buttons
supported by the Xserver. A bit as 1 for a button means
it is currently pressed.
For example, the mask when button 1 is pressed is 256
as a decimal number, or 00000001 00000000 as binary.
Dropping the first 8 bits (the 00000000) leaves 00000001.
Similarly the mask for button 3 pressed becomes 00000100.
|#
(let
( ;;;;All pointer buttons currently pressed.
;;;; Drop the keys from the mask.
(Lall-buttons-mask
(ash
(car
(cddddr
(multiple-value-call'list
(xlib:query-pointer
(stumpwm:screen-root(stumpwm:current-screen))))))
-8))
;;;;Mask for matching the chosen button. The bit position
;;;; is the same as the button number.
(Lbutton-mask(ash 1(1- Fbutton))))
;;;Press or release the button: t to press, nil to release.
(xlib/xtest:fake-button-event
stumpwm:*display*
Fbutton
#|
Nothing matched when #'logand returns 0, so button is
currently unpressed and needs to be pressed.
The #'zerop function returns T when the value given it
is 0, which is also the same value needed for pressing
the button. Otherwise, it returns nil, which is also
what is needed for releasing the button.
|#
(zerop(logand Lall-buttons-mask Lbutton-mask)))))
#|#
Buttonboard bindings for pointer activation
and cursor halving.
The optional modifier buttons when binding a button:
Control "C-"
Meta "M-"
Alt "A-"
super "s-" (a.k.a. Command or Windows)
Hyper "H-"
Shift "S-" (often unused, f.e. "A" instead of "S-a")
|#
#|
Bindings are for the numeric pad:
thumb for 1a (button _0_),
forefinger for 1t (button 1),
pinky for 3 ("enter" button),
when on rightside.
7 8 9 -
4 5 6 +
1 2 3 enter => 1t 3
_0_ . enter _1a 3
"0" is "1a" activates primary button.
double-wide. "1t" toggles primary button.
"enter" is "3" is the secondary button.
double-tall.
See also:
* Numeric pad layout for a buttonboard.
|#
;Press and release primary button (button 1).
(stumpwm:define-key stumpwm:*top-map*
(stumpwm:kbd"KP_Insert")"pointer-button-activate.nu 1")
;Toggle primary button (button 1),
; f.e. either press or release for drag'n drop.
(stumpwm:define-key stumpwm:*top-map*
(stumpwm:kbd"KP_End")"pointer-button-toggle.nu 1")
;Press and release secondary button (button 3).
(stumpwm:define-key stumpwm:*top-map*
(stumpwm:kbd"KP_Enter")"pointer-button-activate.nu 3")