mousekey.c (24753B)
1 /* 2 * Copyright 2011 Jun Wako <wakojun@gmail.com> 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <stdint.h> 19 #include <string.h> 20 #include "keycode.h" 21 #include "host.h" 22 #include "timer.h" 23 #include "print.h" 24 #include "debug.h" 25 #include "mousekey.h" 26 27 static inline int8_t times_inv_sqrt2(int8_t x) { 28 // 181/256 (0.70703125) is used as an approximation for 1/sqrt(2) 29 // because it is close to the exact value which is 0.707106781 30 const int16_t n = x * 181; 31 const uint16_t d = 256; 32 33 // To ensure that the integer result is rounded accurately after 34 // division, check the sign of the numerator: 35 // If negative, subtract half of the denominator before dividing 36 // Otherwise, add half of the denominator before dividing 37 return n < 0 ? (n - d / 2) / d : (n + d / 2) / d; 38 } 39 40 static report_mouse_t mouse_report = {0}; 41 static void mousekey_debug(void); 42 static uint8_t mousekey_accel = 0; 43 static uint8_t mousekey_repeat = 0; 44 static uint8_t mousekey_wheel_repeat = 0; 45 #ifdef MOUSEKEY_INERTIA 46 static uint8_t mousekey_frame = 0; // track whether gesture is inactive, first frame, or repeating 47 static int8_t mousekey_x_dir = 0; // -1 / 0 / 1 = left / neutral / right 48 static int8_t mousekey_y_dir = 0; // -1 / 0 / 0 = up / neutral / down 49 static int8_t mousekey_x_inertia = 0; // current velocity, limit +/- MOUSEKEY_TIME_TO_MAX 50 static int8_t mousekey_y_inertia = 0; // ... 51 #endif 52 #ifdef MK_KINETIC_SPEED 53 static uint16_t mouse_timer = 0; 54 #endif 55 56 #ifndef MK_3_SPEED 57 58 static uint16_t last_timer_c = 0; 59 static uint16_t last_timer_w = 0; 60 61 /* 62 * Mouse keys acceleration algorithm 63 * http://en.wikipedia.org/wiki/Mouse_keys 64 * 65 * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000) 66 */ 67 /* milliseconds between the initial key press and first repeated motion event (0-2550) */ 68 uint8_t mk_delay = MOUSEKEY_DELAY / 10; 69 /* milliseconds between repeated motion events (0-255) */ 70 uint8_t mk_interval = MOUSEKEY_INTERVAL; 71 /* steady speed (in action_delta units) applied each event (0-255) */ 72 uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED; 73 /* number of events (count) accelerating to steady speed (0-255) */ 74 uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX; 75 /* ramp used to reach maximum pointer speed (NOT SUPPORTED) */ 76 // int8_t mk_curve = 0; 77 /* wheel params */ 78 /* milliseconds between the initial key press and first repeated motion event (0-2550) */ 79 uint8_t mk_wheel_delay = MOUSEKEY_WHEEL_DELAY / 10; 80 /* milliseconds between repeated motion events (0-255) */ 81 # ifdef MK_KINETIC_SPEED 82 uint16_t mk_wheel_interval = 1000U / MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; 83 # else 84 uint8_t mk_wheel_interval = MOUSEKEY_WHEEL_INTERVAL; 85 # endif 86 uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; 87 uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; 88 89 # ifndef MK_COMBINED 90 # ifndef MK_KINETIC_SPEED 91 # ifndef MOUSEKEY_INERTIA 92 93 /* Default accelerated mode */ 94 95 static uint8_t move_unit(void) { 96 uint16_t unit; 97 if (mousekey_accel & (1 << 0)) { 98 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 4; 99 } else if (mousekey_accel & (1 << 1)) { 100 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; 101 } else if (mousekey_accel & (1 << 2)) { 102 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed); 103 } else if (mousekey_repeat == 0) { 104 unit = MOUSEKEY_MOVE_DELTA; 105 } else if (mousekey_repeat >= mk_time_to_max) { 106 unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; 107 } else { 108 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; 109 } 110 return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); 111 } 112 113 # else // MOUSEKEY_INERTIA mode 114 115 static int8_t move_unit(uint8_t axis) { 116 int16_t unit; 117 118 // handle X or Y axis 119 int8_t inertia, dir; 120 if (axis) { 121 inertia = mousekey_y_inertia; 122 dir = mousekey_y_dir; 123 } else { 124 inertia = mousekey_x_inertia; 125 dir = mousekey_x_dir; 126 } 127 128 if (mousekey_frame < 2) { // first frame(s): initial keypress moves one pixel 129 mousekey_frame = 1; 130 unit = dir * MOUSEKEY_MOVE_DELTA; 131 } else { // acceleration 132 // linear acceleration (is here for reference, but doesn't feel as good during use) 133 // unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * inertia) / mk_time_to_max; 134 135 // x**2 acceleration (quadratic, more precise for short movements) 136 int16_t percent = (inertia << 8) / mk_time_to_max; 137 percent = ((int32_t)percent * percent) >> 8; 138 if (inertia < 0) percent = -percent; 139 140 // unit = sign(inertia) + (percent of max speed) 141 if (inertia > 0) 142 unit = 1; 143 else if (inertia < 0) 144 unit = -1; 145 else 146 unit = 0; 147 148 unit = unit + ((mk_max_speed * percent) >> 8); 149 } 150 151 if (unit > MOUSEKEY_MOVE_MAX) 152 unit = MOUSEKEY_MOVE_MAX; 153 else if (unit < -MOUSEKEY_MOVE_MAX) 154 unit = -MOUSEKEY_MOVE_MAX; 155 return unit; 156 } 157 158 # endif // end MOUSEKEY_INERTIA mode 159 160 static uint8_t wheel_unit(void) { 161 uint16_t unit; 162 if (mousekey_accel & (1 << 0)) { 163 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 4; 164 } else if (mousekey_accel & (1 << 1)) { 165 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; 166 } else if (mousekey_accel & (1 << 2)) { 167 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed); 168 } else if (mousekey_wheel_repeat == 0) { 169 unit = MOUSEKEY_WHEEL_DELTA; 170 } else if (mousekey_wheel_repeat >= mk_wheel_time_to_max) { 171 unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; 172 } else { 173 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_wheel_repeat) / mk_wheel_time_to_max; 174 } 175 return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); 176 } 177 178 # else /* #ifndef MK_KINETIC_SPEED */ 179 180 /* 181 * Kinetic movement acceleration algorithm 182 * 183 * current speed = I + A * T/50 + A * (T/50)^2 * 1/2 | maximum B 184 * 185 * T: time since the mouse movement started 186 * E: mouse events per second (set through MOUSEKEY_INTERVAL, UHK sends 250, the 187 * pro micro on my Signum 3.0 sends only 125!) 188 * I: initial speed at time 0 189 * A: acceleration 190 * B: base mouse travel speed 191 */ 192 const uint16_t mk_accelerated_speed = MOUSEKEY_ACCELERATED_SPEED; 193 const uint16_t mk_base_speed = MOUSEKEY_BASE_SPEED; 194 const uint16_t mk_decelerated_speed = MOUSEKEY_DECELERATED_SPEED; 195 const uint16_t mk_initial_speed = MOUSEKEY_INITIAL_SPEED; 196 197 static uint8_t move_unit(void) { 198 uint16_t speed = mk_initial_speed; 199 200 if (mousekey_accel & (1 << 0)) { 201 speed = mk_decelerated_speed; 202 } else if (mousekey_accel & (1 << 2)) { 203 speed = mk_accelerated_speed; 204 } else if (mousekey_repeat && mouse_timer) { 205 const uint16_t time_elapsed = timer_elapsed(mouse_timer) / 50; 206 speed = mk_initial_speed + MOUSEKEY_MOVE_DELTA * time_elapsed + (MOUSEKEY_MOVE_DELTA * time_elapsed * time_elapsed) / 2; 207 if (speed > mk_base_speed) { 208 speed = mk_base_speed; 209 } 210 } 211 /* convert speed to USB mouse speed 1 to 127 */ 212 speed = (uint8_t)(speed / (1000U / mk_interval)); 213 214 if (speed > MOUSEKEY_MOVE_MAX) { 215 speed = MOUSEKEY_MOVE_MAX; 216 } else if (speed < 1) { 217 speed = 1; 218 } 219 return speed; 220 } 221 222 static uint8_t wheel_unit(void) { 223 uint16_t speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS; 224 225 if (mousekey_accel & (1 << 0)) { 226 speed = MOUSEKEY_WHEEL_DECELERATED_MOVEMENTS; 227 } else if (mousekey_accel & (1 << 2)) { 228 speed = MOUSEKEY_WHEEL_ACCELERATED_MOVEMENTS; 229 } else if (mousekey_wheel_repeat && mouse_timer) { 230 if (mk_wheel_interval != MOUSEKEY_WHEEL_BASE_MOVEMENTS) { 231 const uint16_t time_elapsed = timer_elapsed(mouse_timer) / 50; 232 speed = MOUSEKEY_WHEEL_INITIAL_MOVEMENTS + 1 * time_elapsed + (1 * time_elapsed * time_elapsed) / 2; 233 } 234 if (speed > MOUSEKEY_WHEEL_BASE_MOVEMENTS) { 235 speed = MOUSEKEY_WHEEL_BASE_MOVEMENTS; 236 } 237 } 238 mk_wheel_interval = 1000U / speed; 239 return 1; 240 } 241 242 # endif /* #ifndef MK_KINETIC_SPEED */ 243 # else /* #ifndef MK_COMBINED */ 244 245 /* Combined mode */ 246 247 static uint8_t move_unit(void) { 248 uint16_t unit; 249 if (mousekey_accel & (1 << 0)) { 250 unit = 1; 251 } else if (mousekey_accel & (1 << 1)) { 252 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed) / 2; 253 } else if (mousekey_accel & (1 << 2)) { 254 unit = MOUSEKEY_MOVE_MAX; 255 } else if (mousekey_repeat == 0) { 256 unit = MOUSEKEY_MOVE_DELTA; 257 } else if (mousekey_repeat >= mk_time_to_max) { 258 unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; 259 } else { 260 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; 261 } 262 return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); 263 } 264 265 static uint8_t wheel_unit(void) { 266 uint16_t unit; 267 if (mousekey_accel & (1 << 0)) { 268 unit = 1; 269 } else if (mousekey_accel & (1 << 1)) { 270 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed) / 2; 271 } else if (mousekey_accel & (1 << 2)) { 272 unit = MOUSEKEY_WHEEL_MAX; 273 } else if (mousekey_repeat == 0) { 274 unit = MOUSEKEY_WHEEL_DELTA; 275 } else if (mousekey_repeat >= mk_wheel_time_to_max) { 276 unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; 277 } else { 278 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max; 279 } 280 return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); 281 } 282 283 # endif /* #ifndef MK_COMBINED */ 284 285 # ifdef MOUSEKEY_INERTIA 286 287 static int8_t calc_inertia(int8_t direction, int8_t velocity) { 288 // simulate acceleration and deceleration 289 290 // deceleration 291 if ((direction > -1) && (velocity < 0)) 292 velocity = (velocity + 1) * (256 - MOUSEKEY_FRICTION) / 256; 293 else if ((direction < 1) && (velocity > 0)) 294 velocity = velocity * (256 - MOUSEKEY_FRICTION) / 256; 295 296 // acceleration 297 if ((direction > 0) && (velocity < mk_time_to_max)) 298 velocity++; 299 else if ((direction < 0) && (velocity > -mk_time_to_max)) 300 velocity--; 301 302 return velocity; 303 } 304 305 # endif 306 307 void mousekey_task(void) { 308 // report cursor and scroll movement independently 309 report_mouse_t tmpmr = mouse_report; 310 311 mouse_report.x = 0; 312 mouse_report.y = 0; 313 mouse_report.v = 0; 314 mouse_report.h = 0; 315 316 # ifdef MOUSEKEY_INERTIA 317 318 // if an animation is in progress and it's time for the next frame 319 if ((mousekey_frame) && timer_elapsed(last_timer_c) > ((mousekey_frame > 1) ? mk_interval : mk_delay * 10)) { 320 mousekey_x_inertia = calc_inertia(mousekey_x_dir, mousekey_x_inertia); 321 mousekey_y_inertia = calc_inertia(mousekey_y_dir, mousekey_y_inertia); 322 323 mouse_report.x = move_unit(0); 324 mouse_report.y = move_unit(1); 325 326 // prevent sticky "drift" 327 if ((!mousekey_x_dir) && (!mousekey_x_inertia)) tmpmr.x = 0; 328 if ((!mousekey_y_dir) && (!mousekey_y_inertia)) tmpmr.y = 0; 329 330 if (mousekey_frame < 2) mousekey_frame++; 331 } 332 333 // reset if not moving and no movement keys are held 334 if ((!mousekey_x_dir) && (!mousekey_y_dir) && (!mousekey_x_inertia) && (!mousekey_y_inertia)) { 335 mousekey_frame = 0; 336 tmpmr.x = 0; 337 tmpmr.y = 0; 338 } 339 340 # else // default acceleration 341 342 if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) { 343 if (mousekey_repeat != UINT8_MAX) mousekey_repeat++; 344 if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1); 345 if (tmpmr.y != 0) mouse_report.y = move_unit() * ((tmpmr.y > 0) ? 1 : -1); 346 347 /* diagonal move [1/sqrt(2)] */ 348 if (mouse_report.x && mouse_report.y) { 349 mouse_report.x = times_inv_sqrt2(mouse_report.x); 350 if (mouse_report.x == 0) { 351 mouse_report.x = 1; 352 } 353 mouse_report.y = times_inv_sqrt2(mouse_report.y); 354 if (mouse_report.y == 0) { 355 mouse_report.y = 1; 356 } 357 } 358 } 359 360 # endif // MOUSEKEY_INERTIA or not 361 362 if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) { 363 if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++; 364 if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1); 365 if (tmpmr.h != 0) mouse_report.h = wheel_unit() * ((tmpmr.h > 0) ? 1 : -1); 366 367 /* diagonal move [1/sqrt(2)] */ 368 if (mouse_report.v && mouse_report.h) { 369 mouse_report.v = times_inv_sqrt2(mouse_report.v); 370 if (mouse_report.v == 0) { 371 mouse_report.v = 1; 372 } 373 mouse_report.h = times_inv_sqrt2(mouse_report.h); 374 if (mouse_report.h == 0) { 375 mouse_report.h = 1; 376 } 377 } 378 } 379 380 if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) { 381 mousekey_send(); 382 } 383 // save the state for later 384 memcpy(&mouse_report, &tmpmr, sizeof(tmpmr)); 385 } 386 387 void mousekey_on(uint8_t code) { 388 # ifdef MK_KINETIC_SPEED 389 // Start kinetic timer when movement keycodes are pressed 390 if (mouse_timer == 0 && (IS_MOUSEKEY_MOVE(code) || IS_MOUSEKEY_WHEEL(code))) { 391 mouse_timer = timer_read(); 392 } 393 # endif 394 395 # if defined(MOUSEKEY_OVERLAP_RESET) && !defined(MOUSEKEY_INERTIA) 396 // If mouse report is not zero, the current mousekey press is overlapping 397 // with another. Restart acceleration for smoother directional transition. 398 if (mouse_report.x || mouse_report.y || mouse_report.h || mouse_report.v) { 399 # ifdef MK_KINETIC_SPEED 400 mouse_timer = timer_read() - MOUSEKEY_OVERLAP_INTERVAL; 401 # else 402 mousekey_repeat = MOUSEKEY_OVERLAP_MOVE_DELTA; 403 mousekey_wheel_repeat = MOUSEKEY_OVERLAP_WHEEL_DELTA; 404 # endif 405 } 406 # endif // defined(MOUSEKEY_OVERLAP_RESET) && !defined(MOUSEKEY_INERTIA) 407 408 # ifdef MOUSEKEY_INERTIA 409 410 // initial keypress sets impulse and activates first frame of movement 411 if ((code == QK_MOUSE_CURSOR_UP) || (code == QK_MOUSE_CURSOR_DOWN)) { 412 mousekey_y_dir = (code == QK_MOUSE_CURSOR_DOWN) ? 1 : -1; 413 if (mousekey_frame < 2) mouse_report.y = move_unit(1); 414 } else if ((code == QK_MOUSE_CURSOR_LEFT) || (code == QK_MOUSE_CURSOR_RIGHT)) { 415 mousekey_x_dir = (code == QK_MOUSE_CURSOR_RIGHT) ? 1 : -1; 416 if (mousekey_frame < 2) mouse_report.x = move_unit(0); 417 } 418 419 # else // no inertia 420 421 if (code == QK_MOUSE_CURSOR_UP) 422 mouse_report.y = move_unit() * -1; 423 else if (code == QK_MOUSE_CURSOR_DOWN) 424 mouse_report.y = move_unit(); 425 else if (code == QK_MOUSE_CURSOR_LEFT) 426 mouse_report.x = move_unit() * -1; 427 else if (code == QK_MOUSE_CURSOR_RIGHT) 428 mouse_report.x = move_unit(); 429 430 # endif // inertia or not 431 432 else if (code == QK_MOUSE_WHEEL_UP) 433 mouse_report.v = wheel_unit(); 434 else if (code == QK_MOUSE_WHEEL_DOWN) 435 mouse_report.v = wheel_unit() * -1; 436 else if (code == QK_MOUSE_WHEEL_LEFT) 437 mouse_report.h = wheel_unit() * -1; 438 else if (code == QK_MOUSE_WHEEL_RIGHT) 439 mouse_report.h = wheel_unit(); 440 else if (IS_MOUSEKEY_BUTTON(code)) 441 mouse_report.buttons |= 1 << (code - QK_MOUSE_BUTTON_1); 442 else if (code == QK_MOUSE_ACCELERATION_0) 443 mousekey_accel |= (1 << 0); 444 else if (code == QK_MOUSE_ACCELERATION_1) 445 mousekey_accel |= (1 << 1); 446 else if (code == QK_MOUSE_ACCELERATION_2) 447 mousekey_accel |= (1 << 2); 448 } 449 450 void mousekey_off(uint8_t code) { 451 # ifdef MOUSEKEY_INERTIA 452 453 // key release clears impulse unless opposite direction is held 454 if ((code == QK_MOUSE_CURSOR_UP) && (mousekey_y_dir < 1)) 455 mousekey_y_dir = 0; 456 else if ((code == QK_MOUSE_CURSOR_DOWN) && (mousekey_y_dir > -1)) 457 mousekey_y_dir = 0; 458 else if ((code == QK_MOUSE_CURSOR_LEFT) && (mousekey_x_dir < 1)) 459 mousekey_x_dir = 0; 460 else if ((code == QK_MOUSE_CURSOR_RIGHT) && (mousekey_x_dir > -1)) 461 mousekey_x_dir = 0; 462 463 # else // no inertia 464 465 if (code == QK_MOUSE_CURSOR_UP && mouse_report.y < 0) 466 mouse_report.y = 0; 467 else if (code == QK_MOUSE_CURSOR_DOWN && mouse_report.y > 0) 468 mouse_report.y = 0; 469 else if (code == QK_MOUSE_CURSOR_LEFT && mouse_report.x < 0) 470 mouse_report.x = 0; 471 else if (code == QK_MOUSE_CURSOR_RIGHT && mouse_report.x > 0) 472 mouse_report.x = 0; 473 474 # endif // inertia or not 475 476 else if (code == QK_MOUSE_WHEEL_UP && mouse_report.v > 0) 477 mouse_report.v = 0; 478 else if (code == QK_MOUSE_WHEEL_DOWN && mouse_report.v < 0) 479 mouse_report.v = 0; 480 else if (code == QK_MOUSE_WHEEL_LEFT && mouse_report.h < 0) 481 mouse_report.h = 0; 482 else if (code == QK_MOUSE_WHEEL_RIGHT && mouse_report.h > 0) 483 mouse_report.h = 0; 484 else if (IS_MOUSEKEY_BUTTON(code)) 485 mouse_report.buttons &= ~(1 << (code - QK_MOUSE_BUTTON_1)); 486 else if (code == QK_MOUSE_ACCELERATION_0) 487 mousekey_accel &= ~(1 << 0); 488 else if (code == QK_MOUSE_ACCELERATION_1) 489 mousekey_accel &= ~(1 << 1); 490 else if (code == QK_MOUSE_ACCELERATION_2) 491 mousekey_accel &= ~(1 << 2); 492 if (mouse_report.x == 0 && mouse_report.y == 0) { 493 mousekey_repeat = 0; 494 # ifdef MK_KINETIC_SPEED 495 mouse_timer = 0; 496 # endif /* #ifdef MK_KINETIC_SPEED */ 497 } 498 if (mouse_report.v == 0 && mouse_report.h == 0) mousekey_wheel_repeat = 0; 499 } 500 501 #else /* #ifndef MK_3_SPEED */ 502 503 enum { mkspd_unmod, mkspd_0, mkspd_1, mkspd_2, mkspd_COUNT }; 504 # ifndef MK_MOMENTARY_ACCEL 505 static uint8_t mk_speed = mkspd_1; 506 # else 507 static uint8_t mk_speed = mkspd_unmod; 508 static uint8_t mkspd_DEFAULT = mkspd_unmod; 509 # endif 510 static uint16_t last_timer_c = 0; 511 static uint16_t last_timer_w = 0; 512 uint16_t c_offsets[mkspd_COUNT] = {MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2}; 513 uint16_t c_intervals[mkspd_COUNT] = {MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2}; 514 uint16_t w_offsets[mkspd_COUNT] = {MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2}; 515 uint16_t w_intervals[mkspd_COUNT] = {MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2}; 516 517 void mousekey_task(void) { 518 // report cursor and scroll movement independently 519 report_mouse_t tmpmr = mouse_report; 520 mouse_report.x = 0; 521 mouse_report.y = 0; 522 mouse_report.v = 0; 523 mouse_report.h = 0; 524 525 if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) { 526 mouse_report.x = tmpmr.x; 527 mouse_report.y = tmpmr.y; 528 } 529 if ((tmpmr.h || tmpmr.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) { 530 mouse_report.v = tmpmr.v; 531 mouse_report.h = tmpmr.h; 532 } 533 534 if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) { 535 mousekey_send(); 536 } 537 memcpy(&mouse_report, &tmpmr, sizeof(tmpmr)); 538 } 539 540 void adjust_speed(void) { 541 uint16_t const c_offset = c_offsets[mk_speed]; 542 uint16_t const w_offset = w_offsets[mk_speed]; 543 if (mouse_report.x > 0) mouse_report.x = c_offset; 544 if (mouse_report.x < 0) mouse_report.x = c_offset * -1; 545 if (mouse_report.y > 0) mouse_report.y = c_offset; 546 if (mouse_report.y < 0) mouse_report.y = c_offset * -1; 547 if (mouse_report.h > 0) mouse_report.h = w_offset; 548 if (mouse_report.h < 0) mouse_report.h = w_offset * -1; 549 if (mouse_report.v > 0) mouse_report.v = w_offset; 550 if (mouse_report.v < 0) mouse_report.v = w_offset * -1; 551 // adjust for diagonals 552 if (mouse_report.x && mouse_report.y) { 553 mouse_report.x = times_inv_sqrt2(mouse_report.x); 554 if (mouse_report.x == 0) { 555 mouse_report.x = 1; 556 } 557 mouse_report.y = times_inv_sqrt2(mouse_report.y); 558 if (mouse_report.y == 0) { 559 mouse_report.y = 1; 560 } 561 } 562 if (mouse_report.h && mouse_report.v) { 563 mouse_report.h = times_inv_sqrt2(mouse_report.h); 564 mouse_report.v = times_inv_sqrt2(mouse_report.v); 565 } 566 } 567 568 void mousekey_on(uint8_t code) { 569 uint16_t const c_offset = c_offsets[mk_speed]; 570 uint16_t const w_offset = w_offsets[mk_speed]; 571 uint8_t const old_speed = mk_speed; 572 if (code == QK_MOUSE_CURSOR_UP) 573 mouse_report.y = c_offset * -1; 574 else if (code == QK_MOUSE_CURSOR_DOWN) 575 mouse_report.y = c_offset; 576 else if (code == QK_MOUSE_CURSOR_LEFT) 577 mouse_report.x = c_offset * -1; 578 else if (code == QK_MOUSE_CURSOR_RIGHT) 579 mouse_report.x = c_offset; 580 else if (code == QK_MOUSE_WHEEL_UP) 581 mouse_report.v = w_offset; 582 else if (code == QK_MOUSE_WHEEL_DOWN) 583 mouse_report.v = w_offset * -1; 584 else if (code == QK_MOUSE_WHEEL_LEFT) 585 mouse_report.h = w_offset * -1; 586 else if (code == QK_MOUSE_WHEEL_RIGHT) 587 mouse_report.h = w_offset; 588 else if (IS_MOUSEKEY_BUTTON(code)) 589 mouse_report.buttons |= 1 << (code - QK_MOUSE_BUTTON_1); 590 else if (code == QK_MOUSE_ACCELERATION_0) 591 mk_speed = mkspd_0; 592 else if (code == QK_MOUSE_ACCELERATION_1) 593 mk_speed = mkspd_1; 594 else if (code == QK_MOUSE_ACCELERATION_2) 595 mk_speed = mkspd_2; 596 if (mk_speed != old_speed) adjust_speed(); 597 } 598 599 void mousekey_off(uint8_t code) { 600 # ifdef MK_MOMENTARY_ACCEL 601 uint8_t const old_speed = mk_speed; 602 # endif 603 if (code == QK_MOUSE_CURSOR_UP && mouse_report.y < 0) 604 mouse_report.y = 0; 605 else if (code == QK_MOUSE_CURSOR_DOWN && mouse_report.y > 0) 606 mouse_report.y = 0; 607 else if (code == QK_MOUSE_CURSOR_LEFT && mouse_report.x < 0) 608 mouse_report.x = 0; 609 else if (code == QK_MOUSE_CURSOR_RIGHT && mouse_report.x > 0) 610 mouse_report.x = 0; 611 else if (code == QK_MOUSE_WHEEL_UP && mouse_report.v > 0) 612 mouse_report.v = 0; 613 else if (code == QK_MOUSE_WHEEL_DOWN && mouse_report.v < 0) 614 mouse_report.v = 0; 615 else if (code == QK_MOUSE_WHEEL_LEFT && mouse_report.h < 0) 616 mouse_report.h = 0; 617 else if (code == QK_MOUSE_WHEEL_RIGHT && mouse_report.h > 0) 618 mouse_report.h = 0; 619 else if (IS_MOUSEKEY_BUTTON(code)) 620 mouse_report.buttons &= ~(1 << (code - QK_MOUSE_BUTTON_1)); 621 # ifdef MK_MOMENTARY_ACCEL 622 else if (code == QK_MOUSE_ACCELERATION_0) 623 mk_speed = mkspd_DEFAULT; 624 else if (code == QK_MOUSE_ACCELERATION_1) 625 mk_speed = mkspd_DEFAULT; 626 else if (code == QK_MOUSE_ACCELERATION_2) 627 mk_speed = mkspd_DEFAULT; 628 if (mk_speed != old_speed) adjust_speed(); 629 # endif 630 } 631 632 #endif /* #ifndef MK_3_SPEED */ 633 634 void mousekey_send(void) { 635 mousekey_debug(); 636 uint16_t time = timer_read(); 637 if (mouse_report.x || mouse_report.y) last_timer_c = time; 638 if (mouse_report.v || mouse_report.h) last_timer_w = time; 639 host_mouse_send(&mouse_report); 640 } 641 642 void mousekey_clear(void) { 643 mouse_report = (report_mouse_t){}; 644 mousekey_repeat = 0; 645 mousekey_wheel_repeat = 0; 646 mousekey_accel = 0; 647 #ifdef MOUSEKEY_INERTIA 648 mousekey_frame = 0; 649 mousekey_x_inertia = 0; 650 mousekey_y_inertia = 0; 651 mousekey_x_dir = 0; 652 mousekey_y_dir = 0; 653 #endif 654 } 655 656 static void mousekey_debug(void) { 657 if (!debug_mouse) return; 658 print("mousekey [btn|x y v h](rep/acl): ["); 659 print_hex8(mouse_report.buttons); 660 print("|"); 661 print_decs(mouse_report.x); 662 print(" "); 663 print_decs(mouse_report.y); 664 print(" "); 665 print_decs(mouse_report.v); 666 print(" "); 667 print_decs(mouse_report.h); 668 print("]("); 669 print_dec(mousekey_repeat); 670 print("/"); 671 print_dec(mousekey_accel); 672 print(")\n"); 673 } 674 675 report_mouse_t mousekey_get_report(void) { 676 return mouse_report; 677 } 678 679 bool should_mousekey_report_send(report_mouse_t *mouse_report) { 680 return mouse_report->x || mouse_report->y || mouse_report->v || mouse_report->h; 681 }