Skip to main content

Python library for controlling keyboard, mouse, and touchpad via HID gadgets on NanoKVM Pro

Project description

nanokvm-hid

Python library for controlling NanoKVM Pro hardware via direct device access. Runs on-device on the NanoKVM itself.

The NanoKVM Pro sits between a host computer and its peripherals, exposing USB HID gadget devices (/dev/hidg0–2) that allow hardware-level input injection — indistinguishable from a real keyboard and mouse. This library provides a clean, Pythonic API on top of those raw HID interfaces, plus control of GPIO, HDMI, virtual media, and more.

Features

  • Keyboard — key combos (CTRL+C, ALT+F4, GUI+L), media keys (VOLUME_UP), string typing
  • Mouse — absolute positioning, left/right click, double-click, scroll, drag
  • Screen capture — grab JPEG screenshots from the HDMI video stream
  • GPIO control — power/reset button press, power/HDD LED status
  • Virtual media — mount/unmount ISO/IMG files as USB drives
  • HDMI control — capture on/off, passthrough (loopout), EDID management
  • Mouse jiggler — background keep-alive with relative/absolute modes
  • HID management — reset stuck USB gadgets, switch normal/hid-only mode
  • Virtual USB devices — toggle network adapter (NCM), microphone (UAC2), disk (SD/eMMC)
  • Stream control — FPS, GOP, quality, bitrate, rate-control, stream mode via server HTTP API
  • Video capture — record raw H.264/H.265 streams via WebSocket (direct mode)
  • Wake-on-LAN — send magic packets to power on machines
  • Pure Python — single dependency (websockets) for video capture
  • OS-agnostic target — works on any OS the KVM-controlled computer runs (Windows, Linux, macOS, BIOS, UEFI…)

Installation

# On the NanoKVM itself
uv pip install .

# Or for development
uv sync --dev

Quick Start

from nanokvm_hid import Keyboard, Mouse

kb = Keyboard()
mouse = Mouse()

# Move cursor and click
mouse.left_click(0.5, 0.5)       # click center of screen

# Type text
kb.type("hello world")
kb.press("ENTER")

# Key combos
kb.hotkey("CTRL", "S")           # Ctrl+S
kb.press("ALT+F4")              # Alt+F4

# Mouse operations
mouse.right_click(0.8, 0.2)     # right-click near top-right
mouse.double_click(0.3, 0.7)    # double-click
mouse.scroll_down(3)             # scroll down 3 steps
mouse.drag(0.1, 0.1, 0.9, 0.9) # drag from corner to corner

API Reference

Keyboard(device="/dev/hidg0", inter_report_delay=0.02)

Method Description
press(combo) Send a key combination: "A", "CTRL+C", "ALT+F4", "VOLUME_UP"
type(text) Type a string of printable ASCII characters
backspace(n) Press Backspace n times
hotkey(*keys) hotkey("CTRL", "SHIFT", "A")press("CTRL+SHIFT+A")
enter() Press Enter
tab() Press Tab
escape() Press Escape

Mouse(mouse_device="/dev/hidg1", touchpad_device="/dev/hidg2", screen_size=None)

All coordinates are normalised to [0.0, 1.0] relative to screen dimensions.

Method Description
move(x, y) Move cursor to absolute position
left_click(x, y) Left-click at position
right_click(x, y) Right-click at position
double_click(x, y) Double-click at position
click(x, y, button=) Click with specified button
scroll_down(steps) Scroll down
scroll_up(steps) Scroll up
drag(x0, y0, x1, y1) Drag from start to end position

Screen(url="https://localhost/api/stream/mjpeg", timeout=10)

from nanokvm_hid import Screen

screen = Screen()
jpeg_data = screen.capture()          # raw JPEG bytes
screen.capture_to_file("shot.jpg")    # save to file
b64 = screen.capture_base64()         # base64 (for VLM APIs)
w, h = screen.screen_size()           # read resolution

GPIO()

from nanokvm_hid import GPIO

gpio = GPIO()
gpio.power()                    # short press (800ms)
gpio.power_off()                # long press (5s)
gpio.reset()                    # reset button press
print(gpio.power_led())         # True if power LED is on
print(gpio.hdd_led())           # True if HDD LED is on

Storage()

from nanokvm_hid import Storage

storage = Storage()
images = storage.list_images()                   # find .iso/.img files
storage.mount("/data/ubuntu.iso", cdrom=True)    # mount as CD-ROM
print(storage.mounted())                         # current mount info
storage.unmount()

HDMI()

from nanokvm_hid import HDMI

hdmi = HDMI()
hdmi.set_capture(True)              # enable HDMI capture
hdmi.set_passthrough(True)          # enable loopout
print(hdmi.current_edid)            # e.g. "E54-1080P60FPS"
print(hdmi.list_edids())            # available profiles
hdmi.switch_edid("E54-1080P60FPS")  # switch EDID profile
hdmi.upload_edid("custom.bin")      # upload custom EDID
hdmi.delete_edid("custom.bin")      # delete custom EDID

Jiggler()

from nanokvm_hid import Jiggler

jiggler = Jiggler()
jiggler.start(mode="relative")   # or "absolute"
print(jiggler.is_running)
jiggler.stop()

VirtualDevices()

from nanokvm_hid import VirtualDevices

vdev = VirtualDevices()
print(vdev.status())          # all device states
vdev.toggle_network()         # toggle USB NCM adapter
vdev.toggle_mic()             # toggle USB UAC2 mic
vdev.set_disk("sdcard")       # expose SD card as USB drive
vdev.set_disk(None)           # disable virtual disk

HID Management

from nanokvm_hid import reset_hid, get_hid_mode, set_hid_mode

reset_hid()                   # restart USB gadgets
print(get_hid_mode())         # "normal" or "hid-only"
set_hid_mode("hid-only")     # switch mode

Wake-on-LAN

from nanokvm_hid import wake_on_lan

wake_on_lan("AA:BB:CC:DD:EE:FF")

Stream()

Control the hardware video encoder via the NanoKVM server's local API (no auth required from localhost):

from nanokvm_hid import Stream

stream = Stream()

# Read current settings
info = stream.status()
print(info)
# {'fps': 0, 'gop': 50, 'bitrate': 8000,
#  'resolution': {'width': 3840, 'height': 2160}, 'captured_fps': 0}

# Set parameters
stream.set_fps(30)                  # cap at 30 FPS (0 = auto)
stream.set_gop(50)                  # GOP length (1–200)
stream.set_quality(80)              # MJPEG quality (1–100)
stream.set_bitrate(5000)            # H264/H265 bitrate (1000–20000 kbps)
stream.set_rate_control("vbr")      # "cbr" or "vbr"
stream.set_mode("h264-webrtc")      # mjpeg, h264-webrtc, h264-direct, h265-*

# Record raw video stream to file
result = stream.record("clip.h264", codec="h264", duration=5.0)
# {'file': 'clip.h264', 'codec': 'h264', 'frames': 150, 'bytes': 2048576, 'duration': 5.01}

result = stream.record("clip.h265", codec="h265", max_frames=300)

# Async frame-by-frame capture
import asyncio

async def grab_frames():
    async for frame in stream.capture("h264", max_frames=10):
        print(frame.is_key_frame, frame.timestamp_us, len(frame.data))
        # frame.data = raw NAL units (starts with 00 00 00 01)

asyncio.run(grab_frames())

Methods:

Method Description
status() Read current encoder state (FPS, GOP, bitrate, resolution, captured FPS)
set_fps(n) Set target FPS (0=auto, 1–120)
set_gop(n) Set GOP length (1–200)
set_quality(n) Set MJPEG quality (1–100)
set_bitrate(n) Set H264/H265 bitrate in kbps (1000–20000)
set_rate_control(mode) Set rate control: "cbr" or "vbr"
set_mode(mode) Set stream mode (see table below)
record(path, codec, ...) Record raw H.264/H.265 stream to file (sync)
capture(codec, ...) Async generator yielding VideoFrame objects

VideoFrame fields: is_key_frame (bool), timestamp_us (int), data (bytes), codec (str)

Stream modes:

Mode Description
mjpeg MJPEG over HTTP (widest compatibility)
h264-webrtc H.264 via WebRTC (default in web UI)
h264-direct H.264 NAL units over WebSocket
h265-webrtc H.265/HEVC via WebRTC
h265-direct H.265/HEVC NAL units over WebSocket

H.265 note: The NanoKVM Pro hardware (AX620Q SoC) and server binary fully support H.265 encoding, but the web dashboard hides the option because most browsers lack H.265 WebRTC support. This library can enable H.265 mode regardless — use h265-direct for WebSocket-based access, which is easier to consume from custom clients.

HIDTransport(device_path)

Low-level transport for sending raw HID reports:

from nanokvm_hid import HIDTransport

tp = HIDTransport("/dev/hidg0")
tp.send(bytes([0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00]))  # press 'A'
tp.send(bytes(8))  # release

Command Line

After installing, the nanokvm-hid command is available:

# Device info
nanokvm-hid info

# Keyboard
nanokvm-hid key CTRL+C
nanokvm-hid key ALT+F4
nanokvm-hid key CTRL+A BACKSPACE           # multiple combos in sequence
nanokvm-hid type "hello world"
nanokvm-hid backspace 5
nanokvm-hid enter
nanokvm-hid tab
nanokvm-hid escape

# Mouse (coordinates are normalised 0.0–1.0)
nanokvm-hid mouse move 0.5 0.5
nanokvm-hid mouse click 0.3 0.7            # left-click
nanokvm-hid mouse click -r 0.8 0.2         # right-click
nanokvm-hid mouse click -d 0.5 0.5         # double-click
nanokvm-hid mouse scroll-down 3
nanokvm-hid mouse scroll-up
nanokvm-hid mouse drag 0.1 0.1 0.9 0.9

# GPIO — power/reset/LEDs
nanokvm-hid power                           # short press (800ms)
nanokvm-hid power --duration 5000           # force off (5s hold)
nanokvm-hid reset-button                    # reset press
nanokvm-hid power-led                       # exit 0=on, 1=off
nanokvm-hid hdd-led

# Virtual media — mount ISO/IMG
nanokvm-hid storage list
nanokvm-hid storage mount /data/ubuntu.iso --cdrom
nanokvm-hid storage unmount
nanokvm-hid storage status

# HDMI control
nanokvm-hid hdmi status
nanokvm-hid hdmi capture on
nanokvm-hid hdmi capture off
nanokvm-hid hdmi passthrough on
nanokvm-hid hdmi edid list
nanokvm-hid hdmi edid current
nanokvm-hid hdmi edid switch E54-1080P60FPS

# Mouse jiggler
nanokvm-hid jiggler on
nanokvm-hid jiggler on --mode absolute
nanokvm-hid jiggler off
nanokvm-hid jiggler status

# HID management
nanokvm-hid hid-reset
nanokvm-hid hid-mode                        # show current mode
nanokvm-hid hid-mode hid-only
nanokvm-hid hid-mode normal

# Virtual USB devices
nanokvm-hid virtual-device status
nanokvm-hid virtual-device network          # toggle
nanokvm-hid virtual-device mic              # toggle
nanokvm-hid virtual-device disk sdcard
nanokvm-hid virtual-device disk emmc

# Wake-on-LAN
nanokvm-hid wol AA:BB:CC:DD:EE:FF

# Stream encoder control
nanokvm-hid stream status                   # show current settings
nanokvm-hid stream fps 30                   # set FPS (0 = auto)
nanokvm-hid stream gop 50                   # set GOP length
nanokvm-hid stream quality 80               # MJPEG quality
nanokvm-hid stream bitrate 5000             # H264/H265 bitrate (kbps)
nanokvm-hid stream rate-control vbr         # cbr or vbr
nanokvm-hid stream mode h264-webrtc         # stream mode

# Video capture (raw H.264/H.265 via WebSocket)
nanokvm-hid stream record -o clip.h264                   # record H.264 (Ctrl+C to stop)
nanokvm-hid stream record -o clip.h264 --duration 10     # record for 10 seconds
nanokvm-hid stream record -o clip.h265 --codec h265 --frames 300  # 300 H.265 frames

# Delay
nanokvm-hid sleep 1.5

# Screenshot
nanokvm-hid capture -o screenshot.jpg

Scripting

Run a sequence of commands from a file (or pipe from stdin):

nanokvm-hid script commands.txt
echo 'key CTRL+C' | nanokvm-hid script

Script files support comments and blank lines:

# login.script — unlock a workstation
mouse click 0.5 0.5
sleep 0.5
type "mypassword"
enter
sleep 2
# open a terminal
key CTRL+ALT+T

Supported Keys

Modifiers: CTRL, SHIFT, ALT, GUI (+ WIN, SUPER, META, CMD aliases), with LEFT_/RIGHT_ variants.

Function keys: F1F12

Navigation: UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, HOME, END, PAGE_UP, PAGE_DOWN, INSERT, DELETE

Control: ENTER, ESCAPE, BACKSPACE, TAB, SPACE, CAPS_LOCK, PRINT_SCREEN, SCROLL_LOCK, PAUSE

Media: PLAY_PAUSE, VOLUME_UP, VOLUME_DOWN, MUTE, SCAN_NEXT_TRACK, SCAN_PREVIOUS_TRACK, STOP

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nanokvm_hid-0.2.1.tar.gz (86.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nanokvm_hid-0.2.1-py3-none-any.whl (43.4 kB view details)

Uploaded Python 3

File details

Details for the file nanokvm_hid-0.2.1.tar.gz.

File metadata

  • Download URL: nanokvm_hid-0.2.1.tar.gz
  • Upload date:
  • Size: 86.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nanokvm_hid-0.2.1.tar.gz
Algorithm Hash digest
SHA256 5df14ca7815bb0d1ff56a27d87be36de8d500bb00d8a8743f127867a18ecfecc
MD5 ab6c41515b76b518867019404cc2f80e
BLAKE2b-256 6f751c1e3f0e101d841e820641f8580487504bf81060ed984d3b340156587aca

See more details on using hashes here.

File details

Details for the file nanokvm_hid-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: nanokvm_hid-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 43.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nanokvm_hid-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 45e7f71020a8dfefa54247888e8565122440965a8141db0eaf7191e135be888e
MD5 858976a59f12f6235bafd0cd8e3ea182
BLAKE2b-256 d69fd3bbacc980529539b90363fb93a840055db5fa4e816117837deabbe0270f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page