#|
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")