Skip to content

Commit c25124d

Browse files
authored
Merge pull request #2424 from jepler/snes-mouse
Add code for SNES mouse to USB HID with CircuitPython
2 parents f0771c1 + b587e23 commit c25124d

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

CircuitPython_SNES_Mouse/code.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# SPDX-FileCopyrightText: 2023 Jeff Epler for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
import time
4+
import board
5+
import digitalio
6+
from adafruit_hid.mouse import Mouse
7+
from usb_hid import devices
8+
9+
SCALE = 3
10+
11+
def delta(value): # Convert 8 bit value to signed number of distance steps
12+
value = ~value # All value is inverted on the bus
13+
if value & 0x80: # and is in sign-magnitude format
14+
return -(value & 0x7f)
15+
else:
16+
return value & 0x7f
17+
18+
mouse = Mouse(devices)
19+
20+
spi = board.SPI()
21+
strobe = digitalio.DigitalInOut(board.RX)
22+
strobe.switch_to_output(False)
23+
24+
if not spi.try_lock():
25+
raise SystemExit("could not lock SPI bus")
26+
27+
spi.configure(baudrate=100_000, polarity=1)
28+
29+
# Wait for the mouse to be ready at power-on
30+
time.sleep(2)
31+
32+
# A buffer to fetch mouse data into
33+
data = bytearray(4)
34+
35+
print("Mouse is ready!")
36+
while True:
37+
# Request fresh data
38+
strobe.value = True
39+
strobe.value = False
40+
41+
# Must do read in 2 pieces with delay in between
42+
spi.readinto(data, end=2)
43+
spi.readinto(data, start=2)
44+
lmb = bool(~data[1] & 0x40) # data is inverted on the bus
45+
rmb = bool(~data[1] & 0x80)
46+
dy = delta(data[2])
47+
dx = delta(data[3])
48+
49+
50+
# Pressing both buttons together emulates the wheel
51+
wheel = lmb and rmb
52+
53+
# Compute the new button state
54+
old_buttons = mouse.report[0]
55+
mouse.report[0] = (
56+
0 if wheel else
57+
mouse.LEFT_BUTTON if lmb else
58+
mouse.RIGHT_BUTTON if rmb else
59+
0)
60+
61+
# If there's any movement, send a move event
62+
if dx or dy:
63+
if wheel:
64+
mouse.move(dx * SCALE, 0, wheel=-dy)
65+
else:
66+
mouse.move(dx * SCALE, dy * SCALE)
67+
elif old_buttons != mouse.report[0]:
68+
mouse.press(0) # Send buttons previously set via report[0]

0 commit comments

Comments
 (0)