Text Editor
Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.
Alternatively, you can use any text editor that saves simple text files.
Download the Project Bundle
Your project will use a specific set of CircuitPython libraries, and the code.py file. To get everything you need, click on the Download Project Bundle link below, and uncompress the .zip file.
Drag the contents of the uncompressed bundle directory onto your board's CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary. The CIRCUITPY drive appears when you plug the QT Py into the computer via USB.
# SPDX-FileCopyrightText: 2023 John Park w/ Tod Kurt ps2controller library # # SPDX-License-Identifier: MIT # The Takara Game of Life PlayStation roulette wheel controller spinner (TAKC-00001) # sends two sets of held CIRCLE buttons with randomized hold time periods # this code turns that into mouse click spamming (the CIRCLE button also spams) # Tested on QT Py RP2040 import time import board import usb_hid import neopixel from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard import Keyboard from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS from adafruit_hid.mouse import Mouse from ps2controller import PS2Controller # turn on neopixel led = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.1) led.fill(0x331000) # amber while we wait for controller to connect mouse = Mouse(usb_hid.devices) keyboard = Keyboard(usb_hid.devices) layout = KeyboardLayoutUS(keyboard) # create controller object with QT Py wiring psx = PS2Controller( dat=board.A0, cmd=board.A1, att=board.A2, clk=board.A3 ) led.fill(0x0010ee) # a nice PlayStation blue circle_held = False spam_speed = 0.001 buttonmap = { ("SELECT"): (0, Keycode.SPACEBAR), ("START"): (0, Keycode.X), ("UP"): (0, Keycode.W), ("DOWN"): (0, Keycode.S), ("RIGHT"): (0, Keycode.D), ("LEFT"): (0, Keycode.A), ("L3"): (0, Keycode.V), ("R3"): (0, Keycode.B), ("L2"): (0, Keycode.R), ("R2"): (0, Keycode.T), ("L1"): (0, Keycode.F), ("R1"): (0, Keycode.G), ("TRIANGLE"): (0, Keycode.I), ("CIRCLE"): (1, Mouse.LEFT_BUTTON), # for mouse clicks ("CROSS"): (0, Keycode.K), ("SQUARE"): (0, Keycode.L), } print("PlayStation Roulette Wheel controller") while True: events = psx.update() if events: print(events) for event in events: if buttonmap[event.name][0] == 0: # regular button if event.pressed: keyboard.press(buttonmap[event.name][1]) if event.released: keyboard.release(buttonmap[event.name][1]) if buttonmap[event.name][0] == 1: # mouse button if event.pressed: circle_held = True if event.released: circle_held = False if circle_held: # spam the mouse click mouse.press(buttonmap["CIRCLE"][1]) mouse.release_all() time.sleep(spam_speed)
How It Works
The code uses the ps2controller
library to interpret the PlayStation controller messages, then the adafruit_hid
library is used to send USB keyboard commands and mouse clicks.
Libraries
First, the necessary libraries and modules are imported.
import time import board import usb_hid import neopixel from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard import Keyboard from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS from adafruit_hid.mouse import Mouse from ps2controller import PS2Controller
NeoPixel Setup
The on-board NeoPixel is set up next to be used as a status indicator -- amber during boot up and blue when a PSX/PS2 controller has been successfully connected.
led = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.1) led.fill(0x331000) # amber while we wait for controller to connect
Mouse and Keyboard Setup
Next, we create instances of Mouse
, Keyboard
, and KeyboardLayoutUS
.
mouse = Mouse(usb_hid.devices) keyboard = Keyboard(usb_hid.devices) layout = KeyboardLayoutUS(keyboard)
PS2Controller
We'll created an object called psx
that is an instance of the PS2Controller
with the necessary pin configuration to use it on the QT Py. After the controller is set up the NeoPixel is set to blue.
psx = PS2Controller( dat=board.A0, cmd=board.A1, att=board.A2, clk=board.A3 ) led.fill(0x0010ee)
Variables
A boolean variable called circle_held
is used to hold the state of the spinner -- while the O (circle) button is held (meaning the spinner is spinning) this variable is True
and the rapid mouse button spamming will occur. When the spinner stops the mouse button stops spamming.
The spam_speed
variable is used to adjust the mouse-click rate.
circle_held = False spam_speed = 0.001
Buttonmap
The buttonmap
dictionary is defined to map the controller button names to USB HID keycodes or mouse-clicks. The first item in each key is a 0
or 1
to indicate if keycodes or mouse events are sent, while the second item is the specific keycode or mouse event.
buttonmap = { ("SELECT"): (0, Keycode.SPACEBAR), ("START"): (0, Keycode.X), ("UP"): (0, Keycode.W), ("DOWN"): (0, Keycode.S), ("RIGHT"): (0, Keycode.D), ("LEFT"): (0, Keycode.A), ("L3"): (0, Keycode.V), ("R3"): (0, Keycode.B), ("L2"): (0, Keycode.R), ("R2"): (0, Keycode.T), ("L1"): (0, Keycode.F), ("R1"): (0, Keycode.G), ("TRIANGLE"): (0, Keycode.I), ("CIRCLE"): (1, Mouse.LEFT_BUTTON), ("CROSS"): (0, Keycode.K), ("SQUARE"): (0, Keycode.L), }
Main Loop
The main loop of the program first checks for any PSX controller events with psx.update()
.
Each controller event is checked to see if it should trigger a keycode or mouse event.
The events are then sent as per the buttonmap
mappings.
Keycodes are pressed and then released along with their corresponding buttons, while the O key that the spinner sends is treated specially -- it rapidly clicks the left mouse button, making it perfect for clicker games!
while True: events = psx.update() if events: print(events) for event in events: if buttonmap[event.name][0] == 0: # regular button if event.pressed: keyboard.press(buttonmap[event.name][1]) if event.released: keyboard.release(buttonmap[event.name][1]) if buttonmap[event.name][0] == 1: # mouse button if event.pressed: circle_held = True if event.released: circle_held = False if circle_held: # spam the mouse click mouse.press(buttonmap["CIRCLE"][1]) mouse.release_all() time.sleep(spam_speed)
Text editor powered by tinymce.