MAKCU API

KM Host Protocol — v3.9 · Comprehensive command reference for the MAKCU ecosystem.

Legacy API (ASCII)

All replies start with km. and end withCRLF followed by the prompt>>> .
TX samples below show the final prompt as\r\n>>> .
RX (Host → Device)
  • Command format: Start with . and end with ). The km. prefix is no longer required.
  • Other values (such as km, \r\n, etc.) are ignored. Example: .move(1,1,)
  • Optional binary frame: DE AD <lenLE:2> <ASCII or binary payload>
TX (Device → Host)
  • Format: km.payload\r\n>>> (the km. prefix is retained for compatibility)
  • Setters echo the input as ACK unless suppressed byecho(0).
  • Some streaming replies carry binary after the km. prefix:km.mouse<8 bytes> andkm.buttons<1-byte mask>. Lines still terminate with CRLF and the prompt.

Mouse

Individual Buttons (GET/SET)

Command
left([state]) | right([state]) | middle([state]) | side1([state]) | side2([state])
Params
state: 0=release (sends frame), 1=down, 2=silent_release (sets to 0 but doesn't send frame)
Response (GET)
km.left()
>>> 

Returns lock state: 0=none, 1=raw, 2=injected, 3=both.

Response (SET)
km.left(1)
>>> 

Echo ACK (subject to echo(0|1)).

Click Scheduling (SET)

Command
click(button[,count[,delay_ms]])
Params
button: button number; count: click count (optional); delay_ms: delay (optional, defaults to random 35-75ms, internal timing)
Response (SET)
km.click(1,3)
>>> 

Echo ACK.

turbo([button[,delay_ms]]) — GET/SET

Command
turbo([button[,delay_ms]])
Description

Enable rapid-fire mode for mouse buttons. When the button is held down, it automatically triggers rapid press/release cycles at the specified interval. Multiple buttons can have turbo enabled simultaneously, each with its own delay setting.

Params
  • button: 1-5 (mouse buttons: 1=left, 2=right, 3=middle, 4=side1, 5=side2), 0=disable all turbo
  • delay_ms: 1-5000ms (0=disable). If omitted, uses random 35-75ms. The delay is the time between each press/release toggle (e.g., 500ms = press for 500ms, release for 500ms, repeat)
  • Delay is automatically rounded to the mouse endpoint's bInterval for USB synchronization
  • turbo() - Returns only active turbo settings as (m1=200, m2=400) (only shows what's set, not zeros)
  • turbo(button) - Sets turbo with random 35-75ms delay (auto-rounded to bInterval)
  • turbo(button, delay_ms) - Sets turbo with specified delay (auto-rounded to bInterval)
  • turbo(button, 0) - Disables turbo for that specific button
  • turbo(0) - Disables all turbo
Examples
km.turbo(1, 500)
>>> 
km.turbo(2, 250)
>>> 
km.turbo(1)
>>> 
km.turbo()
>>> 

Mouse Movement

move(dx,dy[,segments[,cx1,cy1[,cx2,cy2]]]) — SET

Command
move(dx,dy[,segments[,cx1,cy1[,cx2,cy2]]])
Params

dx,dy: relative move distance; segments: segment count (optional, default 1, max 512); cx1,cy1,cx2,cy2: cubic Bézier control points (optional)

Response (SET)
km.move(10,-3)
>>> 
km.move(100,50,8,40,25,80,10)
>>> 

Echo ACK.

moveto(x,y[,segments[,cx1,cy1[,cx2,cy2]]]) — SET

Command
moveto(x,y[,segments[,cx1,cy1[,cx2,cy2]]])
Description

Move pointer to absolute position. Internally calculates the needed x,y movement to reach the requested position on the screen. Parameters align with km.move().

Params

x,y: absolute coordinates; segments: segment count (optional, default 1, max 512); cx1,cy1,cx2,cy2: cubic Bézier control points (optional)

Response (SET)
km.moveto(640,360)
>>> 
km.moveto(100,50,8,40,25,80,10)
>>> 

Echo ACK.

wheel(delta) — SET

Command
wheel(delta)
Description

Windows does not allow multiple scroll steps in a single command. The delta value is clamped to ±1 step (positive for scroll up, negative for scroll down). Values greater than 1 are treated as 1, values less than -1 are treated as -1.

Params
delta: scroll step (clamped to ±1)
Response (SET)
km.wheel(-1)
>>> 
km.wheel(1)
>>> 

Echo ACK. Note: km.wheel(-5) will only scroll down 1 step, km.wheel(5) will only scroll up 1 step.

pan([steps]) — GET/SET

Command
pan([steps])
Params
steps: horizontal scroll steps (SET); no params to query pending (GET)
Response
km.pan(3)
>>> 

tilt([steps]) — GET/SET

Command
tilt([steps])
Params
steps: tilt/z-axis scroll steps (SET); no params to query pending (GET)
Response
km.tilt(2)
>>> 

getpos() — GET

Command
getpos()
Response (GET)
km.getpos()
>>> km.getpos(123,456)
>>> 

Returns current pointer position as (x,y).

silent(x,y) — SET

Command
silent(x,y)
Params
Move then perform silent left click at (x,y)
Response (SET)
km.silent(400,300)
>>> 

Echo ACK.

Mouse Advanced

mo(buttons,x,y,wheel,pan,tilt) — SET

Command
mo(buttons,x,y,wheel,pan,tilt)
Description

Send complete raw mouse frame (SET only, no GET). (0) clears all; x,y,wheel,pan,tilt are one-shots; button mask mirrors button states.

Params
buttons: button mask; x,y: movement deltas; wheel,pan,tilt: scroll values
Response (SET)
km.mo(1,10,5,0,0,0)
>>> 

lock_<target>(state) — GET/SET

Command Format
lock_<target>([state])
Description

Lock button or axis. The target is part of the command name, not a parameter. state: 1=lock, 0=unlock. Call with `()` to read lock state.

Targets

Buttons: ml/mm/mr/ms1/ms2

  • ml - Left mouse button
  • mm - Middle mouse button
  • mr - Right mouse button
  • ms1 - Side button 1
  • ms2 - Side button 2

Axes: mx/my/mw/mx+/mx-/my+/my-/mw+/mw-

  • mx/my/mw - Full lock (blocks all movement in that axis)
  • mx+/my+/mw+ - Positive direction lock (blocks positive movement only)
  • mx-/my-/mw- - Negative direction lock (blocks negative movement only)
Response (GET)
km.lock_mx()
>>> km.lock_mx(1)
>>> 

Returns: 1=locked, 0=unlocked

Response (SET)
km.lock_mx(1)
>>> 

Lock all X-axis movement

km.lock_mx+(1)
>>> 

Lock only positive X movement (right)

km.lock_mx-(1)
>>> 

Lock only negative X movement (left)

km.lock_my(1)
>>> 

Lock all Y-axis movement

km.lock_mw(1)
>>> 

Lock all wheel movement

km.lock_mw+(1)
>>> 

Lock only positive wheel movement (scroll up)

km.lock_mw-(1)
>>> 

Lock only negative wheel movement (scroll down)

km.lock_ml(1)
>>> 

Lock left mouse button

catch_<target>(mode) — GET/SET

Command Format
catch_<target>([mode])
Description

Enable catch on a locked button. The target is part of the command name, not a parameter. Note: Catch only works for buttons, not axes. Requires corresponding km.lock_<target> to be set first.

Targets
ml, mm, mr, ms1, ms2 (buttons only, not axes)
Params
mode: 0=auto, 1=manual; () returns state
Response (GET)
km.catch_ml()
>>> 

Use `()` to query catch state

Response (SET)
km.catch_ml(1)
>>> 

Enable manual catch for left mouse button

km.catch_ml(0)
>>> 

Enable auto catch for left mouse button

Mouse Remap (Physical)

The following commands only affect physical input, injection is NOT affected. This means you can remap physical mouse buttons and axes, while injected inputs via API will remain unchanged.

remap_button([src,dst]) — GET/SET

Command
remap_button([src,dst])
Description

Remap mouse buttons (physical only). Auto-clears conflicting mappings; both directions can be mapped (swap).

Params
  • () - Show only active mappings, e.g., (left:right,right:left)
  • (0) - Reset all button remaps
  • (src,dst) - Map button src→dst (1=left, 2=right, 3=middle, 4=side1, 5=side2)
  • (src,0) - Clear remap for button src
Examples
km.remap_button()
>>> 
km.remap_button(1,2)
>>> 
km.remap_button(0)
>>> 

remap_axis([inv_x,inv_y,swap]) — GET/SET

Command
remap_axis([inv_x,inv_y,swap])
Description

Remap mouse axes (physical only). Set all three flags at once.

Params
  • () - Show current settings, e.g., (invert_x=0,invert_y=1,swap_xy=0)
  • (0) - Reset all axis remaps
  • (inv_x,inv_y,swap) - Set all three flags (0 or 1)
Examples
km.remap_axis()
>>> 
km.remap_axis(0,1,0)
>>> 
km.remap_axis(0)
>>> 

invert_x([state]) — GET/SET

Command
invert_x([state])
Description
Invert X axis (physical only)
Params
() show; (0) disable; (1) enable
Response
km.invert_x(1)
>>> 

invert_y([state]) — GET/SET

Command
invert_y([state])
Description
Invert Y axis (physical only)
Params
() show; (0) disable; (1) enable
Response
km.invert_y(1)
>>> 

swap_xy([state]) — GET/SET

Command
swap_xy([state])
Description
Swap X and Y axes (physical only)
Params
() show; (0) disable; (1) enable
Response
km.swap_xy(1)
>>> 

Keyboard Commands

Keyboard commands support two formats: numeric HID code (e.g., 4) or string key name (e.g., 'a', "enter"). Supported key names include letters, numbers, function keys, navigation keys, and modifiers. See specification for details.

down(key) — SET

Command
down(key)
Params
key: HID code or quoted string ('a', "shift")
Response (SET)
km.down('shift')
>>> 

up(key) — SET

Command
up(key)
Params
key: HID code or quoted string ('a', "ctrl")
Response (SET)
km.up("ctrl")
>>> 

press(key[,hold_ms[,rand_ms]]) — SET

Command
press(key[,hold_ms[,rand_ms]])
Params
  • key: HID code (0-255) or quoted key name
  • hold_ms: Optional hold duration in milliseconds. If omitted, uses random 35-75ms (value is logged)
  • rand_ms: Optional randomization range added to hold_ms (0 = no randomization)
  • Note: Duration is automatically rounded to the keyboard's bInterval for USB synchronization
Examples
km.press('a')
>>> 

Press 'a' with random 35-75ms hold (logged)

km.press('d', 50)
>>> 

Press 'd' with exactly 50ms hold

km.press('d', 50, 10)
>>> 

Press 'd' with 50ms base + random 0-10ms

string(text) — SET

Command
string(text)
Description

Type an ASCII string using queued key presses with automatic timing. Automatically handles Shift for uppercase letters and symbols. Uses timed queue system (no timer slot limits).

Params
  • text: ASCII string to type (max 256 characters)
  • Each character uses random 35-75ms hold time (internal timing, not logged)
  • Inter-character delay: 10ms between characters
Examples
km.string("Hello")
>>> 
km.string("Test123!")
>>> 
Response (SET)
km.string("hello")
>>> 

init() — SET

Command
init()
Description
Clear keyboard state and release pressed keys
Response (SET)
km.init()
>>> 

isdown(key) — GET

Command
isdown(key)
Params
key: HID code or quoted string ('a', "shift")
Response (GET)
km.isdown("ctrl")
>>> km.isdown(1)
>>> 

Returns 1 if key is down, 0 if released.

disable([key1,key2,...] | [key,mode]) — GET/SET

Command
disable([key1,key2,...] | [key,mode])
Description

Disable/enable keyboard keys to block them from being sent to the host.

Params
  • () - List all currently disabled keys in format (a,c,f,) (shows key names when available, HID codes otherwise)
  • (key1,key2,...) - Disable multiple keys at once. Keys can be HID codes or quoted key names (e.g., 'a', 'f1', 'ctrl')
  • (key,mode) - Enable or disable a single key. mode: 1=disable, 0=enable
Examples
km.disable()
>>> km.disable(a,c,f,)
>>> 
km.disable('a','c','f')
>>> 
km.disable('f1','alt','win')
>>> 
km.disable('a', 0)
>>> 
km.disable('a', 1)
>>> 
km.disable(4,6,9)
>>> 

mask(key[,mode]) — GET/SET

Command
mask(key[,mode])
Params
key: HID code or quoted string; mode: 0=off, 1=on
Response
km.mask('a',1)
>>> 

remap(source,target) — GET/SET

Command
remap(source,target)
Params
source,target: both can be HID code or quoted string; target=0 clears remap (passthrough)
Examples
km.remap('a','b')
>>> 
km.remap('a',0)
>>> 

Complete Keyboard Key Reference

Single character letters are case-sensitive ('a' types lowercase, 'A' types uppercase). Multi-character special keys are case-insensitive ('f1', 'F1', 'ctrl', 'CTRL' all work the same).
Command
press(key)
Description

Complete keyboard key reference table. All keys support HID codes or string names. Single character letters are case-sensitive (lowercase types lowercase, uppercase automatically uses Shift to type uppercase). Multi-character special keys are case-insensitive.

Letters (HID 4-29)
Key NamesHIDNormal OutputShift Output
'a'4aA
'b'5bB
'c'6cC
'd'7dD
'e'8eE
'f'9fF
'g'10gG
'h'11hH
'i'12iI
'j'13jJ
'k'14kK
'l'15lL
'm'16mM
'n'17nN
'o'18oO
'p'19pP
'q'20qQ
'r'21rR
's'22sS
't'23tT
'u'24uU
'v'25vV
'w'26wW
'x'27xX
'y'28yY
'z'29zZ
Response
km.press('a')      # types "a" (HID 4)
km.press('A')      # types "A" (HID 4 + Shift)
Numbers & Shift Variants (HID 30-39)
Key NamesHIDNormal OutputShift Output
'1'301!
'2'312@
'3'323#
'4'334$
'5'345%
'6'356^
'7'367&
'8'378*
'9'389(
'0'390)
Response
km.press('1')      # types "1" (HID 30)
km.down('shift')
km.press('1')      # types "!" (HID 30 + Shift)
km.up('shift')
Control Keys (HID 40-44)
Key NamesHIDNormal OutputShift Output
'enter', 'return'40Enter-
'escape', 'esc'41Escape-
'backspace', 'back'42Backspace-
'tab'43Tab-
'space', 'spacebar'44 -
Response
km.press('enter')  # Enter key (HID 40)
Symbols & Shift Variants (HID 45-57)
Key NamesHIDNormal OutputShift Output
'minus', 'dash', 'hyphen'45-_
'equals', 'equal'46=+
'leftbracket', 'lbracket', 'openbracket'47[{
'rightbracket', 'rbracket', 'closebracket'48]}
'backslash', 'bslash'49\|
'nonus_hash'50#-
'semicolon', 'semi'51;:
'quote', 'apostrophe', 'singlequote'52'"
'grave', 'backtick', 'tilde'53`~
'comma'54,<
'period', 'dot'55.>
'slash', 'forwardslash', 'fslash'56/?
'capslock', 'caps'57Caps Lock-
Response
km.press('minus')  # types "-" (HID 45)
km.down('shift')
km.press('minus')  # types "_" (HID 45 + Shift)
km.up('shift')
Function Keys (HID 58-69)
Key NamesHIDNormal OutputShift Output
'f1'58F1-
'f2'59F2-
'f3'60F3-
'f4'61F4-
'f5'62F5-
'f6'63F6-
'f7'64F7-
'f8'65F8-
'f9'66F9-
'f10'67F10-
'f11'68F11-
'f12'69F12-
Response
km.press('f1')     # F1 key (HID 58)
System Keys (HID 70-83)
Key NamesHIDNormal OutputShift Output
'printscreen', 'prtsc', 'print'70Print Screen-
'scrolllock', 'scroll'71Scroll Lock-
'pause', 'break'72Pause/Break-
'insert', 'ins'73Insert-
'home'74Home-
'pageup', 'pgup'75Page Up-
'delete', 'del'76Delete-
'end'77End-
'pagedown', 'pgdown', 'pgdn'78Page Down-
'right', 'rightarrow'79Right Arrow-
'left', 'leftarrow'80Left Arrow-
'down', 'downarrow'81Down Arrow-
'up', 'uparrow'82Up Arrow-
'numlock', 'num'83Num Lock-
Response
km.press('home')   # Home key (HID 74)
Numpad Keys (HID 84-99)
Key NamesHIDNormal OutputShift Output
'kpdivide', 'npdivide'84/-
'kpmultiply', 'npmultiply'85*-
'kpminus', 'npminus'86--
'kpplus', 'npplus'87+-
'kpenter', 'npenter'88Enter-
'kp1', 'np1'891-
'kp2', 'np2'902-
'kp3', 'np3'913-
'kp4', 'np4'924-
'kp5', 'np5'935-
'kp6', 'np6'946-
'kp7', 'np7'957-
'kp8', 'np8'968-
'kp9', 'np9'979-
'kp0', 'np0'980-
'kpperiod', 'kpdot', 'npperiod', 'npdot'99.-
Response
km.press('kp1')    # Numpad 1 (HID 89)
Modifier Keys (HID 224-231)
Key Names (aliases)HIDNormal OutputShift Output
'leftctrl', 'lctrl', 'leftcontrol', 'lcontrol', 'ctrl', 'control'224Left Ctrl-
'leftshift', 'lshift', 'shift'225Left Shift-
'leftalt', 'lalt', 'alt'226Left Alt-
'leftgui', 'lgui', 'leftwin', 'lwin', 'gui', 'win', 'windows', 'super', 'meta', 'cmd', 'command'227Left GUI-
'rightctrl', 'rctrl', 'rightcontrol', 'rcontrol'228Right Ctrl-
'rightshift', 'rshift'229Right Shift-
'rightalt', 'ralt'230Right Alt-
'rightgui', 'rgui', 'rightwin', 'rwin', 'rightwindows'231Right GUI-

Note: Generic names ('ctrl', 'shift', 'alt', 'gui') default to the left variant

Response
km.down('ctrl')    # Left Ctrl (HID 224)
km.up('ctrl')

Streaming

keyboard([mode[,period]]) — GET/SET

Command
keyboard([mode[,period]])
Description

Stream keyboard keys with human-readable names. Mode 1=raw (physical input), 2=constructed frame (after remapping/masking); period clamped 1-1000 frames.

Params
mode: 1=raw, 2=constructed frame; period: 1-1000 frames; () to query; (0) to disable
Output Format

Output format: keyboard(raw,shift,'h') or keyboard(constructed,ctrl,shift,'a') - modifiers and keys shown as names (e.g., 'shift', 'ctrl', 'h', 'a') instead of HID numbers.

Response (GET)
km.keyboard(2,50)
>>> 
Response (SET)
km.keyboard(1,100)
>>> 

buttons([mode[,period_ms]]) — GET/SET

Command
buttons([mode[,period_ms]])
Params
1=raw, 2=constructed frame; time_ms: 1-1000ms; (0) or (0,0) to reset
Response (GET)
km.buttons(2,25)
>>> 
Response (SET)
km.buttons(1,10)
>>> 

When enabled, device emits 1-byte mask:

km.buttons<mask_u8>
>>> 

axis([mode[,period_ms]]) — GET/SET

Command
axis([mode[,period_ms]])
Params
1=raw, 2=constructed frame; period_ms: 1-1000ms; (0) or (0,0) to reset
Output Format

Output format: raw(x,y,w) or mut(x,y,w) where w is the wheel delta.

Response (GET)
km.axis(1,25)
>>> 
Response (SET)
km.axis(2,10)
>>> 

mouse([mode[,period_ms]]) — GET/SET

Command
mouse([mode[,period_ms]])
Modes
1=raw, 2=constructed frame; period_ms: 1-1000ms; () to query; (0) or (0,0) to reset
Response (GET)
km.mouse(2,25)
>>> 
Response (SET)
km.mouse(1,10)
>>> 
Streaming format

Device emits 8-byte binary frame (x,y as int16):

km.mouse<8 bytes>
>>> 

Misc

help() — GET

Command
help()
Description
Show command list
Response (GET)
km.help()
>>> 

info() — GET

Command
info()
Description
Report system info: MAC address, MCU temperature (when available), RAM stats, firmware info, CPU, and uptime
Response (GET)
km.info()
>>> 

version() — GET

Command
version()
Description
Report firmware version
Response (GET)
km.version()
>>> 

device() — GET

Command
device()
Description
Report which device is used more: (keyboard), (mouse), or (none)
Response (GET)
km.device()
>>> 

fault() — GET

Command
fault()
Description

Returns stored parse fault information including ESP32 MAC address, failed endpoint address, interface number, failure reason, and raw HID descriptor bytes. Useful for debugging devices that fail to parse.

Response (GET)
km.fault()
>>> 

reboot() — SET

Command
reboot()
Description
Reboot device (reboots after response)
Response (SET)
km.reboot()
>>> 

serial([text]) — GET/SET

Command
serial([text])
Description

Used to change the serial number of an attached mouse or keyboard while connected to MAKCU. This change is persistent and remains even after future firmware changes. Note: MAKCU does not allow changing serial numbers for a device that does not contain one.

Params
() to query; (0) to reset; (text) to set sanitized serial value
Response (GET)
km.serial()
>>> km.serial("MAKCU001")
>>> 

Returns current serial number.

Response (SET)
km.serial("MAKCU001")
>>> 
km.serial(0)
>>> 

Echo ACK. The change is persistent across firmware updates.

log([level]) — GET/SET

Command
log([level])
Params
level: 0-5; empty to query current level. Setting persists for 3 power cycles, then disables automatically
Response
km.log(3)
>>> 

echo([enable]) — GET/SET

Command
echo([enable])
Params
enable: 1=on, 0=off; empty to query
Response
km.echo(1)
>>> 

baud([rate]) — GET/SET

Command
baud([rate])
Params
rate: 115200 – 4000000; 0=reset to default 115200; empty to query
Response (GET)
km.baud(115200)
>>> 
Response (SET)
km.baud(921600)
>>> 

Applies immediately; host must re-open serial at new speed.

bypass([mode]) — GET/SET

Command
bypass([mode])
Description

Blocks the mouse endpoint from being sent to USB 1, all other endpoints will pass without issues. Works without USB device attached.

Params
  • () - Query current state
  • (0) - Off (restore USB write, disable telemetry)
  • (1) - Mouse bypass (enables km.mouse(1,1) and disables USB write)
  • (2) - Keyboard bypass (enables km.keyboard(1,1) and disables USB write)
Response (GET)
km.bypass()
>>> km.bypass(0)
>>> 

Warns (no mouse) or (no keyboard) if device not detected

Response (SET)
km.bypass(1)
>>> 
km.bypass(2)
>>> 
km.bypass(0)
>>> 

hs([enable]) — GET/SET

Command
hs([enable])
Description
USB high-speed compatibility for devices that may not report poll rate correctly *persistent
Params
() query; (1/0) enable/disable
Response
km.hs(1)
>>> 

led([target[,mode[,times,delay_ms]]]) — GET/SET

Command
led([target[,mode[,times,delay_ms]]])
Description

Control LED and RGB state for both device and host sides. Supports query, control, and flash functionality.

Query
  • led() - Query device LED state (backward compatible)
  • led(1) - Query device LED state
  • led(2) - Query host LED state (via UART)
  • Returns: (device,off), (device,on), (device,slow_blink), (device,fast_blink), (host,off), (host,on), etc.
Control
  • led(0) - Turn device LED off (backward compatible)
  • led(1) - Turn device LED on (backward compatible, but conflicts with query - use led(1,1) for explicit control)
  • led(1, 0) - Turn device LED off
  • led(1, 1) - Turn device LED on
  • led(2, 0) - Turn host LED off (via UART)
  • led(2, 1) - Turn host LED on (via UART)
  • Target: 1 = device LED, 2 = host LED (USB host side, controlled via UART)
  • Mode: 0 = off, 1 = on
Flash
  • led(1, times, delay_ms) - Flash device LED (e.g., led(1, 3, 200) = 3 flashes at 200ms)
  • led(2, times, delay_ms) - Flash host LED (e.g., led(2, 5, 100) = 5 flashes at 100ms)
  • Flash parameters: times = number of flashes (default 1), delay_ms = delay between flashes in milliseconds (default 100ms, max 5000ms)
Examples
km.led()
>>> km.led(device,on)
>>> 
km.led(2)
>>> km.led(host,off)
>>> 
km.led(1, 0)
>>> 
km.led(2, 1)
>>> 
km.led(1, 3, 200)
>>> 
km.led(2, 5, 100)
>>> 

release([timer_ms]) — GET/SET

Command
release([timer_ms])
Description

Auto-release monitoring system. Continuously monitors independent lock, button, and key states. When the timer expires, it releases only the corresponding values that remain active (not all at once). This setting is persistently saved to storage and automatically enabled on startup/boot. `()` get status (0=disabled, else time ms); `(timer_ms)` set timer 500-300000ms (5 min), (0) disables.

Params
() get status; (timer_ms) set timer 500-300000ms, (0) disables
Response (GET)
km.release()
>>> 
Response (SET)
km.release(5000)
>>> 
km.release(0)
>>> 

screen([W,H]) — GET/SET

Command
screen([width,height])
Params
() to query; (width,height) to set virtual screen size
Response (GET)
km.screen(1920,1080)
>>> 
Response (SET)
km.screen(2560,1440)
>>> 

Baud Rate Change (Legacy)

Purpose
Set UART baud rate using a binary frame (no ASCII command).
Frame
DE AD <lenLE:2> <cmd:0xA5> <baud_rate:LE32>
Example (115200)
DE AD 05 00 A5 00 C2 01 00

Breakdown: DE AD | 05 00(len=5) | A5 (cmd) |00 C2 01 00 (115200 LE)

V2 API (Binary)

All binary commands use the same frame structure. The frame format is explained below, and subsequent command examples show only the command byte and payload data.
RX (Host → Device)
  • Frame format: [0x50] [CMD] [LEN_LO] [LEN_HI] [PAYLOAD...]
  • 0x50 - Frame start byte (fixed)
  • CMD - Command byte (0x01-0xFF)
  • LEN_LO / LEN_HI - Payload length in bytes (little-endian, 16-bit)
  • PAYLOAD - Command-specific data (variable length)
TX (Device → Host)
  • Setters: Return [0x50] [CMD] [LEN_LO] [LEN_HI] [status:u8] where 0x00 = OK (success) and 0x01 = ERR (error)
  • Getters: Return [0x50] [CMD] [LEN_LO] [LEN_HI] [PAYLOAD...] with raw value bytes or structured data
  • Streaming: Return raw HID frame bytes (no text formatting) as [0x50] [CMD] [LEN_LO] [LEN_HI] [PAYLOAD...]
  • Data Types: Multi-byte values use little-endian byte order. Example: Query baud rate (command 0xB1, no payload) returns [0x50] [0xB1] [0x04] [0x00] [0x00] [0xC2] [0x01] [0x00] where 0x00C20100 = 115200 (little-endian)
  • In subsequent command examples, we show only: [CMD] [PAYLOAD...]

Mouse

Individual Buttons (GET/SET)

Command
left(0x08) | right(0x11) | middle(0x0A) | side1(0x12) | side2(0x13)
Description
Control individual mouse buttons - state: 0=release 1=down 2=silent_release; get returns: 0=none 1=raw 2=injected 3=both
Params
() to query; (state) set state. state: 0=release (sends frame), 1=down, 2=silent_release (sets to 0 but doesn't send frame)
Response (GET)
[0x08]
Response: [0x08] [state:u8]

Returns lock state: 0=none, 1=raw, 2=injected, 3=both.

Response (SET)
[0x08] [state:u8]
Response: [0x08] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Click Scheduling (SET)

Command
[0x04]
Description
Schedule clicks - button 1-5, count 1-255, delay_ms (0=random 35-75ms)
Params
button: 1-5 (left, right, middle, side1, side2); count: 1-255; delay_ms: delay in ms, 0=random 35-75ms
Response (SET)
[0x04] [button:u8] [count:u8] [delay_ms:u8]
Response: [0x04] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

turbo() (GET/SET)

Command
[0x17]
Description
Rapid-fire for mouse buttons 1-5 - delay: 1-5000ms or (button) for random 35-75ms - (0) disables all
Params
() returns active settings; (button) random delay; (button,delay_ms) set delay; (0) disables all
Response (GET)
[0x17]
Response: [0x17] [btn1-5_delay:u16×5]

Returns 10 bytes: 5 delays (u16 each) for buttons 1-5.

Response (SET)
[0x17] [button:u8] [delay_ms:u16]
Response: [0x17] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Mouse Movement

move(dx,dy[,segments[,cx1,cy1]]) — SET (0x0D)

Command
[0x0D]
Description
Move relative with bezier curve
Params
dx,dy: relative movement (int16); segments: bezier segments; cx1,cy1: control point 1 (int8)
Response (SET)
[0x0D] [x:i16] [y:i16] [segments:u8] [cx1:i8] [cy1:i8]
Response: [0x0D] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

moveto(x,y[,segments[,cx1,cy1[,cx2,cy2]]]) — SET (0x0E)

Command
[0x0E]
Description
Move absolute with bezier curve
Params
x,y: absolute position (int16); segments: bezier segments; cx1,cy1,cx2,cy2: control points (int16)
Response (SET)
[0x0E] [x:i16] [y:i16] [segments:u8] [cx1:i16] [cy1:i16] [cx2:i16] [cy2:i16]
Response: [0x0E] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

wheel(delta) — SET (0x18)

Command
[0x18]
Description
Scroll wheel steps
Params
delta: wheel steps (int8, positive=up, negative=down)
Response (SET)
[0x18] [delta:i8]
Response: [0x18] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

pan([steps]) — GET/SET (0x0F)

Command
[0x0F]
Description
Horizontal scroll/pan steps
Params
() to query pending pan; (steps) set pan steps (int8)
Response (GET)
[0x0F]
Response: [0x0F] [pending:i8]
Response (SET)
[0x0F] [steps:i8]
Response: [0x0F] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

swap_xy([enable]) — GET/SET (0x15)

Command
[0x15]
Description
Swap X and Y axes (physical only) - 0=disable, 1=enable
Params
() to query; (enable) set. enable: 0=disable, 1=enable
Response (GET)
[0x15]
Response: [0x15] [enabled:u8]

Returns 0=disabled, 1=enabled.

Response (SET)
[0x15] [enable:u8]
Response: [0x15] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

tilt([steps]) — GET/SET (0x16)

Command
[0x16]
Description
Tilt/z-axis steps
Params
() to query pending tilt; (steps) set tilt steps (int8)
Response (GET)
[0x16]
Response: [0x16] [pending:i8]
Response (SET)
[0x16] [steps:i8]
Response: [0x16] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

silent(x,y) — SET (0x14)

Command
[0x14]
Description
Move then silent left click
Params
x,y: position to move to (int16)
Response (SET)
[0x14] [x:i16] [y:i16]
Response: [0x14] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Mouse Advanced

catch_<target>([mode]) — GET/SET (0x03)

Command
[0x03]
Description
Catch mode - 0=off, 1=inject, 2=lock
Params
() to query; (mode) set mode. mode: 0=off, 1=inject, 2=lock
Response (GET)
[0x03]
Response: [0x03] [mode:u8]
Response (SET)
[0x03] [mode:u8]
Response: [0x03] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

getpos() — GET (0x05)

Command
[0x05]
Description
Get current mouse position
Params
No parameters
Response (GET)
[0x05]
Response: [0x05] [x:i16] [y:i16]

Returns current pointer position as int16 coordinates.

invert_x([enable]) — GET/SET (0x06)

Command
[0x06]
Description
Invert X axis (physical only) - 0=disable, 1=enable
Params
() to query; (enable) set. enable: 0=disable, 1=enable
Response (GET)
[0x06]
Response: [0x06] [enabled:u8]

Returns 0=disabled, 1=enabled.

Response (SET)
[0x06] [enable:u8]
Response: [0x06] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

invert_y([enable]) — GET/SET (0x07)

Command
[0x07]
Description
Invert Y axis (physical only) - 0=disable, 1=enable
Params
() to query; (enable) set. enable: 0=disable, 1=enable
Response (GET)
[0x07]
Response: [0x07] [enabled:u8]

Returns 0=disabled, 1=enabled.

Response (SET)
[0x07] [enable:u8]
Response: [0x07] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

lock_<target>([state]) — GET/SET (0x09)

Command
[0x09]
Description
Lock button or axis - state: 1=lock, 0=unlock; target is part of command (mx, my, mw, mx+, mx-, my+, my-, mw+, mw-, ml, mm, mr, ms1, ms2)
Params
() to query; (state) set state. state: 1=lock, 0=unlock
Targets
Axes: mx, my, mw (all); mx+, mx-, my+, my-, mw+, mw- (directional); Buttons: ml, mm, mr, ms1, ms2
Response (GET)
[0x09]
Response: [0x09] [locked:u8]

Returns 1=locked, 0=unlocked.

Response (SET)
[0x09] [state:u8]
Response: [0x09] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

mo(buttons,x,y,wheel,pan,tilt) — SET (0x0B)

Command
[0x0B]
Description
Send raw mouse frame - button mask mirrors states, axes are one-shot
Params
buttons: button mask (u8); x,y: position (i16); wheel,pan,tilt: axis values (i8)
Response (SET)
[0x0B] [buttons:u8] [x:i16] [y:i16] [wheel:i8] [pan:i8] [tilt:i8]
Response: [0x0B] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

remap_button([src,dst]) — GET/SET (0x10)

Command
[0x10]
Description
Remap mouse buttons (1-5: left,right,middle,side1,side2); dst=0 clears src
Params
() show mappings; (0) reset all; (src,dst) map button src→dst; (src,0) clear src
Response (GET)
[0x10]
Response: [0x10] [map1-5:u8×2×5]

Returns 10 bytes: 5 mappings, each 2 bytes (src,dst).

Response (SET)
[0x10] [src:u8] [dst:u8]
Response: [0x10] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

remap_axis([inv_x,inv_y,swap]) — GET/SET (0x19)

Command
[0x19]
Description
Remap mouse axes (physical only) - Set all three flags atomically: inv_x, inv_y, swap (each 0=disable, 1=enable)
Params
  • () - Query current settings
  • (0) - Reset all axis remaps
  • (inv_x,inv_y,swap) - Set all three flags (each 0 or 1)
Response (GET)
[0x19]
Response: [0x19] [inv_x:u8] [inv_y:u8] [swap:u8]

Returns 3 bytes: inv_x, inv_y, swap (each 0=disabled, 1=enabled).

Response (SET)
[0x19] [inv_x:u8] [inv_y:u8] [swap:u8]
Response: [0x19] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. Sets all three flags atomically.

[0x19] [0x00]
Response: [0x19] [status:u8]

Reset all axis remaps (sets all flags to 0).

Keyboard

Keyboard commands use numeric HID codes (u8). Supported HID codes: 0x00-0xFF. See complete key reference for details.

disable([key1,key2,...] | [key,mode]) — GET/SET (0xA1)

Command
[0xA1]
Description
Disable keys - key: HID code - mode: 0=enable 1=disable - can disable multiple keys
Params
() list disabled keys; (key1,key2,...) disable keys; (key,mode) enable/disable single key
Response (GET)
[0xA1]
Response: [0xA1] [disabled_keys:u8×N]

Returns list of disabled HID codes.

Response (SET)
[0xA1] [key1:u8]...[keyN:u8]
Response: [0xA1] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

down(key) — SET (0xA2)

Command
[0xA2]
Description
Press key down
Params
key: HID code (u8)
Response (SET)
[0xA2] [key:u8]
Response: [0xA2] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

init() — SET (0xA3)

Command
[0xA3]
Description
Clear keyboard state
Params
No parameters
Response (SET)
[0xA3]
Response: [0xA3] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

isdown(key) — GET (0xA4)

Command
[0xA4]
Description
Query if key is down
Params
key: HID code (u8)
Response (GET)
[0xA4] [key:u8]
Response: [0xA4] [is_down:u8]

Returns 0=up, 1=down.

mask(key[,mode]) — SET (0xA6)

Command
[0xA6]
Description
Mask key - key: HID code - mode: 0=off 1=on
Params
key: HID code (u8); mode: 0=off, 1=on
Response (SET)
[0xA6] [key:u8] [mode:u8]
Response: [0xA6] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

press(key[,hold_ms[,rand_ms]]) — SET (0xA7)

Command
[0xA7]
Description
Tap key - key: HID code - hold_ms: random 35-85ms if omitted - rand_ms optional
Params
key: HID code (u8); hold_ms: hold time (u8, 0=random 35-85ms); rand_ms: randomization (u8, optional)
Response (SET)
[0xA7] [key:u8] [hold_ms:u8] [rand_ms:u8]
Response: [0xA7] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

remap(source,target) — SET (0xA8)

Command
[0xA8]
Description
Remap keycode - both: HID code; target=0 clears remap (passthrough)
Params
source: source HID code (u8); target: target HID code (u8), 0=clear remap
Response (SET)
[0xA8] [source:u8] [target:u8]
Response: [0xA8] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

string(text) — SET (0xA9)

Command
[0xA9]
Description
Type ASCII string - max 256 chars
Params
text: ASCII bytes (u8×N, max 256 bytes)
Response (SET)
[0xA9] [text:u8×N]
Response: [0xA9] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

up(key) — SET (0xAA)

Command
[0xAA]
Description
Release key
Params
key: HID code (u8)
Response (SET)
[0xAA] [key:u8]
Response: [0xAA] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Streaming

buttons([mode[,period_ms]]) — GET/SET (0x02)

Command
[0x02]
Description
Stream button states - mode: 1=raw 2=mut; period: 1-1000ms (rounded to bInterval); requires baud >= 1M; only emits on new frames
Params
() to query; (mode) set mode; (mode,period_ms) set mode and period. mode: 1=raw 2=mut; period: 1-1000ms
Response (GET)
[0x02]
Response: [0x02] [mode:u8] [period:u8]

Returns current streaming mode and period.

Response (SET)
[0x02] [mode:u8] [period:u8]
Response: [0x02] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Streaming format

Device emits 2-byte binary frame when buttons change:

[0x02] [buttons_lo:u8] [buttons_hi:u8]

Buttons mask: bit 0=left, 1=right, 2=middle, 3=side1, 4=side2

axis([mode[,period_ms]]) — GET/SET (0x01)

Command
[0x01]
Description
Stream x/y/wheel axis deltas - mode: 1=raw 2=mut; period: 1-1000ms (rounded to bInterval); requires baud >= 1M; only emits on new frames
Params
() to query; (mode) set mode; (mode,period_ms) set mode and period. mode: 1=raw 2=mut; period: 1-1000ms
Response (GET)
[0x01]
Response: [0x01] [mode:u8] [period:u8]
Response (SET)
[0x01] [mode:u8] [period:u8]
Response: [0x01] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Streaming format

Device emits 6-byte binary frame when axes change:

[0x01] [dx:i16] [dy:i16] [wheel:i8]

mouse([mode[,period_ms]]) — GET/SET (0x0C)

Command
[0x0C]
Description
Stream full mouse data - mode: 1=raw 2=mut; period: 1-1000ms (rounded to bInterval); requires baud >= 1M; only emits on new frames
Params
() to query; (mode) set mode; (mode,period_ms) set mode and period. mode: 1=raw 2=mut; period: 1-1000ms
Response (GET)
[0x0C]
Response: [0x0C] [mode:u8] [period:u8]
Response (SET)
[0x0C] [mode:u8] [period:u8]
Response: [0x0C] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Streaming format

Device emits 8-byte binary frame when mouse data changes:

[0x0C] [buttons:u8] [dx:i16] [dy:i16] [wheel:i8] [pan:i8] [tilt:i8]

keyboard([mode[,period_ms]]) — GET/SET (0xA5)

Command
[0xA5]
Description
Stream keyboard - mode: 1=raw 2=mut; period: 1-1000ms (rounded to bInterval); requires baud >= 1M; only emits on new frames
Params
() to query; (mode) set mode; (mode,period_ms) set mode and period. mode: 1=raw 2=mut; period: 1-1000ms
Response (GET)
[0xA5]
Response: [0xA5] [mode:u8] [period:u8]
Response (SET)
[0xA5] [mode:u8] [period:u8]
Response: [0xA5] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Streaming format

Device emits 15-byte binary frame when keyboard data changes:

[0xA5] [modifiers:u8] [keys:u8×14]

Modifiers byte: bit flags for ctrl, shift, alt, gui, etc. Keys array: up to 14 HID codes.

Misc

baud([rate]) — GET/SET (0xB1)

Command
[0xB1]
Description
Set/get UART0 baud rate - 0=default (115200)
Params
() to query; (rate) set baud rate (u32), 0=default 115200, range: 115200-4000000
Response (GET)
[0xB1]
Response: [0xB1] [rate:u32]

Returns current baud rate as uint32 (little-endian).

Response (SET)
[0xB1] [rate:u32]
Response: [0xB1] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. Change is persistent.

bypass([mode]) — GET/SET (0xB2)

Command
[0xB2]
Description
Bypass mode - 0=off, 1=mouse, 2=keyboard; disables USB write, streams raw to COM2
Params
() to query; (mode) set mode. mode: 0=off, 1=mouse, 2=keyboard; requires baud >= 1M
Response (GET)
[0xB2]
Response: [0xB2] [mode:u8]
Response (SET)
[0xB2] [mode:u8]
Response: [0xB2] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

echo([enable]) — GET/SET (0xB4)

Command
[0xB4]
Description
Toggle UART echo
Params
() to query; (enable) set echo. enable: 0=disable, 1=enable
Response (GET)
[0xB4]
Response: [0xB4] [enabled:u8]
Response (SET)
[0xB4] [enable:u8]
Response: [0xB4] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. When echo is disabled, most setter commands won't echo their input.

hs([enable]) — GET/SET (0xB7)

Command
[0xB7]
Description
USB high-speed compatibility - 0=disable, 1=enable (persistent)
Params
() to query; (enable) set high-speed mode. enable: 0=disable, 1=enable
Response (GET)
[0xB7]
Response: [0xB7] [enabled:u8]
Response (SET)
[0xB7] [enable:u8]
Response: [0xB7] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. Setting is persistent across reboots.

led([...]) — GET/SET (0xB9)

Command
[0xB9]
Description
LED control - target: 1=device 2=host; mode: 0=off 1=on; state: 0=off 1=on 2=slow_blink 3=fast_blink
Params
() query device; (1) query device; (2) query host; (0) device off; (1) device on; (target,mode) control; (target,times,delay_ms) flash
Response (GET)
Query device: [0xB9]
Query host:   [0xB9] [0x02]
Response:    [0xB9] [target:u8] [state:u8]

State: 0=off, 1=on, 2=slow_blink, 3=fast_blink

Response (SET)
Set:    [0xB9] [target:u8] [mode:u8]
Response: [0xB9] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

Flash
Flash:  [0xB9] [target:u8] [times:u32] [delay_ms:u32]
Response: [0xB9] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. Controls both LED and RGB. Times: 1-255, delay_ms: 100-5000ms

log([level]) — GET/SET (0xBA)

Command
[0xBA]
Description
Set/get log level - 0-5. Setting persists for 3 power cycles, then disables automatically
Params
() to query; (level) set log level. level: 0-5 (0=none, 5=debug). Setting persists for 3 power cycles, then disables automatically
Response (GET)
[0xBA]
Response: [0xBA] [level:u8]
Response (SET)
[0xBA] [level:u8]
Response: [0xBA] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

release([timer_ms]) — GET/SET (0xBC)

Command
[0xBC]
Description
Auto-release timer - releases all active locks/buttons/keys when expired
Params
() get status; (timer_ms) set timer 500-300000ms (5 min), (0) disables
Response (GET)
[0xBC]
Response: [0xBC] [timer_ms:u32]

Returns 0 if disabled, else time in milliseconds.

Response (SET)
[0xBC] [timer_ms:u32]
Response: [0xBC] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

screen([W,H]) — GET/SET (0xBD)

Command
[0xBD]
Description
Set/get virtual screen dimensions
Params
() to query; (width,height) set virtual screen size (int16)
Response (GET)
[0xBD]
Response: [0xBD] [width:i16] [height:i16]
Response (SET)
[0xBD] [width:i16] [height:i16]
Response: [0xBD] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error.

serial([text]) — GET/SET (0xBE)

Command
[0xBE]
Description
USB serial number operations - ASCII bytes
Params
() to query; (0) to reset; (text) to set sanitized serial value (ASCII bytes)
Response (GET)
[0xBE]
Response: [0xBE] [serial:u8×N]

Returns current serial number as ASCII bytes.

Response (SET)
[0xBE] [text:u8×N]
Response: [0xBE] [status:u8]

Returns 0x00 (OK) on success, 0x01 (ERR) on error. The change is persistent across firmware updates.

device() — GET (0xB3)

Command
[0xB3]
Description
Returns active device type
Params
No parameters
Response (GET)
[0xB3]
Response: [0xB3] [type:u8]

Type: 0=none, 1=keyboard, 2=mouse

fault() — GET (0xB5)

Command
[0xB5]
Description
Get stored parse fault info (same as 0xE8)
Params
No parameters
Response (GET)
[0xB5]
Response: [0xB5] [parse_fault_t struct]

Returns parse_fault_t structure with MAC, endpoint, reason, and raw descriptor bytes.

info() — GET (0xB8)

Command
[0xB8]
Description
System/device info - key=value format: MAC1, MAC2, TEMP, RAM, FW, CPU, UP, VID, PID, VENDOR, MODEL, ORIGINAL_SERIAL, SPOOFED_SERIAL, MOUSE_BINT, KBD_BINT, FAULT
Params
No parameters
Response (GET)
[0xB8]
Response: [0xB8] [field_count:u8] [fields...]

Returns structured binary data with system/device info key-value pairs. Device info cached after first fetch.

reboot() — SET (0xBB)

Command
[0xBB]
Description
Reboot device after response
Params
No parameters
Response (SET)
[0xBB]
Response: [0xBB] [status:u8]

Always returns 0x00 (success). Device reboots after sending response.

version() — GET (0xBF)

Command
[0xBF]
Description
Get firmware version information
Params
No parameters
Response (GET)
[0xBF]
Response: [0xBF] [version:u8×N]

Returns firmware version as ASCII bytes.