Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# nanokvm API Reference

**Version:** 0.1.1
**Version:** 0.1.2
**License:** MIT
**Python:** >= 3.12

Expand Down
1 change: 0 additions & 1 deletion examples/ai_agent_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from __future__ import annotations

import json
import time

from nanokvm import NanoKVM
Expand Down
47 changes: 32 additions & 15 deletions examples/mouse_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ def _record_loop(self) -> None:

if writer is None:
h, w = frame.shape[:2]
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter(self._output_path, fourcc, self._fps, (w, h))
fourcc = cv2.VideoWriter_fourcc(*"mp4v") # type: ignore[reportAttributeAccessIssue]
writer = cv2.VideoWriter(
self._output_path, fourcc, self._fps, (w, h)
)
if not writer.isOpened():
print(f" [recorder] Failed to open VideoWriter for {self._output_path}")
print(
f" [recorder] Failed to open VideoWriter for {self._output_path}"
)
return

writer.write(frame)
Expand Down Expand Up @@ -102,11 +106,11 @@ def test_absolute_mode(kvm: NanoKVM) -> None:
print("Moving cursor to five positions (corners + center)...\n")

positions = [
("top-left", 0.05, 0.05),
("top-right", 0.95, 0.05),
("top-left", 0.05, 0.05),
("top-right", 0.95, 0.05),
("bottom-right", 0.95, 0.95),
("bottom-left", 0.05, 0.95),
("center", 0.50, 0.50),
("bottom-left", 0.05, 0.95),
("center", 0.50, 0.50),
]

for name, x, y in positions:
Expand Down Expand Up @@ -157,11 +161,11 @@ def test_relative_move_to(kvm: NanoKVM) -> None:
print("Visits corners using reset-to-origin + relative movement.\n")

positions = [
("top-left", 0.0, 0.0),
("top-right", 1.0, 0.0),
("top-left", 0.0, 0.0),
("top-right", 1.0, 0.0),
("bottom-right", 1.0, 1.0),
("bottom-left", 0.0, 1.0),
("center", 0.5, 0.5),
("bottom-left", 0.0, 1.0),
("center", 0.5, 0.5),
]

for name, x, y in positions:
Expand Down Expand Up @@ -196,10 +200,23 @@ def test_scroll(kvm: NanoKVM) -> None:
def main() -> None:
parser = argparse.ArgumentParser(description="NanoKVM mouse control test")
parser.add_argument("--port", default="/dev/ttyACM0", help="Serial port")
parser.add_argument("--video", type=int, default=None, help="Video device index (optional)")
parser.add_argument("--record", action="store_true", help="Record the KVM screen during tests")
parser.add_argument("--output", default=None, help="Output video file path (default: recording_<timestamp>.mp4)")
parser.add_argument("--record-fps", type=float, default=10, help="Recording frame rate (default: 10)")
parser.add_argument(
"--video", type=int, default=None, help="Video device index (optional)"
)
parser.add_argument(
"--record", action="store_true", help="Record the KVM screen during tests"
)
parser.add_argument(
"--output",
default=None,
help="Output video file path (default: recording_<timestamp>.mp4)",
)
parser.add_argument(
"--record-fps",
type=float,
default=10,
help="Recording frame rate (default: 10)",
)
args = parser.parse_args()

if args.record and args.video is None:
Expand Down
8 changes: 4 additions & 4 deletions examples/open_chrome_win11.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ def record_loop() -> None:

# --- Move mouse to each corner and center ---
positions = [
("top-left", 0.0, 0.0),
("top-right", 1.0, 0.0),
("top-left", 0.0, 0.0),
("top-right", 1.0, 0.0),
("bottom-right", 1.0, 1.0),
("bottom-left", 0.0, 1.0),
("center", 0.5, 0.5),
("bottom-left", 0.0, 1.0),
("center", 0.5, 0.5),
]

for name, x, y in positions:
Expand Down
4 changes: 3 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ def main() -> None:
devices = VideoCapture.list_devices()
if devices:
for d in devices:
print(f" Index {d['index']}: {d['width']}x{d['height']} @ {d['fps']}fps ({d['backend']})")
print(
f" Index {d['index']}: {d['width']}x{d['height']} @ {d['fps']}fps ({d['backend']})"
)
else:
print(" (none found)")

Expand Down
2 changes: 1 addition & 1 deletion nanokvm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .serial_conn import SerialConnection
from .video import VideoCapture

__version__ = "0.1.1"
__version__ = "0.1.2"

__all__ = [
"NanoKVM",
Expand Down
4 changes: 3 additions & 1 deletion nanokvm/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ def main() -> None:
devices = VideoCapture.list_devices()
if devices:
for d in devices:
print(f" Index {d['index']}: {d['width']}x{d['height']} @ {d['fps']}fps ({d['backend']})")
print(
f" Index {d['index']}: {d['width']}x{d['height']} @ {d['fps']}fps ({d['backend']})"
)
else:
print(" (none found)")

Expand Down
17 changes: 12 additions & 5 deletions nanokvm/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@

import time

from .keyboard import KeyboardReport, is_modifier, resolve_key_code
from .keyboard import KeyboardReport, resolve_key_code
from .mouse import (
MouseButton,
build_absolute_report,
build_relative_report,
resolve_button,
Expand Down Expand Up @@ -93,7 +92,9 @@ def connect(
info = self.get_info()

if vdev is not None:
self._video.open(vdev, self._video_width, self._video_height, self._video_fps)
self._video.open(
vdev, self._video_width, self._video_height, self._video_fps
)

return info

Expand Down Expand Up @@ -199,7 +200,11 @@ def type_text(self, text: str, delay: float = INTER_KEY_DELAY) -> None:
# ------------------------------------------------------------------

def _send_mouse(self, report: list[int]) -> None:
pkt_cmd = CmdEvent.SEND_MS_REL_DATA if report[0] == 0x01 else CmdEvent.SEND_MS_ABS_DATA
pkt_cmd = (
CmdEvent.SEND_MS_REL_DATA
if report[0] == 0x01
else CmdEvent.SEND_MS_ABS_DATA
)
pkt = CmdPacket(addr=self._addr, cmd=pkt_cmd, data=report)
self._serial.write(pkt.encode())

Expand Down Expand Up @@ -276,7 +281,9 @@ def mouse_move_relative(self, dx: int, dy: int, step_delay: float = 0.005) -> No
while dx != 0 or dy != 0:
chunk_x = max(-127, min(127, dx))
chunk_y = max(-127, min(127, dy))
report = build_relative_report(dx=chunk_x, dy=chunk_y, buttons=self._buttons)
report = build_relative_report(
dx=chunk_x, dy=chunk_y, buttons=self._buttons
)
self._send_mouse(report)
dx -= chunk_x
dy -= chunk_y
Expand Down
Loading