forked from mirrors/qmk_userspace
		
	add "inertia" mode for mouse keys (#18774)
Co-authored-by: Selene ToyKeeper <git@toykeeper.net>
This commit is contained in:
		
					parent
					
						
							
								4c0c491e31
							
						
					
				
			
			
				commit
				
					
						2a61bfc27d
					
				
			
		
					 3 changed files with 208 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -48,8 +48,9 @@ Mouse keys supports three different modes to move the cursor:
 | 
			
		|||
* **Kinetic:** Holding movement keys accelerates the cursor with its speed following a quadratic curve until it reaches its maximum speed.
 | 
			
		||||
* **Constant:** Holding movement keys moves the cursor at constant speeds.
 | 
			
		||||
* **Combined:** Holding movement keys accelerates the cursor until it reaches its maximum speed, but holding acceleration and movement keys simultaneously moves the cursor at constant speeds.
 | 
			
		||||
* **Inertia:** Cursor accelerates when key held, and decelerates after key release.  Tracks X and Y velocity separately for more nuanced movements.  Applies to cursor only, not scrolling.
 | 
			
		||||
 | 
			
		||||
The same principle applies to scrolling.
 | 
			
		||||
The same principle applies to scrolling, in most modes.
 | 
			
		||||
 | 
			
		||||
Configuration options that are times, intervals or delays are given in milliseconds. Scroll speed is given as multiples of the default scroll step. For example, a scroll speed of 8 means that each scroll action covers 8 times the length of the default scroll step as defined by your operating system or application.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -170,6 +171,37 @@ To use combined speed mode, you must at least define `MK_COMBINED` in your keyma
 | 
			
		|||
#define MK_COMBINED
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Inertia mode
 | 
			
		||||
 | 
			
		||||
This mode provides smooth motion, like sliding on ice.  The cursor accelerates
 | 
			
		||||
along a quadratic curve while a key is held, then glides to a stop after the
 | 
			
		||||
key is released.  Vertical and horizontal movements are tracked independently,
 | 
			
		||||
so the cursor can move in many directions and make curves.
 | 
			
		||||
 | 
			
		||||
Cannot be used at the same time as Kinetic mode, Constant mode, or Combined mode.
 | 
			
		||||
 | 
			
		||||
Recommended settings in your keymap’s `config.h` file:
 | 
			
		||||
 | 
			
		||||
|Define                      |Default  |Description                                                |
 | 
			
		||||
|----------------------------|---------|-----------------------------------------------------------|
 | 
			
		||||
|`MOUSEKEY_INERTIA`          |undefined|Enable Inertia mode                                        |
 | 
			
		||||
|`MOUSEKEY_DELAY`            |150      |Delay between pressing a movement key and cursor movement  |
 | 
			
		||||
|`MOUSEKEY_INTERVAL`         |16       |Time between cursor movements in milliseconds (16 = 60fps) |
 | 
			
		||||
|`MOUSEKEY_MAX_SPEED`        |32       |Maximum cursor speed at which acceleration stops           |
 | 
			
		||||
|`MOUSEKEY_TIME_TO_MAX`      |32       |Number of frames until maximum cursor speed is reached     |
 | 
			
		||||
|`MOUSEKEY_FRICTION`         |24       |How quickly the cursor stops after releasing a key         |
 | 
			
		||||
|`MOUSEKEY_MOVE_DELTA`       |1        |How much to move on first frame (1 strongly recommended)   |
 | 
			
		||||
 | 
			
		||||
Tips:
 | 
			
		||||
 | 
			
		||||
* Set `MOUSEKEY_DELAY` to roughly the same value as your host computer's key repeat delay, in ms.  Recommended values are 100 to 300.
 | 
			
		||||
* Set `MOUSEKEY_INTERVAL` to a value of 1000 / your monitor's FPS.  For 60 FPS, 1000/60 = 16.
 | 
			
		||||
* Set `MOUSEKEY_MAX_SPEED` based on your screen resolution and refresh rate, like Width / FPS.  For example, 1920 pixels / 60 FPS = 32 pixels per frame.
 | 
			
		||||
* Set `MOUSEKEY_TIME_TO_MAX` to a value of approximately FPS / 2, to make it reach full speed in half a second (or so).
 | 
			
		||||
* Set `MOUSEKEY_FRICTION` to something between 1 and 255.  Lower makes the cursor glide longer. Values from 8 to 40 are the most effective.
 | 
			
		||||
* Keep `MOUSEKEY_MOVE_DELTA` at 1.  This allows precise movements before the gliding effect starts.
 | 
			
		||||
* Mouse wheel options are the same as the default accelerated mode, and do not use inertia.
 | 
			
		||||
 | 
			
		||||
## Use with PS/2 Mouse and Pointing Device
 | 
			
		||||
 | 
			
		||||
Mouse keys button state is shared with [PS/2 mouse](feature_ps2_mouse.md) and [pointing device](feature_pointing_device.md) so mouse keys button presses can be used for clicks and drags.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,13 @@ static void           mousekey_debug(void);
 | 
			
		|||
static uint8_t        mousekey_accel        = 0;
 | 
			
		||||
static uint8_t        mousekey_repeat       = 0;
 | 
			
		||||
static uint8_t        mousekey_wheel_repeat = 0;
 | 
			
		||||
#ifdef MOUSEKEY_INERTIA
 | 
			
		||||
static uint8_t mousekey_frame     = 0; // track whether gesture is inactive, first frame, or repeating
 | 
			
		||||
static int8_t  mousekey_x_dir     = 0; // -1 / 0 / 1 = left / neutral / right
 | 
			
		||||
static int8_t  mousekey_y_dir     = 0; // -1 / 0 / 0 = up / neutral / down
 | 
			
		||||
static int8_t  mousekey_x_inertia = 0; // current velocity, limit +/- MOUSEKEY_TIME_TO_MAX
 | 
			
		||||
static int8_t  mousekey_y_inertia = 0; // ...
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MK_KINETIC_SPEED
 | 
			
		||||
static uint16_t mouse_timer = 0;
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +83,7 @@ uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
 | 
			
		|||
 | 
			
		||||
#    ifndef MK_COMBINED
 | 
			
		||||
#        ifndef MK_KINETIC_SPEED
 | 
			
		||||
#            ifndef MOUSEKEY_INERTIA
 | 
			
		||||
 | 
			
		||||
/* Default accelerated mode */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +105,53 @@ static uint8_t move_unit(void) {
 | 
			
		|||
    return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#            else // MOUSEKEY_INERTIA mode
 | 
			
		||||
 | 
			
		||||
static int8_t move_unit(uint8_t axis) {
 | 
			
		||||
    int16_t unit;
 | 
			
		||||
 | 
			
		||||
    // handle X or Y axis
 | 
			
		||||
    int8_t inertia, dir;
 | 
			
		||||
    if (axis) {
 | 
			
		||||
        inertia = mousekey_y_inertia;
 | 
			
		||||
        dir     = mousekey_y_dir;
 | 
			
		||||
    } else {
 | 
			
		||||
        inertia = mousekey_x_inertia;
 | 
			
		||||
        dir     = mousekey_x_dir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mousekey_frame < 2) { // first frame(s): initial keypress moves one pixel
 | 
			
		||||
        mousekey_frame = 1;
 | 
			
		||||
        unit           = dir * MOUSEKEY_MOVE_DELTA;
 | 
			
		||||
    } else { // acceleration
 | 
			
		||||
        // linear acceleration (is here for reference, but doesn't feel as good during use)
 | 
			
		||||
        // unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * inertia) / mk_time_to_max;
 | 
			
		||||
 | 
			
		||||
        // x**2 acceleration (quadratic, more precise for short movements)
 | 
			
		||||
        int16_t percent = (inertia << 8) / mk_time_to_max;
 | 
			
		||||
        percent         = (percent * percent) >> 8;
 | 
			
		||||
        if (inertia < 0) percent = -percent;
 | 
			
		||||
 | 
			
		||||
        // unit = sign(inertia) + (percent of max speed)
 | 
			
		||||
        if (inertia > 0)
 | 
			
		||||
            unit = 1;
 | 
			
		||||
        else if (inertia < 0)
 | 
			
		||||
            unit = -1;
 | 
			
		||||
        else
 | 
			
		||||
            unit = 0;
 | 
			
		||||
 | 
			
		||||
        unit = unit + ((mk_max_speed * percent) >> 8);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (unit > MOUSEKEY_MOVE_MAX)
 | 
			
		||||
        unit = MOUSEKEY_MOVE_MAX;
 | 
			
		||||
    else if (unit < -MOUSEKEY_MOVE_MAX)
 | 
			
		||||
        unit = -MOUSEKEY_MOVE_MAX;
 | 
			
		||||
    return unit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#            endif // end MOUSEKEY_INERTIA mode
 | 
			
		||||
 | 
			
		||||
static uint8_t wheel_unit(void) {
 | 
			
		||||
    uint16_t unit;
 | 
			
		||||
    if (mousekey_accel & (1 << 0)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -213,6 +268,28 @@ static uint8_t wheel_unit(void) {
 | 
			
		|||
 | 
			
		||||
#    endif /* #ifndef MK_COMBINED */
 | 
			
		||||
 | 
			
		||||
#    ifdef MOUSEKEY_INERTIA
 | 
			
		||||
 | 
			
		||||
static int8_t calc_inertia(int8_t direction, int8_t velocity) {
 | 
			
		||||
    // simulate acceleration and deceleration
 | 
			
		||||
 | 
			
		||||
    // deceleration
 | 
			
		||||
    if ((direction > -1) && (velocity < 0))
 | 
			
		||||
        velocity = (velocity + 1) * (256 - MOUSEKEY_FRICTION) / 256;
 | 
			
		||||
    else if ((direction < 1) && (velocity > 0))
 | 
			
		||||
        velocity = velocity * (256 - MOUSEKEY_FRICTION) / 256;
 | 
			
		||||
 | 
			
		||||
    // acceleration
 | 
			
		||||
    if ((direction > 0) && (velocity < mk_time_to_max))
 | 
			
		||||
        velocity++;
 | 
			
		||||
    else if ((direction < 0) && (velocity > -mk_time_to_max))
 | 
			
		||||
        velocity--;
 | 
			
		||||
 | 
			
		||||
    return velocity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#    endif
 | 
			
		||||
 | 
			
		||||
void mousekey_task(void) {
 | 
			
		||||
    // report cursor and scroll movement independently
 | 
			
		||||
    report_mouse_t tmpmr = mouse_report;
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +299,32 @@ void mousekey_task(void) {
 | 
			
		|||
    mouse_report.v = 0;
 | 
			
		||||
    mouse_report.h = 0;
 | 
			
		||||
 | 
			
		||||
#    ifdef MOUSEKEY_INERTIA
 | 
			
		||||
 | 
			
		||||
    // if an animation is in progress and it's time for the next frame
 | 
			
		||||
    if ((mousekey_frame) && timer_elapsed(last_timer_c) > ((mousekey_frame > 1) ? mk_interval : mk_delay * 10)) {
 | 
			
		||||
        mousekey_x_inertia = calc_inertia(mousekey_x_dir, mousekey_x_inertia);
 | 
			
		||||
        mousekey_y_inertia = calc_inertia(mousekey_y_dir, mousekey_y_inertia);
 | 
			
		||||
 | 
			
		||||
        mouse_report.x = move_unit(0);
 | 
			
		||||
        mouse_report.y = move_unit(1);
 | 
			
		||||
 | 
			
		||||
        // prevent sticky "drift"
 | 
			
		||||
        if ((!mousekey_x_dir) && (!mousekey_x_inertia)) tmpmr.x = 0;
 | 
			
		||||
        if ((!mousekey_y_dir) && (!mousekey_y_inertia)) tmpmr.y = 0;
 | 
			
		||||
 | 
			
		||||
        if (mousekey_frame < 2) mousekey_frame++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // reset if not moving and no movement keys are held
 | 
			
		||||
    if ((!mousekey_x_dir) && (!mousekey_y_dir) && (!mousekey_x_inertia) && (!mousekey_y_inertia)) {
 | 
			
		||||
        mousekey_frame = 0;
 | 
			
		||||
        tmpmr.x        = 0;
 | 
			
		||||
        tmpmr.y        = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#    else // default acceleration
 | 
			
		||||
 | 
			
		||||
    if ((tmpmr.x || tmpmr.y) && timer_elapsed(last_timer_c) > (mousekey_repeat ? mk_interval : mk_delay * 10)) {
 | 
			
		||||
        if (mousekey_repeat != UINT8_MAX) mousekey_repeat++;
 | 
			
		||||
        if (tmpmr.x != 0) mouse_report.x = move_unit() * ((tmpmr.x > 0) ? 1 : -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -239,6 +342,9 @@ void mousekey_task(void) {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#    endif // MOUSEKEY_INERTIA or not
 | 
			
		||||
 | 
			
		||||
    if ((tmpmr.v || tmpmr.h) && timer_elapsed(last_timer_w) > (mousekey_wheel_repeat ? mk_wheel_interval : mk_wheel_delay * 10)) {
 | 
			
		||||
        if (mousekey_wheel_repeat != UINT8_MAX) mousekey_wheel_repeat++;
 | 
			
		||||
        if (tmpmr.v != 0) mouse_report.v = wheel_unit() * ((tmpmr.v > 0) ? 1 : -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -260,6 +366,7 @@ void mousekey_task(void) {
 | 
			
		|||
    if (has_mouse_report_changed(&mouse_report, &tmpmr) || should_mousekey_report_send(&mouse_report)) {
 | 
			
		||||
        mousekey_send();
 | 
			
		||||
    }
 | 
			
		||||
    // save the state for later
 | 
			
		||||
    memcpy(&mouse_report, &tmpmr, sizeof(tmpmr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -270,6 +377,19 @@ void mousekey_on(uint8_t code) {
 | 
			
		|||
    }
 | 
			
		||||
#    endif /* #ifdef MK_KINETIC_SPEED */
 | 
			
		||||
 | 
			
		||||
#    ifdef MOUSEKEY_INERTIA
 | 
			
		||||
 | 
			
		||||
    // initial keypress sets impulse and activates first frame of movement
 | 
			
		||||
    if ((code == KC_MS_UP) || (code == KC_MS_DOWN)) {
 | 
			
		||||
        mousekey_y_dir = (code == KC_MS_DOWN) ? 1 : -1;
 | 
			
		||||
        if (mousekey_frame < 2) mouse_report.y = move_unit(1);
 | 
			
		||||
    } else if ((code == KC_MS_LEFT) || (code == KC_MS_RIGHT)) {
 | 
			
		||||
        mousekey_x_dir = (code == KC_MS_RIGHT) ? 1 : -1;
 | 
			
		||||
        if (mousekey_frame < 2) mouse_report.x = move_unit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#    else // no inertia
 | 
			
		||||
 | 
			
		||||
    if (code == KC_MS_UP)
 | 
			
		||||
        mouse_report.y = move_unit() * -1;
 | 
			
		||||
    else if (code == KC_MS_DOWN)
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +398,9 @@ void mousekey_on(uint8_t code) {
 | 
			
		|||
        mouse_report.x = move_unit() * -1;
 | 
			
		||||
    else if (code == KC_MS_RIGHT)
 | 
			
		||||
        mouse_report.x = move_unit();
 | 
			
		||||
 | 
			
		||||
#    endif // inertia or not
 | 
			
		||||
 | 
			
		||||
    else if (code == KC_MS_WH_UP)
 | 
			
		||||
        mouse_report.v = wheel_unit();
 | 
			
		||||
    else if (code == KC_MS_WH_DOWN)
 | 
			
		||||
| 
						 | 
				
			
			@ -297,6 +420,20 @@ void mousekey_on(uint8_t code) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void mousekey_off(uint8_t code) {
 | 
			
		||||
#    ifdef MOUSEKEY_INERTIA
 | 
			
		||||
 | 
			
		||||
    // key release clears impulse unless opposite direction is held
 | 
			
		||||
    if ((code == KC_MS_UP) && (mousekey_y_dir < 1))
 | 
			
		||||
        mousekey_y_dir = 0;
 | 
			
		||||
    else if ((code == KC_MS_DOWN) && (mousekey_y_dir > -1))
 | 
			
		||||
        mousekey_y_dir = 0;
 | 
			
		||||
    else if ((code == KC_MS_LEFT) && (mousekey_x_dir < 1))
 | 
			
		||||
        mousekey_x_dir = 0;
 | 
			
		||||
    else if ((code == KC_MS_RIGHT) && (mousekey_x_dir > -1))
 | 
			
		||||
        mousekey_x_dir = 0;
 | 
			
		||||
 | 
			
		||||
#    else // no inertia
 | 
			
		||||
 | 
			
		||||
    if (code == KC_MS_UP && mouse_report.y < 0)
 | 
			
		||||
        mouse_report.y = 0;
 | 
			
		||||
    else if (code == KC_MS_DOWN && mouse_report.y > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -305,6 +442,9 @@ void mousekey_off(uint8_t code) {
 | 
			
		|||
        mouse_report.x = 0;
 | 
			
		||||
    else if (code == KC_MS_RIGHT && mouse_report.x > 0)
 | 
			
		||||
        mouse_report.x = 0;
 | 
			
		||||
 | 
			
		||||
#    endif // inertia or not
 | 
			
		||||
 | 
			
		||||
    else if (code == KC_MS_WH_UP && mouse_report.v > 0)
 | 
			
		||||
        mouse_report.v = 0;
 | 
			
		||||
    else if (code == KC_MS_WH_DOWN && mouse_report.v < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -476,6 +616,13 @@ void mousekey_clear(void) {
 | 
			
		|||
    mousekey_repeat       = 0;
 | 
			
		||||
    mousekey_wheel_repeat = 0;
 | 
			
		||||
    mousekey_accel        = 0;
 | 
			
		||||
#ifdef MOUSEKEY_INERTIA
 | 
			
		||||
    mousekey_frame     = 0;
 | 
			
		||||
    mousekey_x_inertia = 0;
 | 
			
		||||
    mousekey_y_inertia = 0;
 | 
			
		||||
    mousekey_x_dir     = 0;
 | 
			
		||||
    mousekey_y_dir     = 0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mousekey_debug(void) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,35 +36,49 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#    endif
 | 
			
		||||
 | 
			
		||||
#    ifndef MOUSEKEY_MOVE_DELTA
 | 
			
		||||
#        ifndef MK_KINETIC_SPEED
 | 
			
		||||
#            define MOUSEKEY_MOVE_DELTA 8
 | 
			
		||||
#        else
 | 
			
		||||
#        if defined(MK_KINETIC_SPEED)
 | 
			
		||||
#            define MOUSEKEY_MOVE_DELTA 16
 | 
			
		||||
#        elif defined(MOUSEKEY_INERTIA)
 | 
			
		||||
#            define MOUSEKEY_MOVE_DELTA 1
 | 
			
		||||
#        else
 | 
			
		||||
#            define MOUSEKEY_MOVE_DELTA 8
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_WHEEL_DELTA
 | 
			
		||||
#        define MOUSEKEY_WHEEL_DELTA 1
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_DELAY
 | 
			
		||||
#        ifndef MK_KINETIC_SPEED
 | 
			
		||||
#            define MOUSEKEY_DELAY 10
 | 
			
		||||
#        else
 | 
			
		||||
#        if defined(MK_KINETIC_SPEED)
 | 
			
		||||
#            define MOUSEKEY_DELAY 5
 | 
			
		||||
#        elif defined(MOUSEKEY_INERTIA)
 | 
			
		||||
#            define MOUSEKEY_DELAY 150 // allow single-pixel movements before repeat activates
 | 
			
		||||
#        else
 | 
			
		||||
#            define MOUSEKEY_DELAY 10
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_INTERVAL
 | 
			
		||||
#        ifndef MK_KINETIC_SPEED
 | 
			
		||||
#            define MOUSEKEY_INTERVAL 20
 | 
			
		||||
#        else
 | 
			
		||||
#        if defined(MK_KINETIC_SPEED)
 | 
			
		||||
#            define MOUSEKEY_INTERVAL 10
 | 
			
		||||
#        elif defined(MOUSEKEY_INERTIA)
 | 
			
		||||
#            define MOUSEKEY_INTERVAL 16 // 60 fps
 | 
			
		||||
#        else
 | 
			
		||||
#            define MOUSEKEY_INTERVAL 20
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_MAX_SPEED
 | 
			
		||||
#        if defined(MOUSEKEY_INERTIA)
 | 
			
		||||
#            define MOUSEKEY_MAX_SPEED 32
 | 
			
		||||
#        else
 | 
			
		||||
#            define MOUSEKEY_MAX_SPEED 10
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_TIME_TO_MAX
 | 
			
		||||
#        if defined(MOUSEKEY_INERTIA)
 | 
			
		||||
#            define MOUSEKEY_TIME_TO_MAX 32
 | 
			
		||||
#        else
 | 
			
		||||
#            define MOUSEKEY_TIME_TO_MAX 30
 | 
			
		||||
#        endif
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_WHEEL_DELAY
 | 
			
		||||
#        define MOUSEKEY_WHEEL_DELAY 10
 | 
			
		||||
#    endif
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +92,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#        define MOUSEKEY_WHEEL_TIME_TO_MAX 40
 | 
			
		||||
#    endif
 | 
			
		||||
 | 
			
		||||
#    ifndef MOUSEKEY_FRICTION
 | 
			
		||||
#        define MOUSEKEY_FRICTION 24 // 0 to 255
 | 
			
		||||
#    endif
 | 
			
		||||
#    ifndef MOUSEKEY_INITIAL_SPEED
 | 
			
		||||
#        define MOUSEKEY_INITIAL_SPEED 100
 | 
			
		||||
#    endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue