Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit a33a309

Browse files
committed
nanokvm: fix mouse move/click
1 parent f8af8b7 commit a33a309

File tree

2 files changed

+65
-44
lines changed

2 files changed

+65
-44
lines changed

packages/jumpstarter-driver-nanokvm/jumpstarter_driver_nanokvm/client.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,55 +95,64 @@ def reset_hid(self):
9595
"""
9696
self.call("reset_hid")
9797

98-
def mouse_move_abs(self, x: int, y: int):
98+
def mouse_move_abs(self, x: float, y: float):
9999
"""
100100
Move mouse to absolute coordinates
101101
102102
Args:
103-
x: X coordinate (0-65535, scaled to screen resolution)
104-
y: Y coordinate (0-65535, scaled to screen resolution)
103+
x: X coordinate (0.0 to 1.0, where 0.0 is left and 1.0 is right)
104+
y: Y coordinate (0.0 to 1.0, where 0.0 is top and 1.0 is bottom)
105105
106106
Example::
107107
108-
# Move to center of screen (assuming 1920x1080)
109-
hid.mouse_move_abs(32768, 32768)
108+
# Move to center of screen
109+
hid.mouse_move_abs(0.5, 0.5)
110+
111+
# Move to top-left corner
112+
hid.mouse_move_abs(0.0, 0.0)
113+
114+
# Move to bottom-right corner
115+
hid.mouse_move_abs(1.0, 1.0)
110116
"""
111117
self.call("mouse_move_abs", x, y)
112118

113-
def mouse_move_rel(self, dx: int, dy: int):
119+
def mouse_move_rel(self, dx: float, dy: float):
114120
"""
115121
Move mouse relative to current position
116122
117123
Args:
118-
dx: X movement delta (-127 to 127)
119-
dy: Y movement delta (-127 to 127)
124+
dx: X movement delta (-1.0 to 1.0, where 1.0 is full screen width)
125+
dy: Y movement delta (-1.0 to 1.0, where 1.0 is full screen height)
120126
121127
Example::
122128
123-
# Move right and down
124-
hid.mouse_move_rel(50, 50)
129+
# Move right by 10% of screen width and down by 10%
130+
hid.mouse_move_rel(0.1, 0.1)
131+
132+
# Move left by 20%
133+
hid.mouse_move_rel(-0.2, 0.0)
125134
"""
126135
self.call("mouse_move_rel", dx, dy)
127136

128-
def mouse_click(self, button: str = "left", x: int | None = None, y: int | None = None):
137+
def mouse_click(self, button: str = "left", x: float | None = None, y: float | None = None):
129138
"""
130139
Click a mouse button
131140
132141
Args:
133142
button: Mouse button to click ("left", "right", "middle")
134-
x: Optional X coordinate for absolute positioning before click
135-
y: Optional Y coordinate for absolute positioning before click
143+
x: Optional X coordinate (0.0 to 1.0) for absolute positioning before click
144+
y: Optional Y coordinate (0.0 to 1.0) for absolute positioning before click
136145
137146
Example::
138147
139148
# Click at current position
140149
hid.mouse_click("left")
141150
142-
# Click at specific coordinates
143-
hid.mouse_click("left", 32768, 32768)
151+
# Click at center of screen
152+
hid.mouse_click("left", 0.5, 0.5)
144153
145-
# Right-click
146-
hid.mouse_click("right")
154+
# Right-click at specific location
155+
hid.mouse_click("right", 0.75, 0.25)
147156
"""
148157
if x is not None and y is not None:
149158
self.call("mouse_click", button, x, y)
@@ -204,25 +213,25 @@ def mouse():
204213
pass
205214

206215
@mouse.command()
207-
@click.argument("x", type=int)
208-
@click.argument("y", type=int)
216+
@click.argument("x", type=float)
217+
@click.argument("y", type=float)
209218
def move(x, y):
210-
"""Move mouse to absolute coordinates (0-65535)"""
219+
"""Move mouse to absolute coordinates (0.0-1.0)"""
211220
self.mouse_move_abs(x, y)
212221
click.echo(f"Mouse moved to ({x}, {y})")
213222

214223
@mouse.command()
215-
@click.argument("dx", type=int)
216-
@click.argument("dy", type=int)
224+
@click.argument("dx", type=float)
225+
@click.argument("dy", type=float)
217226
def move_rel(dx, dy):
218-
"""Move mouse by relative offset (-127 to 127)"""
227+
"""Move mouse by relative offset (-1.0 to 1.0, where 1.0 is full screen)"""
219228
self.mouse_move_rel(dx, dy)
220229
click.echo(f"Mouse moved by ({dx}, {dy})")
221230

222231
@mouse.command(name="click")
223232
@click.option("--button", "-b", default="left", type=click.Choice(["left", "right", "middle"]))
224-
@click.option("--x", type=int, default=None, help="Optional X coordinate")
225-
@click.option("--y", type=int, default=None, help="Optional Y coordinate")
233+
@click.option("--x", type=float, default=None, help="Optional X coordinate (0.0-1.0)")
234+
@click.option("--y", type=float, default=None, help="Optional Y coordinate (0.0-1.0)")
226235
def mouse_click_cmd(button, x, y):
227236
"""Click a mouse button"""
228237
self.mouse_click(button, x, y)

packages/jumpstarter-driver-nanokvm/jumpstarter_driver_nanokvm/driver.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -222,18 +222,30 @@ async def _get_ws(self):
222222
return self._ws
223223

224224
@with_reauth
225-
async def _send_mouse_event(self, event_type: int, x: int, y: int):
225+
async def _send_mouse_event(self, event_type: int, button_state: int, x: float, y: float):
226226
"""
227227
Send a mouse event via WebSocket
228228
229229
Args:
230230
event_type: 0=mouse_up, 1=mouse_down, 2=move_abs, 3=move_rel, 4=scroll
231-
x: X coordinate or movement
232-
y: Y coordinate or movement
231+
button_state: Button state (0=no buttons, 1=left, 2=right, 4=middle)
232+
x: X coordinate (0.0-1.0 for abs/rel) or scroll amount (int for scroll)
233+
y: Y coordinate (0.0-1.0 for abs/rel) or scroll amount (int for scroll)
233234
"""
234235
ws = await self._get_ws()
235-
message = [2, event_type, x, y] # 2 indicates mouse event
236-
await ws.send_json(message)
236+
# Scale coordinates for absolute and relative movements
237+
if event_type == 2: # move_abs
238+
x_val = int(x * 32768)
239+
y_val = int(y * 32768)
240+
elif event_type == 3: # move_rel
241+
x_val = int(x * 32768)
242+
y_val = int(y * 32768)
243+
else:
244+
x_val = int(x)
245+
y_val = int(y)
246+
message = [2, event_type, button_state, x_val, y_val] # 2 indicates mouse event
247+
res = await ws.send_json(message)
248+
print(message, res)
237249
self.logger.debug(f"Sent mouse event: {message}")
238250

239251
def close(self):
@@ -301,38 +313,38 @@ async def reset_hid(self):
301313
self.logger.info("HID subsystem reset")
302314

303315
@export
304-
async def mouse_move_abs(self, x: int, y: int):
316+
async def mouse_move_abs(self, x: float, y: float):
305317
"""
306318
Move mouse to absolute coordinates
307319
308320
Args:
309-
x: X coordinate (0-65535, scaled to screen resolution)
310-
y: Y coordinate (0-65535, scaled to screen resolution)
321+
x: X coordinate (0.0 to 1.0, where 0.0 is left/top and 1.0 is right/bottom)
322+
y: Y coordinate (0.0 to 1.0, where 0.0 is left/top and 1.0 is right/bottom)
311323
"""
312-
await self._send_mouse_event(2, x, y)
324+
await self._send_mouse_event(2, 0, x, y)
313325
self.logger.debug(f"Mouse moved to absolute position: ({x}, {y})")
314326

315327
@export
316-
async def mouse_move_rel(self, dx: int, dy: int):
328+
async def mouse_move_rel(self, dx: float, dy: float):
317329
"""
318330
Move mouse relative to current position
319331
320332
Args:
321-
dx: X movement delta (-127 to 127)
322-
dy: Y movement delta (-127 to 127)
333+
dx: X movement delta (-1.0 to 1.0, where 1.0 is full screen width)
334+
dy: Y movement delta (-1.0 to 1.0, where 1.0 is full screen height)
323335
"""
324-
await self._send_mouse_event(3, dx, dy)
336+
await self._send_mouse_event(3, 0, dx, dy)
325337
self.logger.debug(f"Mouse moved by relative offset: ({dx}, {dy})")
326338

327339
@export
328-
async def mouse_click(self, button: str = "left", x: int | None = None, y: int | None = None):
340+
async def mouse_click(self, button: str = "left", x: float | None = None, y: float | None = None):
329341
"""
330342
Click a mouse button at current position or specified coordinates
331343
332344
Args:
333345
button: Mouse button to click ("left", "right", "middle")
334-
x: Optional X coordinate for absolute positioning before click
335-
y: Optional Y coordinate for absolute positioning before click
346+
x: Optional X coordinate (0.0 to 1.0) for absolute positioning before click
347+
y: Optional Y coordinate (0.0 to 1.0) for absolute positioning before click
336348
"""
337349
# Map button names to bit flags (left=1, right=2, middle=4)
338350
button_map = {"left": 1, "right": 2, "middle": 4}
@@ -345,11 +357,11 @@ async def mouse_click(self, button: str = "left", x: int | None = None, y: int |
345357
await asyncio.sleep(0.05)
346358

347359
# Send mouse down
348-
await self._send_mouse_event(1, button_code, 0)
360+
await self._send_mouse_event(1, button_code, 0.0, 0.0)
349361
# Small delay between down and up
350362
await asyncio.sleep(0.05)
351363
# Send mouse up
352-
await self._send_mouse_event(0, 0, 0)
364+
await self._send_mouse_event(0, 0, 0.0, 0.0)
353365

354366
self.logger.info(f"Mouse {button} clicked")
355367

@@ -362,7 +374,7 @@ async def mouse_scroll(self, dx: int, dy: int):
362374
dx: Horizontal scroll amount
363375
dy: Vertical scroll amount (positive=up, negative=down)
364376
"""
365-
await self._send_mouse_event(4, dx, dy)
377+
await self._send_mouse_event(4, 0, float(dx), float(dy))
366378
self.logger.debug(f"Mouse scrolled: ({dx}, {dy})")
367379

368380

0 commit comments

Comments
 (0)