From e18bbad24d396c40f742d36606e38d467855f3d5 Mon Sep 17 00:00:00 2001 From: Eric Ihli Date: Wed, 25 Aug 2021 13:25:39 -0500 Subject: [PATCH] Add command to orient Wacom tablet to StumpWM frame Adds a StumpWM command that detects orientation and dimensions of the current frame and runs the appropriate `xsetwacom` commands to map the Wacom tablet input to the frame. --- util/wacom/README.org | 31 ++++++++++++++ util/wacom/package.lisp | 4 ++ util/wacom/wacom.asd | 11 +++++ util/wacom/wacom.lisp | 94 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 util/wacom/README.org create mode 100644 util/wacom/package.lisp create mode 100644 util/wacom/wacom.asd create mode 100644 util/wacom/wacom.lisp diff --git a/util/wacom/README.org b/util/wacom/README.org new file mode 100644 index 0000000..63327a5 --- /dev/null +++ b/util/wacom/README.org @@ -0,0 +1,31 @@ +#+TITLE: Wacom StumpWM + +* Requirements + +- [[https://linux.die.net/man/1/xsetwacom][xsetwacom]] +- [[https://linuxwacom.github.io/][Linux Wacom Project]] + +* Installation + +Like any other module: Add ~(load-module "wacom")~ somewhere in your ~.stumpwmrc~. + +* Usage + +Focus the frame you want to use your wacom tablet. Run ~map-wacom-to-current-frame~. + +One thing that can't be detected is the physical orientation of your device. Even if we could detect landscape/portrait mode, we can't know which way is right-side-up. + +** Parameters + +There are a couple of parameters defined in ~wacom.lisp~ that you can edit to match the layout of your +tablet on your desk. + +#+begin_src lisp +(defparameter *portrait-rotate* "ccw" + "If you notice the directions are the reverse of what you desirte when your + frame is in portrait orientation, then change this parameter to 'cw'.") + +(defparameter *landscape-rotate* "half" + "If you notice directions are the reverse of what you desire when your + frame is in landscape orientation, then change this parameter to 'none'.") +#+end_src diff --git a/util/wacom/package.lisp b/util/wacom/package.lisp new file mode 100644 index 0000000..75bc474 --- /dev/null +++ b/util/wacom/package.lisp @@ -0,0 +1,4 @@ +;;;; package.lisp + +(defpackage #:wacom + (:use #:cl #:stumpwm #:cl-ppcre)) diff --git a/util/wacom/wacom.asd b/util/wacom/wacom.asd new file mode 100644 index 0000000..228b5cb --- /dev/null +++ b/util/wacom/wacom.asd @@ -0,0 +1,11 @@ +;;;; wacom.asd + +(asdf:defsystem #:wacom + :description "Map StumpWM frames to Wacom tablets using `xsetwacom`." + :author "Eric Ihli " + :license "GPLv3" + :version "1.0.0" + :serial t + :depends-on (#:stumpwm #:cl-ppcre) + :components ((:file "package") + (:file "wacom"))) diff --git a/util/wacom/wacom.lisp b/util/wacom/wacom.lisp new file mode 100644 index 0000000..04a39a3 --- /dev/null +++ b/util/wacom/wacom.lisp @@ -0,0 +1,94 @@ +;;;; wacom.lisp + +(in-package #:wacom) + +(defparameter *portrait-rotate* "ccw" + "If you notice the directions are the reverse of what you desirte when your + frame is in portrait orientation, then change this parameter to 'cw'.") + +(defparameter *landscape-rotate* "half" + "If you notice directions are the reverse of what you desire when your + frame is in landscape orientation, then change this parameter to 'none'.") + +(defun current-frame () + (stumpwm::tile-group-current-frame (stumpwm:current-group))) + +(defun tablet-id () + "List devices with `xsetwacom --list devices` results in something like + the following output. + + Wacom One by Wacom S Pen stylus id: 13 type: STYLUS + Wacom One by Wacom S Pen eraser id: 14 type: ERASER + + I'm not sure how type is determined. Messing around in my + local environment I found that the type that I need to + configure is the `STYLUS`. + + So this function returns the ID of the STYLUS device." + (let ((shell-output (run-shell-command "xsetwacom --list devices" t))) + (multiple-value-bind (match groups) (cl-ppcre:scan-to-strings "id: (\\d+).*STYLUS" shell-output) + (declare (ignore match)) + (aref groups 0)))) + +(defun reset-area! () + "Resets tablet area to system default." + (run-shell-command (format nil "xsetwacom set ~A ResetArea" (tablet-id)) t)) + +(defun tablet-area () + "Returns (top-offset left-offset width height)." + (mapcar + #'parse-integer + (cl-ppcre:split + "\\s+" + (run-shell-command (format nil "xsetwacom get ~A Area" (tablet-id)) t)))) + +(defun current-frame-dimensions () + (let* ((curframe (current-frame)) + (top (stumpwm:frame-y curframe)) + (left (stumpwm:frame-x curframe)) + (width (stumpwm:frame-width curframe)) + (height (stumpwm:frame-height curframe))) + (list top left width height))) + +(defun orientation () + "Returns either :portrait or :landscape. based on dimensions of current frame." + (destructuring-bind (top left width height) + (current-frame-dimensions) + (declare (ignore top left)) ;; Only height used to get sync ratios + (if (> height width) + :portrait + :landscape))) + +(defun reset-rotate! () + (rotate! "none")) + +(defun rotate! (orientation) + (run-shell-command (format nil "xsetwacom set ~A rotate ~A" (tablet-id) orientation) t)) + +(defun -wacom-cur-frame () + (destructuring-bind (top left width height) + (current-frame-dimensions) + (let ((ratio (/ width height))) + (reset-area!) + (destructuring-bind + (tablet-top tablet-left tablet-width tablet-height) + (tablet-area) + (declare (ignore tablet-left tablet-top)) ;; Only height used to get sync ratios + (let* ((id (tablet-id)) + (ideal-width (* tablet-height ratio)) + (discount-ratio (min 1 (/ tablet-width ideal-width))) + (target-width (min tablet-width ideal-width)) + (target-height (* discount-ratio tablet-height)) + (stylus-area (format nil "xsetwacom set ~A Area 0 0 ~A ~A" + id (round target-width) target-height)) + ;; Aspect ratio of 800x900 will mean we need to adjust area of Stylus also. + (map-to-output (format nil "xsetwacom set ~A MapToOutput ~Ax~A+~A+~A" id width height left top))) + (run-shell-command stylus-area t) + (run-shell-command map-to-output t) + (rotate! + (if (eq (orientation) :portrait) + *portrait-rotate* + *landscape-rotate*))))))) + +(defcommand map-wacom-to-current-frame () () + (-wacom-cur-frame))