logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

pimoroni_trackball.c (5986B)


  1. /* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include QMK_KEYBOARD_H
  17. #include "pimoroni_trackball.h"
  18. #include "i2c_master.h"
  19. #include "action.h"
  20. #include "timer.h"
  21. #include "print.h"
  22. static uint8_t scrolling = 0;
  23. static int16_t x_offset = 0;
  24. static int16_t y_offset = 0;
  25. static int16_t h_offset = 0;
  26. static int16_t v_offset = 0;
  27. static float precisionSpeed = 1;
  28. static uint16_t i2c_timeout_timer;
  29. #ifndef I2C_TIMEOUT
  30. # define I2C_TIMEOUT 100
  31. #endif
  32. #ifndef I2C_WAITCHECK
  33. # define I2C_WAITCHECK 1000
  34. #endif
  35. #ifndef MOUSE_DEBOUNCE
  36. # define MOUSE_DEBOUNCE 5
  37. #endif
  38. void trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
  39. uint8_t data[] = {0x00, red, green, blue, white};
  40. i2c_transmit(TRACKBALL_ADDRESS, data, sizeof(data), I2C_TIMEOUT);
  41. }
  42. int16_t mouse_offset(uint8_t positive, uint8_t negative, int16_t scale) {
  43. int16_t offset = (int16_t)positive - (int16_t)negative;
  44. int16_t magnitude = (int16_t)(scale * offset * offset * precisionSpeed);
  45. return offset < 0 ? -magnitude : magnitude;
  46. }
  47. void update_member(int8_t* member, int16_t* offset) {
  48. if (*offset > 127) {
  49. *member = 127;
  50. *offset -= 127;
  51. } else if (*offset < -127) {
  52. *member = -127;
  53. *offset += 127;
  54. } else {
  55. *member = *offset;
  56. *offset = 0;
  57. }
  58. }
  59. __attribute__((weak)) void trackball_check_click(bool pressed, report_mouse_t* mouse) {
  60. if (pressed) {
  61. mouse->buttons |= MOUSE_BTN1;
  62. } else {
  63. mouse->buttons &= ~MOUSE_BTN1;
  64. }
  65. }
  66. bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
  67. if (true) {
  68. xprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
  69. }
  70. if (!process_record_user(keycode, record)) { return false; }
  71. /* If Mousekeys is disabled, then use handle the mouse button
  72. * keycodes. This makes things simpler, and allows usage of
  73. * the keycodes in a consistent manner. But only do this if
  74. * Mousekeys is not enable, so it's not handled twice.
  75. */
  76. #ifndef MOUSEKEY_ENABLE
  77. if (IS_MOUSEKEY_BUTTON(keycode)) {
  78. report_mouse_t currentReport = pointing_device_get_report();
  79. if (record->event.pressed) {
  80. currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
  81. } else {
  82. currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
  83. }
  84. pointing_device_set_report(currentReport);
  85. pointing_device_send();
  86. }
  87. #endif
  88. return true;
  89. }
  90. void trackball_register_button(bool pressed, enum mouse_buttons button) {
  91. report_mouse_t currentReport = pointing_device_get_report();
  92. if (pressed) {
  93. currentReport.buttons |= button;
  94. } else {
  95. currentReport.buttons &= ~button;
  96. }
  97. pointing_device_set_report(currentReport);
  98. }
  99. float trackball_get_precision(void) { return precisionSpeed; }
  100. void trackball_set_precision(float precision) { precisionSpeed = precision; }
  101. bool trackball_is_scrolling(void) { return scrolling; }
  102. void trackball_set_scrolling(bool scroll) { scrolling = scroll; }
  103. __attribute__((weak)) void pointing_device_init(void) { trackball_set_rgbw(0x80, 0x00, 0x00, 0x00); }
  104. bool pointing_device_task(void) {
  105. static bool debounce;
  106. static uint16_t debounce_timer;
  107. uint8_t state[5] = {};
  108. if (timer_elapsed(i2c_timeout_timer) > I2C_WAITCHECK) {
  109. if (i2c_read_register(TRACKBALL_ADDRESS, 0x04, state, 5, I2C_TIMEOUT) == I2C_STATUS_SUCCESS) {
  110. if (!state[4] && !debounce) {
  111. if (scrolling) {
  112. #ifdef PIMORONI_TRACKBALL_INVERT_X
  113. h_offset += mouse_offset(state[2], state[3], 1);
  114. #else
  115. h_offset -= mouse_offset(state[2], state[3], 1);
  116. #endif
  117. #ifdef PIMORONI_TRACKBALL_INVERT_Y
  118. v_offset += mouse_offset(state[1], state[0], 1);
  119. #else
  120. v_offset -= mouse_offset(state[1], state[0], 1);
  121. #endif
  122. } else {
  123. #ifdef PIMORONI_TRACKBALL_INVERT_X
  124. x_offset -= mouse_offset(state[2], state[3], 5);
  125. #else
  126. x_offset += mouse_offset(state[2], state[3], 5);
  127. #endif
  128. #ifdef PIMORONI_TRACKBALL_INVERT_Y
  129. y_offset -= mouse_offset(state[1], state[0], 5);
  130. #else
  131. y_offset += mouse_offset(state[1], state[0], 5);
  132. #endif
  133. }
  134. } else {
  135. if (state[4]) {
  136. debounce = true;
  137. debounce_timer = timer_read();
  138. }
  139. }
  140. } else {
  141. i2c_timeout_timer = timer_read();
  142. }
  143. }
  144. if (timer_elapsed(debounce_timer) > MOUSE_DEBOUNCE) debounce = false;
  145. report_mouse_t mouse = pointing_device_get_report();
  146. // trackball_check_click(state[4] & (1 << 7), &mouse);
  147. #ifndef PIMORONI_TRACKBALL_ROTATE
  148. update_member(&mouse.x, &x_offset);
  149. update_member(&mouse.y, &y_offset);
  150. update_member(&mouse.h, &h_offset);
  151. update_member(&mouse.v, &v_offset);
  152. #else
  153. update_member(&mouse.x, &y_offset);
  154. update_member(&mouse.y, &x_offset);
  155. update_member(&mouse.h, &v_offset);
  156. update_member(&mouse.v, &h_offset);
  157. #endif
  158. pointing_device_set_report(mouse);
  159. return pointing_device_send();
  160. }