summaryrefslogtreecommitdiff
path: root/keyboards/kyria/keymaps/gotham/thumbstick.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/kyria/keymaps/gotham/thumbstick.c')
-rw-r--r--keyboards/kyria/keymaps/gotham/thumbstick.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/keyboards/kyria/keymaps/gotham/thumbstick.c b/keyboards/kyria/keymaps/gotham/thumbstick.c
new file mode 100644
index 0000000000..ec08fb07d4
--- /dev/null
+++ b/keyboards/kyria/keymaps/gotham/thumbstick.c
@@ -0,0 +1,195 @@
+#include "thumbstick.h"
+
+void thumbstick_init(void) {
+ thumbstickTimer = 0;
+ thumbstickScrollTimer = 0;
+
+ thumbstick_state.config.mode = THUMBSTICK_MODE_MOUSE;
+ thumbstick_state.config.deadZone = THUMBSTICK_DEAD_ZONE;
+ thumbstick_state.config.fineZone = THUMBSTICK_FINE_ZONE;
+ thumbstick_state.config.speed = THUMBSTICK_SPEED;
+ thumbstick_state.config.fineSpeed = THUMBSTICK_FINE_SPEED;
+ thumbstick_state.config.axisSeparation = THUMBSTICK_AXIS_SEPARATION;
+ thumbstick_state.config.eightAxis = THUMBSTICK_EIGHT_AXIS;
+
+#if defined THUMBSTICK_DEBUG
+ rawX = 0;
+ rawY = 0;
+ distX = 0;
+ distY = 0;
+ thumbstickLogTimer = 0;
+#endif
+}
+
+// Axis-level wrapper to read raw value, do logging and calculate speed
+int16_t thumbstick_get_component(uint8_t pin) {
+ uint16_t analogValue = analogReadPin(pin);
+ // Compute direction
+ bool directionIsPositive = (analogValue > THUMBSTICK_RANGE_CENTER);
+ // Compute distance from the center
+ uint16_t distance = directionIsPositive ? (analogValue - THUMBSTICK_RANGE_CENTER) : (THUMBSTICK_RANGE_CENTER - analogValue);
+#if defined THUMBSTICK_DEBUG
+ if (pin == THUMBSTICK_PIN_X) {
+ rawX = analogValue;
+ distX = distance;
+ } else {
+ rawY = analogValue;
+ distY = distance;
+ }
+#endif
+ // Compute component (range of [0 to 1023])
+ return directionIsPositive ? distance : -(int16_t)distance;
+}
+
+void thumbstick_mode_set(thumbstick_mode_t mode) { thumbstick_state.config.mode = mode; }
+
+thumbstick_mode_t thumbstick_mode_get(void) { return thumbstick_state.config.mode; }
+
+void thumbstick_mode_cycle(bool reverse) {
+ thumbstick_mode_t mode = thumbstick_mode_get();
+ if (reverse) {
+ mode = (mode == 0) ? (_THUMBSTICK_MODE_LAST - 1) : (mode - 1);
+ } else {
+ mode = (mode == (_THUMBSTICK_MODE_LAST - 1)) ? 0 : (mode + 1);
+ }
+ thumbstick_mode_set(mode);
+}
+
+// Get mouse speed
+int16_t thumbstick_get_mouse_speed(int16_t component) {
+ int16_t maxSpeed;
+ uint16_t distance = abs(component);
+ if (distance > THUMBSTICK_FINE_ZONE) {
+ maxSpeed = THUMBSTICK_SPEED;
+ } else if (distance > THUMBSTICK_DEAD_ZONE) {
+ maxSpeed = THUMBSTICK_FINE_SPEED;
+ } else {
+ return 0;
+ }
+ return (float)maxSpeed * component / THUMBSTICK_RANGE_CENTER;
+}
+
+// Fix direction within one of 8 axes (or 4 if 8-axis is disabled)
+thumbstick_direction_t thumbstick_get_discretized_direction(thumbstick_vector_t vector, float axisSeparation, bool eightAxis) {
+ thumbstick_direction_t direction;
+ uint16_t absX = abs(vector.x);
+ uint16_t absY = abs(vector.y);
+ uint16_t maxComponent = (absX > absY) ? absX : absY;
+ bool insideDeadZone = (maxComponent <= THUMBSTICK_DEAD_ZONE);
+ bool outsideDiagonalZone = ((abs(absX - absY) / (float)maxComponent) >= axisSeparation);
+ if (insideDeadZone) {
+ direction.up = direction.down = direction.left = direction.right = false;
+ } else {
+ direction.up = (vector.y < 0);
+ direction.down = (vector.y > 0);
+ direction.left = (vector.x < 0);
+ direction.right = (vector.x > 0);
+ // Let only the dominant direction remain under the right conditions
+ if (outsideDiagonalZone || !eightAxis) {
+ if (absX > absY) {
+ direction.up = direction.down = false;
+ } else {
+ direction.left = direction.right = false;
+ }
+ }
+ }
+ return direction;
+}
+
+thumbstick_direction_t scrollDirection; // Declaring global to save stack space
+void thumbstick_process(void) {
+ if (timer_elapsed(thumbstickTimer) > THUMBSTICK_TIMEOUT) {
+ thumbstickTimer = timer_read();
+#ifndef THUMBSTICK_FLIP_X
+ thumbstick_state.vector.x = thumbstick_get_component(THUMBSTICK_PIN_X);
+#else
+ thumbstick_state.vector.x = -thumbstick_get_component(THUMBSTICK_PIN_X);
+#endif
+#ifndef THUMBSTICK_FLIP_Y
+ thumbstick_state.vector.y = thumbstick_get_component(THUMBSTICK_PIN_Y);
+#else
+ thumbstick_state.vector.y = -thumbstick_get_component(THUMBSTICK_PIN_Y);
+#endif
+ switch (thumbstick_state.config.mode) {
+ case THUMBSTICK_MODE_MOUSE:
+ thumbstick_state.report.x = thumbstick_get_mouse_speed(thumbstick_state.vector.x);
+ thumbstick_state.report.y = thumbstick_get_mouse_speed(thumbstick_state.vector.y);
+ break;
+ case THUMBSTICK_MODE_ARROWS:
+ thumbstick_state.direction = thumbstick_get_discretized_direction(thumbstick_state.vector, thumbstick_state.config.axisSeparation, thumbstick_state.config.eightAxis);
+ break;
+ case THUMBSTICK_MODE_SCROLL:
+ if (timer_elapsed(thumbstickScrollTimer) > THUMBSTICK_SCROLL_TIMEOUT) {
+ thumbstickScrollTimer = timer_read();
+ scrollDirection = thumbstick_get_discretized_direction(thumbstick_state.vector, thumbstick_state.config.axisSeparation, false);
+ thumbstick_state.report.v = (scrollDirection.up || scrollDirection.down) ? (scrollDirection.up ? THUMBSTICK_SCROLL_SPEED : -THUMBSTICK_SCROLL_SPEED) : 0;
+ thumbstick_state.report.h = (scrollDirection.left || scrollDirection.right) ? (scrollDirection.left ? -THUMBSTICK_SCROLL_SPEED : THUMBSTICK_SCROLL_SPEED) : 0;
+ } else {
+ thumbstick_state.report.v = thumbstick_state.report.h = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void update_keycode_status(uint16_t keycode, bool last, bool current) {
+ if (last != current) {
+ if (current) {
+ register_code16(keycode);
+ } else {
+ unregister_code16(keycode);
+ }
+ }
+}
+
+void pointing_device_init(void) { thumbstick_init(); }
+
+void pointing_device_task(void) {
+ report_mouse_t report = pointing_device_get_report();
+
+ if (!isLeftHand) {
+ thumbstick_process();
+ switch (thumbstick_state.config.mode) {
+ case THUMBSTICK_MODE_MOUSE:
+ report.x = thumbstick_state.report.x;
+ report.y = thumbstick_state.report.y;
+#ifdef THUMBSTICK_DEBUG
+ if (timer_elapsed(thumbstickLogTimer) > 100) {
+ thumbstickLogTimer = timer_read();
+ uprintf("Raw (%d, %d); Dist (%u, %u); Vec (%d, %d);\n", rawX, rawY, distX, distY, thumbstick_state.vector.x, thumbstick_state.vector.y);
+ }
+#endif
+ break;
+ case THUMBSTICK_MODE_ARROWS:
+ update_keycode_status(KC_UP, thumbstick_state.lastDirection.up, thumbstick_state.direction.up);
+ update_keycode_status(KC_DOWN, thumbstick_state.lastDirection.down, thumbstick_state.direction.down);
+ update_keycode_status(KC_LEFT, thumbstick_state.lastDirection.left, thumbstick_state.direction.left);
+ update_keycode_status(KC_RIGHT, thumbstick_state.lastDirection.right, thumbstick_state.direction.right);
+ thumbstick_state.lastDirection = thumbstick_state.direction;
+#ifdef THUMBSTICK_DEBUG
+ if (timer_elapsed(thumbstickLogTimer) > 100) {
+ thumbstickLogTimer = timer_read();
+ uprintf("Up %d; Down %d; Left: %d; Right %d; Vec (%d, %d);\n", direction.up, direction.down, direction.left, direction.right, thumbstick_state.vector.x, thumbstick_state.vector.y);
+ }
+#endif
+ break;
+ case THUMBSTICK_MODE_SCROLL:
+ report.v = thumbstick_state.report.v;
+ report.h = thumbstick_state.report.h;
+#ifdef THUMBSTICK_DEBUG
+ if (timer_elapsed(thumbstickLogTimer) > 100) {
+ thumbstickLogTimer = timer_read();
+ uprintf("Scroll (%d, %d)\n", report.h, report.v);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+ }
+
+ pointing_device_set_report(report);
+ pointing_device_send();
+}