commit 99a09a6927fd0030a70f8b5963bba985c68bbca6
Author: quantumish <freifeld.david@gmail.com>
Date: Sun, 26 Feb 2023 05:13:32 +0000
Initial commit
Diffstat:
5 files changed, 160 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,4 @@
+build:
+ g++ -fPIC -c wheelmacs.cpp -std=c++17
+ g++ -shared -o wheel.so wheelmacs.o xdo.o /usr/lib/x86_64-linux-gnu/libXtst.a
+
diff --git a/test.el b/test.el
@@ -0,0 +1,16 @@
+(add-to-list 'load-path "~/projects/wheelmacs/")
+(require 'wheel)
+;; (load-file "~/projects/wheelmacs/whe.el")
+(wheel-init)
+;; (wheel-def "C-x g"
+;; :starboard hydra-go-to-file/body
+;; :port magit-status
+;; :none vterm)
+
+
+;; (defun test () (interactive)
+;; (while t
+;; (let ((diff (wheel-axis 0)))
+;; (cond ((> diff 0) (parrot-rotate-next-word-at-point))
+;; ((< diff 0) (parrot-rotate-prev-word-at-point)))
+;; )))
diff --git a/todo.org b/todo.org
@@ -0,0 +1,11 @@
+* todos
+- [ ] settings before worker init
+- [X] bind wheel keys to unused emacs-recognized keys
+ - [ ] dynamically choose unused keys
+- [ ] enabling autocenter
+- [ ] changing range
+- [ ] ffb settings
+- [ ] send wheel shifts as keypresses
+ - [ ] emulated (emacs)
+ - [ ] emulated (c++/X11)
+
diff --git a/whe.el b/whe.el
@@ -0,0 +1,14 @@
+(defun wheel-starboard? ()
+ "Are we headed starboard?"
+ (> (wheel-axis 0) 0))
+
+(defun wheel-port? ()
+ "Are we headed port?"
+ (< (wheel-axis 0) 0))
+
+(cl-defmacro wheel-def (keyb &key starboard port none)
+ `(general-def
+ ,keyb (lambda () (interactive)
+ (cond ((wheel-starboard?) (,starboard))
+ ((wheel-port?) (,port))
+ (t (,none))))))
diff --git a/wheelmacs.cpp b/wheelmacs.cpp
@@ -0,0 +1,115 @@
+#include <cstdint>
+#include <thread>
+#include <memory>
+#include <vector>
+#include <cstdio>
+#include <cerrno>
+#include <atomic>
+#include <fcntl.h>
+#include <unistd.h>
+#include <iostream>
+
+#include "linux/joystick.h"
+#include "emacs-module.h"
+
+extern "C" {
+ #include "xdo.h"
+}
+
+#define VERSION 0.1
+int plugin_is_GPL_compatible;
+
+#define S(s) (env->intern(env, s))
+
+static void bind_function (emacs_env *env, const char *name, emacs_value Sfun) {
+ /* Set the function cell of the symbol named NAME to SFUN using
+ the 'fset' function. */
+
+ /* Convert the strings to symbols by interning them */
+ emacs_value Qfset = env->intern (env, "fset");
+ emacs_value Qsym = env->intern (env, name);
+
+ /* Prepare the arguments array */
+ emacs_value args[] = { Qsym, Sfun };
+
+ /* Make the call (2 == nb of arguments) */
+ env->funcall (env, Qfset, 2, args);
+}
+
+#define DEFUN(lsym, csym, amin, amax, doc, data) \
+ bind_function (env, lsym, env->make_function (env, amin, amax, csym, doc, data))
+
+static void provide (emacs_env *env, const char *feature) {
+ emacs_value Qfeat = env->intern (env, feature);
+ emacs_value Qprovide = env->intern (env, "provide");
+ emacs_value args[] = { Qfeat };
+
+ env->funcall (env, Qprovide, 1, args);
+}
+
+
+std::shared_ptr<std::vector<bool>> buttons;
+std::shared_ptr<std::vector<int16_t>> axes;
+std::thread worker;
+std::atomic_bool stop_worker;
+
+void grab_values() {
+ xdo_t* x = xdo_new(NULL);
+ int fd = open("/dev/input/js0", O_RDONLY | O_NONBLOCK);
+ while (true) {
+ struct js_event e;
+ int r = read(fd, &e, sizeof(e));
+ if (e.type & JS_EVENT_BUTTON) {
+ (*buttons)[e.number] = e.value ? true : false;
+ char key[4] = {0};
+ sprintf(key, "F%d", e.number+12);
+ if (e.value) xdo_send_keysequence_window(x, CURRENTWINDOW, key, 0);
+ } else if (e.type & JS_EVENT_AXIS) {
+ (*axes)[e.number] = e.value;
+ }
+ if (stop_worker) return;
+ }
+}
+
+static emacs_value wheel_init (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept {
+ std::vector<bool> tmp_buttons =
+ {{false,false,false,false,false,false,false,false,false,false,false,false}};
+ std::vector<int16_t> tmp_axes = {{0,0,0,0,0}};
+
+ buttons = std::make_unique<std::vector<bool>>(tmp_buttons);
+ axes = std::make_unique<std::vector<int16_t>>(tmp_axes);
+
+ stop_worker = false;
+ worker = std::thread(grab_values);
+ return S("nil");
+}
+
+static emacs_value wheel_stop (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept {
+ stop_worker = true;
+ worker.join();
+ return S("nil");
+}
+
+static emacs_value wheel_button (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept {
+ auto index = env->extract_integer(env, args[0]);
+ if (index >= (*buttons).size() || stop_worker) return S("nil");
+ bool down = (*buttons)[index];
+ return down ? S("t") : S("nil");
+}
+
+static emacs_value wheel_axis (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept {
+ auto index = env->extract_integer(env, args[0]);
+ if (index >= (*axes).size() || stop_worker) return S("nil");
+ int16_t val = (*axes)[index];
+ return env->make_integer(env, val);
+}
+
+extern int emacs_module_init (struct emacs_runtime *ert) noexcept {
+ emacs_env *env = ert->get_environment (ert);
+ DEFUN("wheel-init", wheel_init, 0, 0, "Set up whe.el worker thread", NULL);
+ DEFUN("wheel-stop", wheel_stop, 0, 0, "Stop whe.el worker thread", NULL);
+ DEFUN("wheel-button", wheel_button, 1, 1, "Check if button is pressed.", NULL);
+ DEFUN("wheel-axis", wheel_axis, 1, 1, "Get axis value.", NULL);
+ provide(env, "wheel");
+ return 0;
+}