Raspberry Pi Pico
LED Button Keypad
A nicer way to make a macropad is to use some LED buttons. For this, I used a circuit that I have used before. The button pins are connected to GND and to pins GP2 to GP5. The LEDs are connected to GND via a 220ohm resistor. The positive pins are connected to pins GP6 to GP9. This is a slightly more complex than on the previous page and lets you have an indicator light for each button.
This Fritzing shows how you might set this up with the separate components.
When the first button is pressed, text is written to the screen with some timing. I did this because one of the things I use Macropads for is to perform timed sequences of actions in games. For example, in the game No Man's Sky, there is a set of techniques called 'glitch building' which work by timing button presses to perfection. Having a macro makes it easier to do this reliably. What you see here has nothing to do with the game but shows how you might easily time sequences of button presses.
The second button triggers some key presses, pretty much at once, with no precise timing. The last two buttons are for adjusting the volume and show how you would do multimedia stuff using a custom button pad.
You need the library on your Pico for this,
import board from time import sleep from digitalio import DigitalInOut, Pull, Direction import usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS from adafruit_hid.keycode import Keycode from adafruit_hid.consumer_control import ConsumerControl from adafruit_hid.consumer_control_code import ConsumerControlCode kbd = Keyboard(usb_hid.devices) layout = KeyboardLayoutUS(kbd) cc = ConsumerControl(usb_hid.devices) # function to read buttons into a binary pattern, 1 for pressed def read_btns(btn_list): result = 0 for i, b in enumerate(btn_list): result += (b.value^1)<<i return result # tells if a button is pressed def pressed(pattern, b): return pattern>>b & 1 # sets leds based on a binary value def set_leds(led_list, pattern): for i, l in enumerate(led_list): l.value = pattern >> i & 1 # set up button pins btn_pins = [board.GP2, board.GP3, board.GP4, board.GP5] btns = [DigitalInOut(p) for p in btn_pins] # set up as buttons for b in btns: b.switch_to_input(pull = Pull.UP) # set up LED pins led_pins = [board.GP6, board.GP7, board.GP8, board.GP9] leds = [DigitalInOut(p) for p in led_pins] # set direction for l in leds: l.direction = Direction.OUTPUT previous = 0 while True: reading = read_btns(btns) set_leds(leds, reading) if reading!=previous: if pressed(reading, 0): # writing text and timing layout.write("A message.\n") sleep(1) for c in "This is a message for you.": layout.write(c) sleep(0.2) layout.write("\n") elif pressed(reading,1): # send a load of key strokes kbd.send(*[Keycode.SHIFT, Keycode.M, Keycode.ENTER]) elif pressed(reading,2): cc.send(ConsumerControlCode.VOLUME_INCREMENT) elif pressed(reading,3): cc.send(ConsumerControlCode.VOLUME_DECREMENT) else: sleep(0.1) previous = reading sleep(0.01)
No Man's Sky Glitch Building Macropad
If you have been playing No Man's Sky for long enough and have watched a few videos or live streams about building in the game, you will have come across the term 'glitch building'. If you don't already know the term or the game then glitch building is about trying to extend the capabilities of the in-game build system beyond what appears to have been intended. This is done by pressing combinations of keys in rapid succession. This allows you to build in ways that the developers may not have intended but are not actively seeking to prevent.
Some players already use macros to help them carry out the key combinations more reliably than is otherwise possible. They tend to use the macro buttons on their mice and keyboards. I use a laptop for playing the game and don't have the macro keys. I like to have a single button press to execute the macro and don't want to have to set a shortcut combo that might clash with software I use. For that reason, I use some mechanical keys on a breadboard with an Adafruit Itsy Bitsy. So far, I have used an Arduino program. I thought I'd see how well the code translates into CircuitPython using the LED button layout shown above.
The following code shows the 3 glitch-building macros I use. The second button is used for a right adjacency glitch. The third button is used for all glitches involving wires (blender, reverse wire etc.). The first button is used for storing items in the cache when you are doing glitches to resize items or the universal adjacency glitch. I have left the last button unused for the moment.
import board from time import sleep from digitalio import DigitalInOut, Pull, Direction import usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode from adafruit_hid.mouse import Mouse kbd = Keyboard(usb_hid.devices) m = Mouse(usb_hid.devices) # function to read buttons into a binary pattern, 1 for pressed def read_btns(btn_list): result = 0 for i, b in enumerate(btn_list): result += (b.value^1)<<i return result # tells if a button is pressed def pressed(pattern, b): return pattern>>b & 1 # sets leds based on a binary value def set_leds(led_list, pattern): for i, l in enumerate(led_list): l.value = pattern >> i & 1 # set up button pins btn_pins = [board.GP2, board.GP3, board.GP4, board.GP5] btns = [DigitalInOut(p) for p in btn_pins] # set up as buttons for b in btns: b.switch_to_input(pull = Pull.UP) # set up LED pins led_pins = [board.GP6, board.GP7, board.GP8, board.GP9] leds = [DigitalInOut(p) for p in led_pins] # set direction for l in leds: l.direction = Direction.OUTPUT previous = 0 while True: reading = read_btns(btns) set_leds(leds, reading) if reading!=previous: if pressed(reading, 0): # cache a part kbd.press(Keycode.C) kbd.press(Keycode.Q) sleep(0.017) kbd.release_all() elif pressed(reading,1): # adjacency glitch kbd.press(Keycode.E) m.press(Mouse.LEFT_BUTTON) sleep(0.017) kbd.release_all() m.release_all() elif pressed(reading,2): # wire glitch kbd.press(Keycode.Q) m.press(Mouse.LEFT_BUTTON) sleep(0.017) kbd.release_all() m.release_all() elif pressed(reading,3): #spare button print("Button 4") else: sleep(0.1) previous = reading
This is not quite perfect but is so much more reliable than I can do with a keyboard and mouse or a gamepad. It works as well with CircuitPython as it does with compiled Arduino code, which is pleasing. The wire glitch is the least reliable of the 3 options but still so much better than I can do without the macro. Messing with the delays might make a difference but, to be honest, this is good enough to build with. Maybe one day I will solder the circuit to some nice protoboard or place inside a decent enclosure.