Skip to content

Instantly share code, notes, and snippets.

@krissen
Last active December 30, 2024 23:47
Show Gist options
  • Save krissen/dd27082e7ab0575619c7a31f4d2ec7ae to your computer and use it in GitHub Desktop.
Save krissen/dd27082e7ab0575619c7a31f4d2ec7ae to your computer and use it in GitHub Desktop.

Edit 2024-12-18:

Support for mouse emulation has now been implemented. See https://zmk.dev/docs/keymaps/behaviors/mouse-emulation

The instructions below are outdated.

Outdated instructions. Do ignore. Edit 2024-02-05:

The instructions below are outdated.

There is an official PR (#2027) for mouse functionality. You should use that rather than what is described below.

See comments [1, 2] below.

ZMK mouse support

When looking to add mouse support, I originally found instructions for how to go about it on Reddit. I was later pointed out to this message on the ZMK Discord (invite).

Repository with mouse support: FTC.

Documentation for for beta testing, including how to make a build off of a different repo such as the one mentioned above. Some documentation about mouse support found here; can be complemented by looking at the source code, here.

EDIT 2022-12-10: Added additional configuration options for scroll wheel speed tweaks.
EDIT 2022-12-09: Added additional configuration options which can be used to tweak mouse movement speed.

How-to

Step one, use the custom repository mentioned above in config/west.yml:

manifest:
  remotes:
    - name: zmkfirmware
      url-base: https://github.com/ftc/     # <--- CHANGE REPO
  projects:
    - name: zmk
      remote: zmkfirmware
      revision: mouse-ftc                   # <--- CHANGE REVISION
      import: app/west.yml
  self:
    path: config

Step 2, add necessary config line in config/YOURBOARD.conf:

CONFIG_ZMK_SLEEP=y
CONFIG_ZMK_MOUSE=y                          /* <--- ADD MOUSE SUPPORT */

Step 3, add support in the keyboard layout, config/YOURBOARD.keymap:

a) Necessary include in the header:

#include <dt-bindings/zmk/mouse.h>

b) Binds, like for instance:

&mkp LCLK       &mkp RCLK
&mmv MOVE_UP    &mmv MOVE_DOWN
&mmv MOVE_LEFT  &mmv MOVE_RIGHT

Step 4, build it; install on the board.

Step 5, unpair and repair the keyboard for it to be recognised as a pointer device as well.

Additional, optional configuration

To adjust mouse movement speed, the following can be used in config/YOURBOARD.keymap, before the keymap {}.

#define U_MOUSE_MOVE_MAX 1400                     /* <--- New max speed setting (default: 600) */
#undef MOVE_UP
#undef MOVE_DOWN
#undef MOVE_LEFT
#undef MOVE_RIGHT
#define MOVE_UP MOVE_VERT(-U_MOUSE_MOVE_MAX)
#define MOVE_DOWN MOVE_VERT(U_MOUSE_MOVE_MAX)
#define MOVE_LEFT MOVE_HOR(-U_MOUSE_MOVE_MAX)
#define MOVE_RIGHT MOVE_HOR(U_MOUSE_MOVE_MAX)

&mmv {
	time-to-max-speed-ms = <400>;             /* <--- How long time until max speed is reached (default: 500) */
};

To adjust scroll wheel, use something like the following:

#define U_MOUSE_SCROLL_MAX 100                    /* <--- New max speed setting (default: 10) */

#undef SCROLL_UP
#undef SCROLL_DOWN
#undef SCROLL_LEFT
#undef SCROLL_RIGHT
#define SCROLL_UP SCROLL_VERT(U_MOUSE_SCROLL_MAX)
#define SCROLL_DOWN SCROLL_VERT(-U_MOUSE_SCROLL_MAX)
#define SCROLL_LEFT SCROLL_HOR(-U_MOUSE_SCROLL_MAX)
#define SCROLL_RIGHT SCROLL_HOR(U_MOUSE_SCROLL_MAX)

&mwh {
  time-to-max-speed-ms = <500>;                 /* <--- How long time until max speed is reached */
};
						</details>
@hugomaiavieira
Copy link

Thank you again @caksoylar!

@dee-tree it worked perfectly for me!

I have a layer for the mouse and three layers for changing the speed, which I trigger with a &mo for each speed layer on the mouse layer.

You can check the code here.
#include <input/processors.dtsi>
#include <dt-bindings/zmk/pointing.h>

#define ZMK_POINTING_DEFAULT_MOVE_VAL 1000  // default: 600
#define ZMK_POINTING_DEFAULT_SCRL_VAL 80    // default: 10

// Layer aliases
#define MOUSE 7
#define MOUSEFAST 8
#define MOUSESLOW 9
#define MOUSEXSLOW 10

&mmv {
    time-to-max-speed-ms = <120>;
    acceleration-exponent = <6>;
};

&msc {
    time-to-max-speed-ms = <80>;
    acceleration-exponent = <10>;
};

&mmv_input_listener {
    set_mouse_fast {
        layers = <MOUSEFAST>;
        input-processors = <&zip_xy_scaler 2 1>;
    };
};

&mmv_input_listener {
    set_mouse_slow {
        layers = <MOUSESLOW>;
        input-processors = <&zip_xy_scaler 1 2>;
    };
};

&mmv_input_listener {
    set_mouse_extra_slow {
        layers = <MOUSEXSLOW>;
        input-processors = <&zip_xy_scaler 1 4>;
    };
};

# other things...

/ {
    keymap {
        compatible = "zmk,keymap";

        # other layers...

        MOUSE {
            bindings = <
&none  &kp LEFT_SHIFT  &kp LEFT_GUI  &kp LEFT_ALT  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &mo 8           &mo 9         &mo 10        &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none           &none         &none         &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                                     &none         &none    &none           &mkp LCLK
            >;
        };

        MOUSEFAST {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };

        MOUSESLOW {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };

        MOUSEXSLOW {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };
    };
};

I still need to refactor it (use the aliases on &mo; I guess the speed layers could be &trans, etc) and fine tune the speed, but it is working pretty well! πŸŽ‰

I tried to do the same for the scroll movement (click to see the code), but it didn't work (but I did read the docs yet about it).
&msc_input_listener {
    set_mouse_extra_slow {
        layers = <MOUSEXSLOW>;
        input-processors = <&zip_xy_scaler 1 4>;
    };
};

When I have some extra time I will check that as well πŸ™‚

@dee-tree
Copy link

Thank you again @caksoylar!

@dee-tree it worked perfectly for me!

I have a layer for the mouse and three layers for changing the speed, which I trigger with a &mo for each speed layer on the mouse layer.

You can check the code here.

#include <input/processors.dtsi>
#include <dt-bindings/zmk/pointing.h>

#define ZMK_POINTING_DEFAULT_MOVE_VAL 1000  // default: 600
#define ZMK_POINTING_DEFAULT_SCRL_VAL 80    // default: 10

// Layer aliases
#define MOUSE 7
#define MOUSEFAST 8
#define MOUSESLOW 9
#define MOUSEXSLOW 10

&mmv {
    time-to-max-speed-ms = <120>;
    acceleration-exponent = <6>;
};

&msc {
    time-to-max-speed-ms = <80>;
    acceleration-exponent = <10>;
};

&mmv_input_listener {
    set_mouse_fast {
        layers = <MOUSEFAST>;
        input-processors = <&zip_xy_scaler 2 1>;
    };
};

&mmv_input_listener {
    set_mouse_slow {
        layers = <MOUSESLOW>;
        input-processors = <&zip_xy_scaler 1 2>;
    };
};

&mmv_input_listener {
    set_mouse_extra_slow {
        layers = <MOUSEXSLOW>;
        input-processors = <&zip_xy_scaler 1 4>;
    };
};

# other things...

/ {
    keymap {
        compatible = "zmk,keymap";

        # other layers...

        MOUSE {
            bindings = <
&none  &kp LEFT_SHIFT  &kp LEFT_GUI  &kp LEFT_ALT  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &mo 8           &mo 9         &mo 10        &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none           &none         &none         &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                                     &none         &none    &none           &mkp LCLK
            >;
        };

        MOUSEFAST {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };

        MOUSESLOW {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };

        MOUSEXSLOW {
            bindings = <
&none  &none  &none  &none  &none    &none           &none           &mmv MOVE_UP    &none            &none
&none  &none  &none  &none  &none    &msc SCRL_UP    &mmv MOVE_LEFT  &mmv MOVE_DOWN  &mmv MOVE_RIGHT  &mkp RCLK
&none  &none  &none  &none  &none    &msc SCRL_DOWN  &msc SCRL_LEFT  &mkp MCLK       &msc SCRL_RIGHT  &none
                     &none  &none    &none           &mkp LCLK
            >;
        };
    };
};

I still need to refactor it (use the aliases on &mo; I guess the speed layers could be &trans, etc) and fine tune the speed, but it is working pretty well! πŸŽ‰

I tried to do the same for the scroll movement (click to see the code), but it didn't work (but I did read the docs yet about it).

&msc_input_listener {
    set_mouse_extra_slow {
        layers = <MOUSEXSLOW>;
        input-processors = <&zip_xy_scaler 1 4>;
    };
};

When I have some extra time I will check that as well πŸ™‚

It's an idea! Hope these extra layers will not take too much memory. Thanks for your sources, I will try it.
Relating to mouse scroll speed, have you tried to assign a different layer for it?

@caksoylar
Copy link

I have not, no. But I haven't felt the need yet, but a layer that speeds it up might be nice. I could probably use the same layer I use for move precision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment