Warm-Up no.06, Major Key(boards and mice)
Introduction
The CPX can function, because it connects through USB, as what is called a Human Interface Device or HID. This allows it to appear (to our computer) as a keyboard, or a mouse, or what are called “consumer controls” (the play or pause buttons for controlling media which is a good way to “fake” playing higher quality audio with the CPX).
For reference, I am using the examples for the keyboard and consumer controls from this page and the examples for the mouse from this page
Sending Keyboard Messages
This first example sends individual keycodes. This is probably most relevant for non-alphanumeric keys like the arrow keys or SHIFT or CMD. Here’s an introductory example
# our imports
# ------------------------------------------------------>
import usb_hid
"""
note that, this HID functionality is unique to the
circuit python express (there is an older "non-express"
version that is discontinued). Because of this we import
cpx, rather than cp.
"""
from adafruit_circuitplayground.express import cpx
"""
use this to act as the keyboard
this is where the "send" commands from the
CPX to the computer come from
"""
from adafruit_hid.keyboard import Keyboard
"""
these are all the codes we use to give
the specific "code" of the key we want to
pretend to press. If we didn't have this
we'd have to refer to a table of numbers
or something like this.
"""
from adafruit_hid.keycode import Keycode
# ------------------------------------------------------>
# our keyboard object
# this does some setting up
kbd = Keyboard(usb_hid.devices)
# ------------------------------------------------------>
while True:
# if we press button a, send an O or an o
# the switch controls the shift key
# ----------------------------------->
if cpx.button_a:
if cpx.switch:
kbd.send(Keycode.SHIFT, Keycode.O)
else:
kbd.send(Keycode.O)
while cpx.button_a:
# pass means do nothing
# we just need to do this
# to prevent multiple undesired
# keypresses.
pass
# if we press button b,
# send an X or an x, depending
# on whether the switch is "on"
# ----------------------------------->
if cpx.button_b:
if cpx.switch:
kbd.send(Keycode.SHIFT, Keycode.X)
else:
kbd.send(Keycode.X)
while cpx.button_b:
pass
# ------------------------------------------------------>
here's the code above again but with less verbose so you can see that it isn't quite so complicated:
# our imports
# ------------------------------------------------------>
import usb_hid
from adafruit_circuitplayground.express import cpx
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
# ------------------------------------------------------>
kbd = Keyboard(usb_hid.devices)
# ------------------------------------------------------>
while True:
if cpx.button_a:
if cpx.switch:
kbd.send(Keycode.SHIFT, Keycode.O)
else:
kbd.send(Keycode.O)
while cpx.button_a:
pass
if cpx.button_b:
if cpx.switch:
kbd.send(Keycode.SHIFT, Keycode.X)
else:
kbd.send(Keycode.X)
while cpx.button_b:
pass
# ------------------------------------------------------>
You can also send multiple key presses to, for example, send a message
# imports
# ------------------------------------------------------------>
import usb_hid
from adafruit_circuitplayground.express import cpx
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
# ------------------------------------------------------------>
# we need this code to "start up"
# the underlying code for the kbd and the "layout"
# which understands the keys on the keyboard
kbd = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(kbd)
# the loop
# ------------------------------------------------------------>
while True:
# if we press button a,
# make a bigass message
if cpx.button_a:
# the \n below inserts a linebreakz
layout.write('We are the Borg.\nLower your shields and surrender your ships.\nWe will add your biological and technological distinctiveness to our own.\nYour culture will adapt to service us.\nResistance is futile.\n')
while cpx.button_a:
pass
You may need to reference all the keycodes, especially if you want to work with non-alphanumeric keys. Those are listed here
Controlling Consumer Controls
Here’s the consumer control code. If you have a YouTube video open and the window is “in focus” (selected) the consumer controls should cause the video to play and pause if you use that option.
# imports
# ---------------------------------------------------->
import usb_hid
from adafruit_circuitplayground.express import cpx
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
# this is needed to "start up" our consumer controls
# we then refer to the functions needed with cc
cc = ConsumerControl(usb_hid.devices)
# the loop
# ---------------------------------------------------->
while True:
# if we press button a,
# pause or play the currently selected content
if cpx.button_a:
cc.send(ConsumerControlCode.PLAY_PAUSE)
# while the button is pressed down, do nothing
# (pass does nothing). This prevents multiple
# undesired keypresses
while cpx.button_a:
pass
Controlling the Mouse
Here’s a simple example, using the capacitive touch sensors on the CPX to control the mouse and the scrollwheel. There are three parameters in the move() function you’ll see below. First is the x position, second is y and last is the scrollwheel. Note that the location is relative to the mouse’s original position. That is to say, you don’t say the specific position you want the mouse to move to, you say the amount you want it to move from it’s current position.
"""
This is slightly modified code from the adafruit site to
use CPX and its capacitive touch sensors to move the mouse.
I mainly added comments
The original author and license are below:
SPDX-FileCopyrightText: 2018 Anne Barela for Adafruit Industries
SPDX-License-Identifier: MIT
"""
# our imports we need the first two for the mouse
# -------------------------------------------------->
import usb_hid
from adafruit_hid.mouse import Mouse
from adafruit_circuitplayground.express import cpx
# -------------------------------------------------->
# the mouse object, we need this line so that
# some of the HID stuff gets set up "behind the scenes"
# I don't know specifically what it does but it will
# not work without this.
# note that m is for convenienve/simplicity and the
# mouse can be named anything.
# -------------------------------------------------->
m = Mouse(usb_hid.devices)
# adjust settings for cap touch
cpx.adjust_touch_threshold(200)
speed = 6
# -------------------------------------------------->
# MAIN LOOP
# -------------------------------------------------->
while True:
# move the mouse LEFT
if cpx.touch_A4:
m.move(speed * -1, 0, 0)
# move the mouse RIGHT
if cpx.touch_A3:
m.move(speed, 0, 0)
# move the mouse UP
if cpx.touch_A7:
m.move(0, speed * -1, 0)
# move the mouse DOWN
if cpx.touch_A1:
m.move(0, speed, 0)
# scrollwheel UP
if cpx.touch_A2:
m.move(0,0, speed)
# scrollwheel DOWN
if cpx.touch_A5:
m.move(0,0, speed * -1)
# -------------------------------------------------->
Tilting Out
Here’s an example of something unique to the CPX we can do, which is use the accelerometer or tilt control the mouse. The accelerometer works with the cpx.acceleration tuple. It has x, y, and z values, we access x with cpx.acceleration[0] and y with cpx.acceleration[1], similar to how we talked to the neopixels.
There’s a little bit of math here (multiplication). If you want to edit this code, know that if you don’t have a way to turn off the mouse accelerometer control, it will be annoying to edit the code
"""
use the CPX to control the mouse with the CPX's onboard accelerometer
"""
# our imports
# ------------------------------------------>
import usb_hid
import time
from adafruit_circuitplayground.express import cpx
from adafruit_hid.mouse import Mouse
# our variables
# ------------------------------------------>
# this sets up the "m" variable as our mouse "object"
m = Mouse(usb_hid.devices)
"""
this controls how much we are multiplying the value
from the accelerometer by.
If we leave it as is (1) 90 degrees in either axis,
the plotter reads about 9 - 10
(use the serial port to check this)
we're starting at 2 for a more dramatic effect
"""
magnifier = 2
# where we store how much to move the mouse
mouse_x = 0
mouse_y = 0
# our loop
# ------------------------------------------>
while True:
# when pressing button A we increase the value of
# the magnifier
if cpx.button_a:
magnifier += 1
# (don't do anything while the button is pressed
# so we don't get multiple presses)
while cpx.button_a:
pass
# button B decreases the value of the magnifier
if cpx.button_b:
magnifier -= 1
# (don't do anything while the button is pressed
# so we don't get multiple presses)
while cpx.button_b:
pass
"""
we now read the acceleration sensor
cpx.acceleration does this.
acceleration has x y and z
we're only looking for x and y values
to access them individually we use the
brackets and select the number we want.
This is similar to accessing the individual
neopixels.
This then gets "magnified" or multiplied by the number
we have in magnifier. Button A will increase it B will decrease it.
The other new thing we are doing is using the "int()" function
around the output from the sensor. The output from the sensor,
if you look at the output from the sensor in the serial console
(look for the acceleration example) you'll see it uses floating
point numbers (0.12312190842, etc). the m.move() function below
wants wht are called "integers" or whole numbers. The "int"
function converts the numbers for us.
"""
mouse_x = int(cpx.acceleration[0]* magnifier)
mouse_y = int(cpx.acceleration[1]* magnifier)
"""
m.move() will move the mouse,
the first value is the x amount
the second value is the y amount
the third is the scroll wheel
the values are relative to your current position
they aren't an exact location on the screen.
"""
m.move(mouse_x, mouse_y, 0)
here's the above code again, except with fewer comments.
"""
use the CPX to control the mouse with
the CPX's onboard accelerometer
"""
# our imports
# ------------------------------------------>
import usb_hid
import time
from adafruit_circuitplayground.express import cpx
from adafruit_hid.mouse import Mouse
# our variables
# ------------------------------------------>
# this sets up the "m" variable as our mouse "object"
m = Mouse(usb_hid.devices)
# how much to multiply tilt by
magnifier = 2
# where we store how much to move the mouse
mouse_x = 0
mouse_y = 0
# our loop
# ------------------------------------------>
while True:
# when pressing button A we increase the value of
# the magnifier
if cpx.button_a:
magnifier += 1
while cpx.button_a:
pass
# button B decreases the value of the magnifier
if cpx.button_b:
magnifier -= 1
while cpx.button_b:
pass
# read the accelerometer
mouse_x = int(cpx.acceleration[0]* magnifier)
mouse_y = int(cpx.acceleration[1]* magnifier)
# move the mouse based on values we
# captures from accelerometer
m.move(mouse_x, mouse_y, 0)