wheelmacs.cpp (5615B)
1 #include <cstdint> 2 #include <stdint.h> 3 #include <thread> 4 #include <memory> 5 #include <vector> 6 #include <cstdio> 7 #include <cerrno> 8 #include <atomic> 9 #include <fcntl.h> 10 #include <unistd.h> 11 #include <iostream> 12 #include <sys/socket.h> 13 #include <netinet/in.h> 14 #include <string.h> 15 #include <sys/types.h> 16 #include <arpa/inet.h> 17 #include <mutex> 18 19 #include "linux/joystick.h" 20 #include "emacs-module.h" 21 22 extern "C" { 23 #include "xdo.h" 24 #include "wheelmesg.h" 25 } 26 27 #define VERSION 0.1 28 int plugin_is_GPL_compatible; 29 30 #define S(s) (env->intern(env, s)) 31 32 // Set the function cell of the symbol named NAME to SFUN using the 'fset' function. 33 static void bind_function (emacs_env *env, const char *name, emacs_value Sfun) { 34 emacs_value Qfset = env->intern (env, "fset"); 35 emacs_value Qsym = env->intern (env, name); 36 emacs_value args[] = { Qsym, Sfun }; 37 env->funcall (env, Qfset, 2, args); 38 } 39 40 #define DEFUN(lsym, csym, amin, amax, doc, data) \ 41 bind_function (env, lsym, env->make_function (env, amin, amax, csym, doc, data)) 42 43 static void provide (emacs_env *env, const char *feature) { 44 emacs_value Qfeat = env->intern (env, feature); 45 emacs_value Qprovide = env->intern (env, "provide"); 46 emacs_value args[] = { Qfeat }; 47 48 env->funcall (env, Qprovide, 1, args); 49 } 50 51 std::shared_ptr<std::vector<bool>> buttons; 52 std::shared_ptr<std::vector<int16_t>> axes; 53 std::thread worker; 54 std::atomic_bool stop_worker; 55 std::mutex cmd_mutex; 56 struct wheel_cmd cmd; 57 58 void grab_values() { 59 xdo_t* x = xdo_new(NULL); 60 int fd = open("/dev/input/js0", O_RDONLY | O_NONBLOCK); 61 62 int s = socket(AF_INET, SOCK_DGRAM, 0); 63 struct sockaddr_in addr; 64 memset((char *)&addr, 0, sizeof(addr)); 65 addr.sin_family = AF_INET; // Specify address family. 66 addr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY just 0.0.0.0, machine IP address 67 addr.sin_port = htons(8070); // Specify port. 68 69 connect(s, (struct sockaddr *)&addr, sizeof(addr)); 70 71 while (true) { 72 struct js_event e; 73 int r = read(fd, &e, sizeof(e)); 74 if (e.type & JS_EVENT_BUTTON) { 75 (*buttons)[e.number] = e.value ? true : false; 76 char key[4] = {0}; 77 sprintf(key, "F%d", e.number+12); 78 if (e.value) xdo_send_keysequence_window(x, CURRENTWINDOW, key, 0); 79 } else if (e.type & JS_EVENT_AXIS) { 80 (*axes)[e.number] = e.value; 81 } 82 if (cmd.type != NONE) { 83 sendto(s, (void*)&cmd, sizeof(struct wheel_cmd), 0, NULL, sizeof(addr)); 84 cmd.type = NONE; 85 cmd_mutex.unlock(); 86 } 87 if (stop_worker) return; 88 } 89 } 90 91 static emacs_value wheel_init (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 92 std::vector<bool> tmp_buttons(12); 93 std::vector<int16_t> tmp_axes(5); 94 std::fill(tmp_buttons.begin(), tmp_buttons.end(), false); 95 std::fill(tmp_axes.begin(), tmp_axes.end(), 0); 96 buttons = std::make_unique<std::vector<bool>>(tmp_buttons); 97 axes = std::make_unique<std::vector<int16_t>>(tmp_axes); 98 99 stop_worker = false; 100 worker = std::thread(grab_values); 101 return S("nil"); 102 } 103 104 static emacs_value wheel_stop (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 105 stop_worker = true; 106 worker.join(); 107 return S("nil"); 108 } 109 110 static emacs_value wheel_set_autocenter (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 111 bool val = env->is_not_nil(env, args[0]); 112 // cmd_mutex.lock(); 113 cmd = { 114 .type = AUTOCENTER, 115 .value = {.autocenter = val} 116 }; 117 // cmd_mutex.unlock(); 118 return S("nil"); 119 } 120 121 static emacs_value wheel_set_range (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 122 int val = env->extract_integer(env, args[0]); 123 if (val < 270 || val > 1080) return S("nil"); 124 cmd = { 125 .type = RANGE, 126 .value = {.range = val} 127 }; 128 return S("nil"); 129 } 130 131 static emacs_value wheel_set_gain (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 132 int val = env->extract_integer(env, args[0]); 133 if (val < 0 || val > 100) return S("nil"); 134 cmd = { 135 .type = GAIN, 136 .value = {.gain = val} 137 }; 138 return S("nil"); 139 } 140 141 static emacs_value wheel_set_autocenter_force (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 142 int val = env->extract_integer(env, args[0]); 143 if (val < 0 || val > 100) return S("nil"); 144 cmd = { 145 .type = AUTOCENTER_FORCE, 146 .value = {.autocenter_force = val} 147 }; 148 return S("nil"); 149 } 150 151 static emacs_value wheel_button (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 152 auto index = env->extract_integer(env, args[0]); 153 if (index >= (*buttons).size() || stop_worker) return S("nil"); 154 bool down = (*buttons)[index]; 155 return down ? S("t") : S("nil"); 156 } 157 158 static emacs_value wheel_axis (emacs_env *env, ptrdiff_t nargs, emacs_value* args, void* data) noexcept { 159 auto index = env->extract_integer(env, args[0]); 160 if (index >= (*axes).size() || stop_worker) return S("nil"); 161 int16_t val = (*axes)[index]; 162 return env->make_integer(env, val); 163 } 164 165 extern int emacs_module_init (struct emacs_runtime *ert) noexcept { 166 emacs_env *env = ert->get_environment (ert); 167 DEFUN("wheel-init", wheel_init, 0, 0, "Set up whe.el worker thread", NULL); 168 DEFUN("wheel-stop", wheel_stop, 0, 0, "Stop whe.el worker thread", NULL); 169 DEFUN("wheel-button", wheel_button, 1, 1, "Check if button is pressed.", NULL); 170 DEFUN("wheel-set-autocenter", wheel_set_autocenter, 1, 1, "Enable/disable autocentering.", NULL); 171 DEFUN("wheel-set-autocenter-force", wheel_set_autocenter_force, 1, 1, "", NULL); 172 DEFUN("wheel-set-range", wheel_set_range, 1, 1, "", NULL); 173 DEFUN("wheel-set-gain", wheel_set_gain, 1, 1, "", NULL); 174 DEFUN("wheel-axis", wheel_axis, 1, 1, "Get axis value.", NULL); 175 provide(env, "wheel"); 176 return 0; 177 }