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;
42 static uint16_t last_timer_c
= 0;
43 static uint16_t last_timer_w
= 0;
46 * Mouse keys acceleration algorithm
47 * http://en.wikipedia.org/wiki/Mouse_keys
49 * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000)
51 /* milliseconds between the initial key press and first repeated motion event (0-2550) */
52 uint8_t mk_delay
= MOUSEKEY_DELAY
/ 10;
53 /* milliseconds between repeated motion events (0-255) */
54 uint8_t mk_interval
= MOUSEKEY_INTERVAL
;
55 /* steady speed (in action_delta units) applied each event (0-255) */
56 uint8_t mk_max_speed
= MOUSEKEY_MAX_SPEED
;
57 /* number of events (count) accelerating to steady speed (0-255) */
58 uint8_t mk_time_to_max
= MOUSEKEY_TIME_TO_MAX
;
59 /* ramp used to reach maximum pointer speed (NOT SUPPORTED) */
60 // int8_t mk_curve = 0;
62 /* milliseconds between the initial key press and first repeated motion event (0-2550) */
63 uint8_t mk_wheel_delay
= MOUSEKEY_WHEEL_DELAY
/ 10;
64 /* milliseconds between repeated motion events (0-255) */
65 uint8_t mk_wheel_interval
= MOUSEKEY_WHEEL_INTERVAL
;
66 uint8_t mk_wheel_max_speed
= MOUSEKEY_WHEEL_MAX_SPEED
;
67 uint8_t mk_wheel_time_to_max
= MOUSEKEY_WHEEL_TIME_TO_MAX
;
69 static uint8_t move_unit(void) {
71 if (mousekey_accel
& (1 << 0)) {
72 unit
= (MOUSEKEY_MOVE_DELTA
* mk_max_speed
) / 4;
73 } else if (mousekey_accel
& (1 << 1)) {
74 unit
= (MOUSEKEY_MOVE_DELTA
* mk_max_speed
) / 2;
75 } else if (mousekey_accel
& (1 << 2)) {
76 unit
= (MOUSEKEY_MOVE_DELTA
* mk_max_speed
);
77 } else if (mousekey_repeat
== 0) {
78 unit
= MOUSEKEY_MOVE_DELTA
;
79 } else if (mousekey_repeat
>= mk_time_to_max
) {
80 unit
= MOUSEKEY_MOVE_DELTA
* mk_max_speed
;
82 unit
= (MOUSEKEY_MOVE_DELTA
* mk_max_speed
* mousekey_repeat
) / mk_time_to_max
;
84 return (unit
> MOUSEKEY_MOVE_MAX
? MOUSEKEY_MOVE_MAX
: (unit
== 0 ? 1 : unit
));
87 static uint8_t wheel_unit(void) {
89 if (mousekey_accel
& (1 << 0)) {
90 unit
= (MOUSEKEY_WHEEL_DELTA
* mk_wheel_max_speed
) / 4;
91 } else if (mousekey_accel
& (1 << 1)) {
92 unit
= (MOUSEKEY_WHEEL_DELTA
* mk_wheel_max_speed
) / 2;
93 } else if (mousekey_accel
& (1 << 2)) {
94 unit
= (MOUSEKEY_WHEEL_DELTA
* mk_wheel_max_speed
);
95 } else if (mousekey_repeat
== 0) {
96 unit
= MOUSEKEY_WHEEL_DELTA
;
97 } else if (mousekey_repeat
>= mk_wheel_time_to_max
) {
98 unit
= MOUSEKEY_WHEEL_DELTA
* mk_wheel_max_speed
;
100 unit
= (MOUSEKEY_WHEEL_DELTA
* mk_wheel_max_speed
* mousekey_repeat
) / mk_wheel_time_to_max
;
102 return (unit
> MOUSEKEY_WHEEL_MAX
? MOUSEKEY_WHEEL_MAX
: (unit
== 0 ? 1 : unit
));
105 void mousekey_task(void) {
106 // report cursor and scroll movement independently
107 report_mouse_t
const tmpmr
= mouse_report
;
108 if ((mouse_report
.x
|| mouse_report
.y
) && timer_elapsed(last_timer_c
) > (mousekey_repeat
? mk_interval
: mk_delay
* 10)) {
109 if (mousekey_repeat
!= UINT8_MAX
) mousekey_repeat
++;
112 if (mouse_report
.x
> 0) mouse_report
.x
= move_unit();
113 if (mouse_report
.x
< 0) mouse_report
.x
= move_unit() * -1;
114 if (mouse_report
.y
> 0) mouse_report
.y
= move_unit();
115 if (mouse_report
.y
< 0) mouse_report
.y
= move_unit() * -1;
116 /* diagonal move [1/sqrt(2)] */
117 if (mouse_report
.x
&& mouse_report
.y
) {
118 mouse_report
.x
= times_inv_sqrt2(mouse_report
.x
);
119 if (mouse_report
.x
== 0) {
122 mouse_report
.y
= times_inv_sqrt2(mouse_report
.y
);
123 if (mouse_report
.y
== 0) {
128 last_timer_c
= last_timer
;
129 mouse_report
= tmpmr
;
131 if ((mouse_report
.v
|| mouse_report
.h
) && timer_elapsed(last_timer_w
) > (mousekey_repeat
? mk_wheel_interval
: mk_wheel_delay
* 10)) {
132 if (mousekey_repeat
!= UINT8_MAX
) mousekey_repeat
++;
135 if (mouse_report
.v
> 0) mouse_report
.v
= wheel_unit();
136 if (mouse_report
.v
< 0) mouse_report
.v
= wheel_unit() * -1;
137 if (mouse_report
.h
> 0) mouse_report
.h
= wheel_unit();
138 if (mouse_report
.h
< 0) mouse_report
.h
= wheel_unit() * -1;
139 /* diagonal move [1/sqrt(2)] */
140 if (mouse_report
.v
&& mouse_report
.h
) {
141 mouse_report
.v
= times_inv_sqrt2(mouse_report
.v
);
142 if (mouse_report
.v
== 0) {
145 mouse_report
.h
= times_inv_sqrt2(mouse_report
.h
);
146 if (mouse_report
.h
== 0) {
151 last_timer_w
= last_timer
;
152 mouse_report
= tmpmr
;
156 void mousekey_on(uint8_t code
) {
157 if (code
== KC_MS_UP
)
158 mouse_report
.y
= move_unit() * -1;
159 else if (code
== KC_MS_DOWN
)
160 mouse_report
.y
= move_unit();
161 else if (code
== KC_MS_LEFT
)
162 mouse_report
.x
= move_unit() * -1;
163 else if (code
== KC_MS_RIGHT
)
164 mouse_report
.x
= move_unit();
165 else if (code
== KC_MS_WH_UP
)
166 mouse_report
.v
= wheel_unit();
167 else if (code
== KC_MS_WH_DOWN
)
168 mouse_report
.v
= wheel_unit() * -1;
169 else if (code
== KC_MS_WH_LEFT
)
170 mouse_report
.h
= wheel_unit() * -1;
171 else if (code
== KC_MS_WH_RIGHT
)
172 mouse_report
.h
= wheel_unit();
173 else if (code
== KC_MS_BTN1
)
174 mouse_report
.buttons
|= MOUSE_BTN1
;
175 else if (code
== KC_MS_BTN2
)
176 mouse_report
.buttons
|= MOUSE_BTN2
;
177 else if (code
== KC_MS_BTN3
)
178 mouse_report
.buttons
|= MOUSE_BTN3
;
179 else if (code
== KC_MS_BTN4
)
180 mouse_report
.buttons
|= MOUSE_BTN4
;
181 else if (code
== KC_MS_BTN5
)
182 mouse_report
.buttons
|= MOUSE_BTN5
;
183 else if (code
== KC_MS_ACCEL0
)
184 mousekey_accel
|= (1 << 0);
185 else if (code
== KC_MS_ACCEL1
)
186 mousekey_accel
|= (1 << 1);
187 else if (code
== KC_MS_ACCEL2
)
188 mousekey_accel
|= (1 << 2);
191 void mousekey_off(uint8_t code
) {
192 if (code
== KC_MS_UP
&& mouse_report
.y
< 0)
194 else if (code
== KC_MS_DOWN
&& mouse_report
.y
> 0)
196 else if (code
== KC_MS_LEFT
&& mouse_report
.x
< 0)
198 else if (code
== KC_MS_RIGHT
&& mouse_report
.x
> 0)
200 else if (code
== KC_MS_WH_UP
&& mouse_report
.v
> 0)
202 else if (code
== KC_MS_WH_DOWN
&& mouse_report
.v
< 0)
204 else if (code
== KC_MS_WH_LEFT
&& mouse_report
.h
< 0)
206 else if (code
== KC_MS_WH_RIGHT
&& mouse_report
.h
> 0)
208 else if (code
== KC_MS_BTN1
)
209 mouse_report
.buttons
&= ~MOUSE_BTN1
;
210 else if (code
== KC_MS_BTN2
)
211 mouse_report
.buttons
&= ~MOUSE_BTN2
;
212 else if (code
== KC_MS_BTN3
)
213 mouse_report
.buttons
&= ~MOUSE_BTN3
;
214 else if (code
== KC_MS_BTN4
)
215 mouse_report
.buttons
&= ~MOUSE_BTN4
;
216 else if (code
== KC_MS_BTN5
)
217 mouse_report
.buttons
&= ~MOUSE_BTN5
;
218 else if (code
== KC_MS_ACCEL0
)
219 mousekey_accel
&= ~(1 << 0);
220 else if (code
== KC_MS_ACCEL1
)
221 mousekey_accel
&= ~(1 << 1);
222 else if (code
== KC_MS_ACCEL2
)
223 mousekey_accel
&= ~(1 << 2);
224 if (mouse_report
.x
== 0 && mouse_report
.y
== 0 && mouse_report
.v
== 0 && mouse_report
.h
== 0) mousekey_repeat
= 0;
227 #else /* #ifndef MK_3_SPEED */
229 enum { mkspd_unmod
, mkspd_0
, mkspd_1
, mkspd_2
, mkspd_COUNT
};
230 # ifndef MK_MOMENTARY_ACCEL
231 static uint8_t mk_speed
= mkspd_1
;
233 static uint8_t mk_speed
= mkspd_unmod
;
234 static uint8_t mkspd_DEFAULT
= mkspd_unmod
;
236 static uint16_t last_timer_c
= 0;
237 static uint16_t last_timer_w
= 0;
238 uint16_t c_offsets
[mkspd_COUNT
] = {MK_C_OFFSET_UNMOD
, MK_C_OFFSET_0
, MK_C_OFFSET_1
, MK_C_OFFSET_2
};
239 uint16_t c_intervals
[mkspd_COUNT
] = {MK_C_INTERVAL_UNMOD
, MK_C_INTERVAL_0
, MK_C_INTERVAL_1
, MK_C_INTERVAL_2
};
240 uint16_t w_offsets
[mkspd_COUNT
] = {MK_W_OFFSET_UNMOD
, MK_W_OFFSET_0
, MK_W_OFFSET_1
, MK_W_OFFSET_2
};
241 uint16_t w_intervals
[mkspd_COUNT
] = {MK_W_INTERVAL_UNMOD
, MK_W_INTERVAL_0
, MK_W_INTERVAL_1
, MK_W_INTERVAL_2
};
243 void mousekey_task(void) {
244 // report cursor and scroll movement independently
245 report_mouse_t
const tmpmr
= mouse_report
;
246 if ((mouse_report
.x
|| mouse_report
.y
) && timer_elapsed(last_timer_c
) > c_intervals
[mk_speed
]) {
250 last_timer_c
= last_timer
;
251 mouse_report
= tmpmr
;
253 if ((mouse_report
.h
|| mouse_report
.v
) && timer_elapsed(last_timer_w
) > w_intervals
[mk_speed
]) {
257 last_timer_w
= last_timer
;
258 mouse_report
= tmpmr
;
262 void adjust_speed(void) {
263 uint16_t const c_offset
= c_offsets
[mk_speed
];
264 uint16_t const w_offset
= w_offsets
[mk_speed
];
265 if (mouse_report
.x
> 0) mouse_report
.x
= c_offset
;
266 if (mouse_report
.x
< 0) mouse_report
.x
= c_offset
* -1;
267 if (mouse_report
.y
> 0) mouse_report
.y
= c_offset
;
268 if (mouse_report
.y
< 0) mouse_report
.y
= c_offset
* -1;
269 if (mouse_report
.h
> 0) mouse_report
.h
= w_offset
;
270 if (mouse_report
.h
< 0) mouse_report
.h
= w_offset
* -1;
271 if (mouse_report
.v
> 0) mouse_report
.v
= w_offset
;
272 if (mouse_report
.v
< 0) mouse_report
.v
= w_offset
* -1;
273 // adjust for diagonals
274 if (mouse_report
.x
&& mouse_report
.y
) {
275 mouse_report
.x
= times_inv_sqrt2(mouse_report
.x
);
276 if (mouse_report
.x
== 0) {
279 mouse_report
.y
= times_inv_sqrt2(mouse_report
.y
);
280 if (mouse_report
.y
== 0) {
284 if (mouse_report
.h
&& mouse_report
.v
) {
285 mouse_report
.h
= times_inv_sqrt2(mouse_report
.h
);
286 mouse_report
.v
= times_inv_sqrt2(mouse_report
.v
);
290 void mousekey_on(uint8_t code
) {
291 uint16_t const c_offset
= c_offsets
[mk_speed
];
292 uint16_t const w_offset
= w_offsets
[mk_speed
];
293 uint8_t const old_speed
= mk_speed
;
294 if (code
== KC_MS_UP
)
295 mouse_report
.y
= c_offset
* -1;
296 else if (code
== KC_MS_DOWN
)
297 mouse_report
.y
= c_offset
;
298 else if (code
== KC_MS_LEFT
)
299 mouse_report
.x
= c_offset
* -1;
300 else if (code
== KC_MS_RIGHT
)
301 mouse_report
.x
= c_offset
;
302 else if (code
== KC_MS_WH_UP
)
303 mouse_report
.v
= w_offset
;
304 else if (code
== KC_MS_WH_DOWN
)
305 mouse_report
.v
= w_offset
* -1;
306 else if (code
== KC_MS_WH_LEFT
)
307 mouse_report
.h
= w_offset
* -1;
308 else if (code
== KC_MS_WH_RIGHT
)
309 mouse_report
.h
= w_offset
;
310 else if (code
== KC_MS_BTN1
)
311 mouse_report
.buttons
|= MOUSE_BTN1
;
312 else if (code
== KC_MS_BTN2
)
313 mouse_report
.buttons
|= MOUSE_BTN2
;
314 else if (code
== KC_MS_BTN3
)
315 mouse_report
.buttons
|= MOUSE_BTN3
;
316 else if (code
== KC_MS_BTN4
)
317 mouse_report
.buttons
|= MOUSE_BTN4
;
318 else if (code
== KC_MS_BTN5
)
319 mouse_report
.buttons
|= MOUSE_BTN5
;
320 else if (code
== KC_MS_ACCEL0
)
322 else if (code
== KC_MS_ACCEL1
)
324 else if (code
== KC_MS_ACCEL2
)
326 if (mk_speed
!= old_speed
) adjust_speed();
329 void mousekey_off(uint8_t code
) {
330 # ifdef MK_MOMENTARY_ACCEL
331 uint8_t const old_speed
= mk_speed
;
333 if (code
== KC_MS_UP
&& mouse_report
.y
< 0)
335 else if (code
== KC_MS_DOWN
&& mouse_report
.y
> 0)
337 else if (code
== KC_MS_LEFT
&& mouse_report
.x
< 0)
339 else if (code
== KC_MS_RIGHT
&& mouse_report
.x
> 0)
341 else if (code
== KC_MS_WH_UP
&& mouse_report
.v
> 0)
343 else if (code
== KC_MS_WH_DOWN
&& mouse_report
.v
< 0)
345 else if (code
== KC_MS_WH_LEFT
&& mouse_report
.h
< 0)
347 else if (code
== KC_MS_WH_RIGHT
&& mouse_report
.h
> 0)
349 else if (code
== KC_MS_BTN1
)
350 mouse_report
.buttons
&= ~MOUSE_BTN1
;
351 else if (code
== KC_MS_BTN2
)
352 mouse_report
.buttons
&= ~MOUSE_BTN2
;
353 else if (code
== KC_MS_BTN3
)
354 mouse_report
.buttons
&= ~MOUSE_BTN3
;
355 else if (code
== KC_MS_BTN4
)
356 mouse_report
.buttons
&= ~MOUSE_BTN4
;
357 else if (code
== KC_MS_BTN5
)
358 mouse_report
.buttons
&= ~MOUSE_BTN5
;
359 # ifdef MK_MOMENTARY_ACCEL
360 else if (code
== KC_MS_ACCEL0
)
361 mk_speed
= mkspd_DEFAULT
;
362 else if (code
== KC_MS_ACCEL1
)
363 mk_speed
= mkspd_DEFAULT
;
364 else if (code
== KC_MS_ACCEL2
)
365 mk_speed
= mkspd_DEFAULT
;
366 if (mk_speed
!= old_speed
) adjust_speed();
370 #endif /* #ifndef MK_3_SPEED */
372 void mousekey_send(void) {
374 host_mouse_send(&mouse_report
);
375 last_timer
= timer_read();
378 void mousekey_clear(void) {
379 mouse_report
= (report_mouse_t
){};
384 static void mousekey_debug(void) {
385 if (!debug_mouse
) return;
386 print("mousekey [btn|x y v h](rep/acl): [");
387 phex(mouse_report
.buttons
);
389 print_decs(mouse_report
.x
);
391 print_decs(mouse_report
.y
);
393 print_decs(mouse_report
.v
);
395 print_decs(mouse_report
.h
);
397 print_dec(mousekey_repeat
);
399 print_dec(mousekey_accel
);