It's easy to use the CursorControl module with CircuitPython. This module allows you to easily write Python code which generates and controls a mouse cursor on your CircuitPython device's display.
CursorControl Module Installation
Next you'll need to install the Adafruit CircuitPython CursorControl library on your CircuitPython board.
First make sure you are running the latest version of Adafruit CircuitPython for your board.
Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle. Our introduction guide has a great page on how to install the library bundle for both express and non-express boards.
Remember for non-express boards like the, you'll need to manually install the necessary libraries from the bundle:
- adafruit_cursorcontrol.mpy
- cursorcontrol_cursormanager.mpy
You can also download the adafruit_cursorcontrol.mpy from its releases page on Github.
Before continuing make sure your board's lib folder or root filesystem has the adafruit_cursorcontrol.mpy and cursorcontrol_cursormanager.mpy files are copied over.
Next connect to the board's serial REPL so you are at the CircuitPython >>> prompt.
CircuitPython Usage
To demonstrate the usage of the CursorControl library, we'll use the example below. Save the file below to a code.py file. Then, upload the code.py file to the CIRCUITPY drive.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import displayio from adafruit_cursorcontrol.cursorcontrol import Cursor from adafruit_cursorcontrol.cursorcontrol_cursormanager import CursorManager # Create the display display = board.DISPLAY # Create the display context splash = displayio.Group() # initialize the mouse cursor object mouse_cursor = Cursor(display, display_group=splash) # initialize the cursormanager cursor = CursorManager(mouse_cursor) # show displayio group display.root_group = splash while True: cursor.update() if cursor.is_clicked: if mouse_cursor.hidden: mouse_cursor.show() else: mouse_cursor.hide() time.sleep(0.01)
After saving the code.py to your CIRCUITPY drive, you should see a cursor appear on your device's display.
Move the cursor around by pressing the PyBadge's D-Pad buttons or moving the PyGamer's Joystick!
CursorControl Module Overview
The CursorControl library contains two classes, Cursor
and CursorManager
. The Cursor
class is responsible for generating a cursor bitmap, displaying it on the screen, and adjusting the cursor's properties.
The CursorManager
is a high-level class responsible for initializing a hardware interface for the cursor. This includes methods to set up the joystick or buttons and control the cursor's properties using them.
Let's take a look at a short example to understand how these two classes interact.
First, the example creates a display object (using the board's builtin DISPLAY
) and a displayio group. This step is required - the Cursor
class does not handle generating a displayio group.
- For more information about DisplayIO Groups in CircuitPython, check out this guide.
# Create the display display = board.DISPLAY # Create the display context splash = displayio.Group(max_size=5)
The example next initializes the Cursor
object by passing it the board's display interface and the display group.
If you want to set the cursor's properties during Cursor
initialization (to hide the cursor when a game starts or increase the cursor's scale) - take a look at the __init__
keyword arguments for this class here.
# initialize the mouse cursor object mouse_cursor = Cursor(display, display_group=splash)
While you now have a cursor object (and loading the code so far will make a cursor appear on your display) - you need a way of controlling it. You could control it from the loop and create methods to read the joystick and buttons, but we've already gone ahead and built a class to do this.
If you're using a PyGamer or PyBadge, all you need to do to control a Cursor
is pass the Cursor
object to the CursorManager
# initialize the cursormanager cursor = CursorManager(mouse_cursor)
Then, you'll set the display to "show" the displayio splash group
# show displayio group display.show(splash)
The top of the loop calls cursor.update()
. This method within CursorManager
handles button presses, joystick movement and d-pad button clicks. It also sets the CursorManager
's is_clicked
property.
while True: cursor.update() if cursor.is_clicked: if mouse_cursor.hide: mouse_cursor.hide = False else: mouse_cursor.hide = True time.sleep(0.01)
Next, we'll want to see if the cursor was clicked. The .is_clicked
property is set by a call to cursor.update()
and is a boolean. If it's true, you can hide the Cursor
by setting its .hide
property.
Buttons and Text Elements with Cursor
Below is an advanced example which uses the Display Text module as well as the Button module. Moving the cursors over the button and clicking set different Cursor attributes such as cursor speed and cursor scale size.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import displayio from adafruit_button import Button from adafruit_display_text import label import terminalio from adafruit_cursorcontrol.cursorcontrol import Cursor from adafruit_cursorcontrol.cursorcontrol_cursormanager import CursorManager # Create the display display = board.DISPLAY # Create the display context splash = displayio.Group() # Use the built-in system font font = terminalio.FONT ########################################################################## # Make a background color fill color_bitmap = displayio.Bitmap(display.width, display.height, 1) color_palette = displayio.Palette(1) color_palette[0] = 0x404040 bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) splash.append(bg_sprite) ########################################################################## # Set up button/label properties BUTTON_WIDTH = 80 BUTTON_HEIGHT = 40 BUTTON_MARGIN = 20 LBL_HEADER = [100, 20] LBL_TEXT = [120, 40] # Resize buttons for small display (PyGamer) if display.width < 240: BUTTON_WIDTH = int(BUTTON_WIDTH / 2) BUTTON_HEIGHT = int(BUTTON_HEIGHT / 2) BUTTON_MARGIN = int(BUTTON_MARGIN / 2) LBL_HEADER[0] -= 75 LBL_HEADER[1] -= 10 LBL_TEXT[0] -= 70 LBL_TEXT[1] += 55 # Create the buttons buttons = [] button_speed_inc = Button( x=BUTTON_MARGIN, y=BUTTON_MARGIN + BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Speed+", label_font=font, ) buttons.append(button_speed_inc) button_speed_dec = Button( x=BUTTON_MARGIN, y=BUTTON_MARGIN * 4 + BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Speed-", label_font=font, ) buttons.append(button_speed_dec) button_scale_pos = Button( x=BUTTON_MARGIN * 3 + 2 * BUTTON_WIDTH, y=BUTTON_MARGIN + BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Scale+", label_font=font, style=Button.SHADOWRECT, ) buttons.append(button_scale_pos) button_scale_neg = Button( x=BUTTON_MARGIN * 3 + 2 * BUTTON_WIDTH, y=BUTTON_MARGIN * 4 + BUTTON_HEIGHT, width=BUTTON_WIDTH, height=BUTTON_HEIGHT, label="Scale-", label_font=font, style=Button.SHADOWRECT, ) buttons.append(button_scale_neg) # Show the button for b in buttons: splash.append(b.group) # Create a text label text_label = label.Label( font, text="CircuitPython Cursor!", color=0x00FF00, x=LBL_HEADER[0], y=LBL_HEADER[1] ) splash.append(text_label) text_speed = label.Label(font, color=0x00FF00, x=LBL_TEXT[0], y=LBL_TEXT[1]) splash.append(text_speed) text_scale = label.Label(font, color=0x00FF00, x=LBL_TEXT[0], y=LBL_TEXT[1] + 20) splash.append(text_scale) # initialize the mouse cursor object mouse_cursor = Cursor(display, display_group=splash) # initialize the cursormanager cursor = CursorManager(mouse_cursor) # show displayio group display.root_group = splash prev_btn = None while True: cursor.update() if cursor.is_clicked is True: for i, b in enumerate(buttons): if b.contains((mouse_cursor.x, mouse_cursor.y)): b.selected = True print("Button %d pressed" % i) if i == 0: # Increase the cursor speed mouse_cursor.speed += 1 elif i == 1: # Decrease the cursor speed mouse_cursor.speed -= 1 if i == 2: # Increase the cursor scale mouse_cursor.scale += 1 elif i == 3: # Decrease the cursor scale mouse_cursor.scale -= 1 prev_btn = b elif prev_btn is not None: prev_btn.selected = False text_speed.text = "Speed: {0}px".format(mouse_cursor.speed) text_scale.text = "Scale: {0}px".format(mouse_cursor.scale) time.sleep(0.1)
Page last edited January 22, 2025
Text editor powered by tinymce.