2 Copyright 2011 Jun Wako <wakojun@gmail.com>
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.
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.
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/>.
26 inline int8_t times_inv_sqrt2(int8_t x) {
27 // 181/256 is pretty close to 1/sqrt(2)
28 // 0.70703125 0.707106781
29 // 1 too small for x=99 and x=198
30 // This ends up being a mult and discard lower 8 bits
31 return (x * 181) >> 8;
34 static report_mouse_t mouse_report = {0};
35 static void mousekey_debug(void);
36 static uint8_t mousekey_accel = 0;
37 static uint8_t mousekey_repeat = 0;
38 static uint16_t last_timer = 0;
47 * Mouse keys acceleration algorithm
48 * http://en.wikipedia.org/wiki/Mouse_keys
50 * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000)
52 /* milliseconds between the initial key press and first repeated motion event (0-2550) */
53 uint8_t mk_delay = MOUSEKEY_DELAY/10;
54 /* milliseconds between repeated motion events (0-255) */
55 uint8_t mk_interval = MOUSEKEY_INTERVAL;
56 /* steady speed (in action_delta units) applied each event (0-255) */
57 uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED;
58 /* number of events (count) accelerating to steady speed (0-255) */
59 uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
60 /* ramp used to reach maximum pointer speed (NOT SUPPORTED) */
61 //int8_t mk_curve = 0;
63 uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
64 uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
66 static uint8_t move_unit(void) {
68 if (mousekey_accel & (1<<0)) {
69 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/4;
70 } else if (mousekey_accel & (1<<1)) {
71 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/2;
72 } else if (mousekey_accel & (1<<2)) {
73 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed);
74 } else if (mousekey_repeat == 0) {
75 unit = MOUSEKEY_MOVE_DELTA;
76 } else if (mousekey_repeat >= mk_time_to_max) {
77 unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
79 unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
81 return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
84 static uint8_t wheel_unit(void) {
86 if (mousekey_accel & (1<<0)) {
87 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/4;
88 } else if (mousekey_accel & (1<<1)) {
89 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/2;
90 } else if (mousekey_accel & (1<<2)) {
91 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed);
92 } else if (mousekey_repeat == 0) {
93 unit = MOUSEKEY_WHEEL_DELTA;
94 } else if (mousekey_repeat >= mk_wheel_time_to_max) {
95 unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
97 unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max;
99 return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
102 void mousekey_task(void) {
103 if (timer_elapsed(last_timer) < (mousekey_repeat ? mk_interval : mk_delay*10)) {
106 if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0) {
109 if (mousekey_repeat != UINT8_MAX) mousekey_repeat++;
110 if (mouse_report.x > 0) mouse_report.x = move_unit();
111 if (mouse_report.x < 0) mouse_report.x = move_unit() * -1;
112 if (mouse_report.y > 0) mouse_report.y = move_unit();
113 if (mouse_report.y < 0) mouse_report.y = move_unit() * -1;
114 /* diagonal move [1/sqrt(2)] */
115 if (mouse_report.x && mouse_report.y) {
116 mouse_report.x = times_inv_sqrt2(mouse_report.x);
117 if (mouse_report.x == 0) { mouse_report.x = 1; }
118 mouse_report.y = times_inv_sqrt2(mouse_report.y);
119 if (mouse_report.y == 0) { mouse_report.y = 1; }
121 if (mouse_report.v > 0) mouse_report.v = wheel_unit();
122 if (mouse_report.v < 0) mouse_report.v = wheel_unit() * -1;
123 if (mouse_report.h > 0) mouse_report.h = wheel_unit();
124 if (mouse_report.h < 0) mouse_report.h = wheel_unit() * -1;
128 void mousekey_on(uint8_t code) {
129 if (code == KC_MS_UP) mouse_report.y = move_unit() * -1;
130 else if (code == KC_MS_DOWN) mouse_report.y = move_unit();
131 else if (code == KC_MS_LEFT) mouse_report.x = move_unit() * -1;
132 else if (code == KC_MS_RIGHT) mouse_report.x = move_unit();
133 else if (code == KC_MS_WH_UP) mouse_report.v = wheel_unit();
134 else if (code == KC_MS_WH_DOWN) mouse_report.v = wheel_unit() * -1;
135 else if (code == KC_MS_WH_LEFT) mouse_report.h = wheel_unit() * -1;
136 else if (code == KC_MS_WH_RIGHT) mouse_report.h = wheel_unit();
137 else if (code == KC_MS_BTN1) mouse_report.buttons |= MOUSE_BTN1;
138 else if (code == KC_MS_BTN2) mouse_report.buttons |= MOUSE_BTN2;
139 else if (code == KC_MS_BTN3) mouse_report.buttons |= MOUSE_BTN3;
140 else if (code == KC_MS_BTN4) mouse_report.buttons |= MOUSE_BTN4;
141 else if (code == KC_MS_BTN5) mouse_report.buttons |= MOUSE_BTN5;
142 else if (code == KC_MS_ACCEL0) mousekey_accel |= (1<<0);
143 else if (code == KC_MS_ACCEL1) mousekey_accel |= (1<<1);
144 else if (code == KC_MS_ACCEL2) mousekey_accel |= (1<<2);
147 void mousekey_off(uint8_t code) {
148 if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0;
149 else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0;
150 else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0;
151 else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0;
152 else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0;
153 else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0;
154 else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0;
155 else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0;
156 else if (code == KC_MS_BTN1) mouse_report.buttons &= ~MOUSE_BTN1;
157 else if (code == KC_MS_BTN2) mouse_report.buttons &= ~MOUSE_BTN2;
158 else if (code == KC_MS_BTN3) mouse_report.buttons &= ~MOUSE_BTN3;
159 else if (code == KC_MS_BTN4) mouse_report.buttons &= ~MOUSE_BTN4;
160 else if (code == KC_MS_BTN5) mouse_report.buttons &= ~MOUSE_BTN5;
161 else if (code == KC_MS_ACCEL0) mousekey_accel &= ~(1<<0);
162 else if (code == KC_MS_ACCEL1) mousekey_accel &= ~(1<<1);
163 else if (code == KC_MS_ACCEL2) mousekey_accel &= ~(1<<2);
164 if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0)
171 #else /* #ifndef MK_3_SPEED */
182 #ifndef MK_MOMENTARY_ACCEL
183 static uint8_t mk_speed = mkspd_1;
185 static uint8_t mk_speed = mkspd_unmod;
186 static uint8_t mkspd_DEFAULT = mkspd_unmod;
188 static uint16_t last_timer_c = 0;
189 static uint16_t last_timer_w = 0;
190 uint16_t c_offsets[mkspd_COUNT] = {
191 MK_C_OFFSET_UNMOD, MK_C_OFFSET_0, MK_C_OFFSET_1, MK_C_OFFSET_2
193 uint16_t c_intervals[mkspd_COUNT] = {
194 MK_C_INTERVAL_UNMOD, MK_C_INTERVAL_0, MK_C_INTERVAL_1, MK_C_INTERVAL_2
196 uint16_t w_offsets[mkspd_COUNT] = {
197 MK_W_OFFSET_UNMOD, MK_W_OFFSET_0, MK_W_OFFSET_1, MK_W_OFFSET_2
199 uint16_t w_intervals[mkspd_COUNT] = {
200 MK_W_INTERVAL_UNMOD, MK_W_INTERVAL_0, MK_W_INTERVAL_1, MK_W_INTERVAL_2
204 void mousekey_task(void) {
205 // report cursor and scroll movement independently
206 report_mouse_t const tmpmr = mouse_report;
207 if ((mouse_report.x || mouse_report.y) && timer_elapsed(last_timer_c) > c_intervals[mk_speed]) {
211 last_timer_c = last_timer;
212 mouse_report = tmpmr;
214 if ((mouse_report.h || mouse_report.v) && timer_elapsed(last_timer_w) > w_intervals[mk_speed]) {
218 last_timer_w = last_timer;
219 mouse_report = tmpmr;
223 void adjust_speed(void) {
224 uint16_t const c_offset = c_offsets[mk_speed];
225 uint16_t const w_offset = w_offsets[mk_speed];
226 if (mouse_report.x > 0) mouse_report.x = c_offset;
227 if (mouse_report.x < 0) mouse_report.x = c_offset * -1;
228 if (mouse_report.y > 0) mouse_report.y = c_offset;
229 if (mouse_report.y < 0) mouse_report.y = c_offset * -1;
230 if (mouse_report.h > 0) mouse_report.h = w_offset;
231 if (mouse_report.h < 0) mouse_report.h = w_offset * -1;
232 if (mouse_report.v > 0) mouse_report.v = w_offset;
233 if (mouse_report.v < 0) mouse_report.v = w_offset * -1;
234 // adjust for diagonals
235 if (mouse_report.x && mouse_report.y) {
236 mouse_report.x = times_inv_sqrt2(mouse_report.x);
237 if (mouse_report.x == 0) { mouse_report.x = 1; }
238 mouse_report.y = times_inv_sqrt2(mouse_report.y);
239 if (mouse_report.y == 0) { mouse_report.y = 1; }
241 if (mouse_report.h && mouse_report.v) {
242 mouse_report.h = times_inv_sqrt2(mouse_report.h);
243 mouse_report.v = times_inv_sqrt2(mouse_report.v);
247 void mousekey_on(uint8_t code) {
248 uint16_t const c_offset = c_offsets[mk_speed];
249 uint16_t const w_offset = w_offsets[mk_speed];
250 uint8_t const old_speed = mk_speed;
251 if (code == KC_MS_UP) mouse_report.y = c_offset * -1;
252 else if (code == KC_MS_DOWN) mouse_report.y = c_offset;
253 else if (code == KC_MS_LEFT) mouse_report.x = c_offset * -1;
254 else if (code == KC_MS_RIGHT) mouse_report.x = c_offset;
255 else if (code == KC_MS_WH_UP) mouse_report.v = w_offset;
256 else if (code == KC_MS_WH_DOWN) mouse_report.v = w_offset * -1;
257 else if (code == KC_MS_WH_LEFT) mouse_report.h = w_offset * -1;
258 else if (code == KC_MS_WH_RIGHT) mouse_report.h = w_offset;
259 else if (code == KC_MS_BTN1) mouse_report.buttons |= MOUSE_BTN1;
260 else if (code == KC_MS_BTN2) mouse_report.buttons |= MOUSE_BTN2;
261 else if (code == KC_MS_BTN3) mouse_report.buttons |= MOUSE_BTN3;
262 else if (code == KC_MS_BTN4) mouse_report.buttons |= MOUSE_BTN4;
263 else if (code == KC_MS_BTN5) mouse_report.buttons |= MOUSE_BTN5;
264 else if (code == KC_MS_ACCEL0) mk_speed = mkspd_0;
265 else if (code == KC_MS_ACCEL1) mk_speed = mkspd_1;
266 else if (code == KC_MS_ACCEL2) mk_speed = mkspd_2;
267 if (mk_speed != old_speed) adjust_speed();
270 void mousekey_off(uint8_t code) {
271 #ifdef MK_MOMENTARY_ACCEL
272 uint8_t const old_speed = mk_speed;
274 if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0;
275 else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0;
276 else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0;
277 else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0;
278 else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0;
279 else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0;
280 else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0;
281 else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0;
282 else if (code == KC_MS_BTN1) mouse_report.buttons &= ~MOUSE_BTN1;
283 else if (code == KC_MS_BTN2) mouse_report.buttons &= ~MOUSE_BTN2;
284 else if (code == KC_MS_BTN3) mouse_report.buttons &= ~MOUSE_BTN3;
285 else if (code == KC_MS_BTN4) mouse_report.buttons &= ~MOUSE_BTN4;
286 else if (code == KC_MS_BTN5) mouse_report.buttons &= ~MOUSE_BTN5;
287 #ifdef MK_MOMENTARY_ACCEL
288 else if (code == KC_MS_ACCEL0) mk_speed = mkspd_DEFAULT;
289 else if (code == KC_MS_ACCEL1) mk_speed = mkspd_DEFAULT;
290 else if (code == KC_MS_ACCEL2) mk_speed = mkspd_DEFAULT;
291 if (mk_speed != old_speed) adjust_speed();
298 #endif /* #ifndef MK_3_SPEED */
303 void mousekey_send(void) {
305 host_mouse_send(&mouse_report);
306 last_timer = timer_read();
309 void mousekey_clear(void) {
310 mouse_report = (report_mouse_t){};
315 static void mousekey_debug(void) {
316 if (!debug_mouse) return;
317 print("mousekey [btn|x y v h](rep/acl): [");
318 phex(mouse_report.buttons); print("|");
319 print_decs(mouse_report.x); print(" ");
320 print_decs(mouse_report.y); print(" ");
321 print_decs(mouse_report.v); print(" ");
322 print_decs(mouse_report.h); print("](");
323 print_dec(mousekey_repeat); print("/");
324 print_dec(mousekey_accel); print(")\n");