ploopyco.c (7420B)
1 /* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> 2 * Copyright 2019 Sunjun Kim 3 * Copyright 2020 Ploopy Corporation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "ploopyco.h" 20 #include "analog.h" 21 #include "opt_encoder.h" 22 23 // for legacy support 24 #if defined(OPT_DEBOUNCE) && !defined(PLOOPY_SCROLL_DEBOUNCE) 25 # define PLOOPY_SCROLL_DEBOUNCE OPT_DEBOUNCE 26 #endif 27 #if defined(SCROLL_BUTT_DEBOUNCE) && !defined(PLOOPY_SCROLL_BUTTON_DEBOUNCE) 28 # define PLOOPY_SCROLL_BUTTON_DEBOUNCE SCROLL_BUTT_DEBOUNCE 29 #endif 30 31 #ifndef PLOOPY_SCROLL_DEBOUNCE 32 # define PLOOPY_SCROLL_DEBOUNCE 5 33 #endif 34 #ifndef PLOOPY_SCROLL_BUTTON_DEBOUNCE 35 # define PLOOPY_SCROLL_BUTTON_DEBOUNCE 100 36 #endif 37 38 #ifndef PLOOPY_DPI_OPTIONS 39 # define PLOOPY_DPI_OPTIONS \ 40 { 600, 900, 1200, 1600, 2400 } 41 # ifndef PLOOPY_DPI_DEFAULT 42 # define PLOOPY_DPI_DEFAULT 1 43 # endif 44 #endif 45 #ifndef PLOOPY_DPI_DEFAULT 46 # define PLOOPY_DPI_DEFAULT 0 47 #endif 48 #ifndef PLOOPY_DRAGSCROLL_DIVISOR_H 49 # define PLOOPY_DRAGSCROLL_DIVISOR_H 8.0 50 #endif 51 #ifndef PLOOPY_DRAGSCROLL_DIVISOR_V 52 # define PLOOPY_DRAGSCROLL_DIVISOR_V 8.0 53 #endif 54 #ifndef ENCODER_BUTTON_ROW 55 # define ENCODER_BUTTON_ROW 0 56 #endif 57 #ifndef ENCODER_BUTTON_COL 58 # define ENCODER_BUTTON_COL 0 59 #endif 60 61 keyboard_config_t keyboard_config; 62 uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS; 63 #define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array) 64 65 // Trackball State 66 bool is_scroll_clicked = false; 67 bool is_drag_scroll = false; 68 float scroll_accumulated_h = 0; 69 float scroll_accumulated_v = 0; 70 71 #ifdef ENCODER_ENABLE 72 uint16_t lastScroll = 0; // Previous confirmed wheel event 73 uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed 74 pin_t encoder_pins_a[1] = ENCODER_A_PINS; 75 pin_t encoder_pins_b[1] = ENCODER_B_PINS; 76 bool debug_encoder = false; 77 78 bool encoder_update_kb(uint8_t index, bool clockwise) { 79 if (!encoder_update_user(index, clockwise)) { 80 return false; 81 } 82 # ifdef MOUSEKEY_ENABLE 83 tap_code(clockwise ? MS_WHLU : MS_WHLD); 84 # else 85 report_mouse_t mouse_report = pointing_device_get_report(); 86 mouse_report.v = clockwise ? 1 : -1; 87 pointing_device_set_report(mouse_report); 88 pointing_device_send(); 89 # endif 90 return true; 91 } 92 93 void encoder_driver_init(void) { 94 for (uint8_t i = 0; i < ARRAY_SIZE(encoder_pins_a); i++) { 95 gpio_set_pin_input(encoder_pins_a[i]); 96 gpio_set_pin_input(encoder_pins_b[i]); 97 } 98 opt_encoder_init(); 99 } 100 101 void encoder_driver_task(void) { 102 uint16_t p1 = analogReadPin(encoder_pins_a[0]); 103 uint16_t p2 = analogReadPin(encoder_pins_b[0]); 104 105 if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2); 106 107 int8_t dir = opt_encoder_handler(p1, p2); 108 // If the mouse wheel was just released, do not scroll. 109 if (timer_elapsed(lastMidClick) < PLOOPY_SCROLL_BUTTON_DEBOUNCE) { 110 return; 111 } 112 113 // Limit the number of scrolls per unit time. 114 if (timer_elapsed(lastScroll) < PLOOPY_SCROLL_DEBOUNCE) { 115 return; 116 } 117 118 // Don't scroll if the middle button is depressed. 119 if (is_scroll_clicked) { 120 # ifndef PLOOPY_IGNORE_SCROLL_CLICK 121 return; 122 # endif 123 } 124 125 if (dir == 0) return; 126 encoder_queue_event(0, dir > 0); 127 lastScroll = timer_read(); 128 } 129 #endif 130 131 void toggle_drag_scroll(void) { 132 is_drag_scroll ^= 1; 133 } 134 135 void cycle_dpi(void) { 136 keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE; 137 eeconfig_update_kb(keyboard_config.raw); 138 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); 139 } 140 141 report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { 142 mouse_report = pointing_device_task_user(mouse_report); 143 if (is_drag_scroll) { 144 scroll_accumulated_h += (float)mouse_report.x / PLOOPY_DRAGSCROLL_DIVISOR_H; 145 scroll_accumulated_v += (float)mouse_report.y / PLOOPY_DRAGSCROLL_DIVISOR_V; 146 147 // Assign integer parts of accumulated scroll values to the mouse report 148 mouse_report.h = (int8_t)scroll_accumulated_h; 149 #ifdef PLOOPY_DRAGSCROLL_INVERT 150 mouse_report.v = -(int8_t)scroll_accumulated_v; 151 #else 152 mouse_report.v = (int8_t)scroll_accumulated_v; 153 #endif 154 155 // Update accumulated scroll values by subtracting the integer parts 156 scroll_accumulated_h -= (int8_t)scroll_accumulated_h; 157 scroll_accumulated_v -= (int8_t)scroll_accumulated_v; 158 159 // Clear the X and Y values of the mouse report 160 mouse_report.x = 0; 161 mouse_report.y = 0; 162 163 mouse_report.x = 0; 164 mouse_report.y = 0; 165 } 166 167 return mouse_report; 168 } 169 170 bool process_record_kb(uint16_t keycode, keyrecord_t* record) { 171 if (debug_mouse) { 172 dprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed); 173 } 174 175 // Update Timer to prevent accidental scrolls 176 #ifdef ENCODER_ENABLE 177 if ((record->event.key.col == ENCODER_BUTTON_COL) && (record->event.key.row == ENCODER_BUTTON_ROW)) { 178 lastMidClick = timer_read(); 179 is_scroll_clicked = record->event.pressed; 180 } 181 #endif 182 183 if (!process_record_user(keycode, record)) { 184 return false; 185 } 186 187 if (keycode == DPI_CONFIG && record->event.pressed) { 188 cycle_dpi(); 189 } 190 191 if (keycode == DRAG_SCROLL) { 192 #ifdef PLOOPY_DRAGSCROLL_MOMENTARY 193 is_drag_scroll = record->event.pressed; 194 #else 195 if (record->event.pressed) { 196 toggle_drag_scroll(); 197 } 198 #endif 199 } 200 201 return true; 202 } 203 204 // Hardware Setup 205 void keyboard_pre_init_kb(void) { 206 // debug_enable = true; 207 // debug_matrix = true; 208 // debug_mouse = true; 209 // debug_encoder = true; 210 211 /* Ground all output pins connected to ground. This provides additional 212 * pathways to ground. If you're messing with this, know this: driving ANY 213 * of these pins high will cause a short. On the MCU. Ka-blooey. 214 */ 215 #ifdef UNUSABLE_PINS 216 const pin_t unused_pins[] = UNUSABLE_PINS; 217 218 for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) { 219 gpio_set_pin_output_push_pull(unused_pins[i]); 220 gpio_write_pin_low(unused_pins[i]); 221 } 222 #endif 223 224 // This is the debug LED. 225 #if defined(DEBUG_LED_PIN) 226 gpio_set_pin_output_push_pull(DEBUG_LED_PIN); 227 gpio_write_pin(DEBUG_LED_PIN, debug_enable); 228 #endif 229 230 keyboard_pre_init_user(); 231 } 232 233 void pointing_device_init_kb(void) { 234 keyboard_config.raw = eeconfig_read_kb(); 235 if (keyboard_config.dpi_config > DPI_OPTION_SIZE) { 236 eeconfig_init_kb(); 237 } 238 pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); 239 } 240 241 void eeconfig_init_kb(void) { 242 keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; 243 eeconfig_update_kb(keyboard_config.raw); 244 eeconfig_init_user(); 245 }