We have seen how we can monitor inputs on the GPIO to launch applications and control the Raspberry Pi; however, sometimes we need to control third-party programs. Using the uInput
library, we can emulate key presses from a keyboard (or even mouse movement) to control any program, using our own custom hardware.
For more information about using uInput
, visit http://tjjr.fi/sw/python-uinput/.
Perform the following steps to install uInput
:
uInput
.You will need to download the uInput
Python library from Github (~50 KB) using the following commands:
wget https://github.com/tuomasjjrasanen/python-uinput/archive/master.zip unzip master.zip
The library will unzip to a directory called python-uinput-master
.
Once completed, you can remove the ZIP file using the following command:
rm master.zip
apt-get
command will ignore them) using the following commands:sudo apt-get install python3-setuptools python3-dev sudo apt-get install libudev-dev
uInput
using the following commands:cd python-uinput-master sudo python3 setup.py install
uinput
kernel module using the following command:sudo modprobe uinput
To ensure it is loaded on startup, we can add uinput
to the modules
file using the following command:
sudo nano /etc/modules
Put uinput
on a new line in the file and save it (Ctrl + X,Y).
The keypad circuit can also be built into a permanent circuit by soldering the components into a Vero prototype board (also known as a stripboard), as shown in the following image:
This circuit is available as a solder-yourself kit from PiHardware.com.
Button |
GPIO pin | |
---|---|---|
GND |
6 | |
v |
B_DOWN |
22 |
< |
B_LEFT |
18 |
^ |
B_UP |
15 |
> |
B_RIGHT |
13 |
1 |
B_1 |
11 |
2 |
B_2 |
7 |
Create a gpiokeys.py
script as follows:
#!/usr/bin/python3 #gpiokeys.py import time import RPi.GPIO as GPIO import uinput #HARDWARE SETUP # GPIO # 2[==G=====<=V==]26[=======]40 # 1[===2=1>^=====]25[=======]39 B_DOWN = 22 #V B_LEFT = 18 #< B_UP = 15 #^ B_RIGHT = 13 #> B_1 = 11 #1 B_2 = 7 #2 DEBUG=True BTN = [B_UP,B_DOWN,B_LEFT,B_RIGHT,B_1,B_2] MSG = ["UP","DOWN","LEFT","RIGHT","1","2"] #Setup the DPad module pins and pull-ups def dpad_setup(): #Set up the wiring GPIO.setmode(GPIO.BOARD) # Setup BTN Ports as INPUTS for val in BTN: # set up GPIO input with pull-up control #(pull_up_down can be: # PUD_OFF, PUD_UP or PUD_DOWN, default PUD_OFF) GPIO.setup(val, GPIO.IN, pull_up_down=GPIO.PUD_UP) def main(): #Setup uinput events = (uinput.KEY_UP,uinput.KEY_DOWN,uinput.KEY_LEFT, uinput.KEY_RIGHT,uinput.KEY_ENTER,uinput.KEY_ENTER) device = uinput.Device(events) time.sleep(2) # seconds dpad_setup() print("DPad Ready!") btn_state=[False,False,False,False,False,False] key_state=[False,False,False,False,False,False] while True: #Catch all the buttons pressed before pressing the related keys for idx, val in enumerate(BTN): if GPIO.input(val) == False: btn_state[idx]=True else: btn_state[idx]=False #Perform the button presses/releases (but only change state once) for idx, val in enumerate(btn_state): if val == True and key_state[idx] == False: if DEBUG:print (str(val) + ":" + MSG[idx]) device.emit(events[idx], 1) # Press. key_state[idx]=True elif val == False and key_state[idx] == True: if DEBUG:print (str(val) + ":!" + MSG[idx]) device.emit(events[idx], 0) # Release. key_state[idx]=False time.sleep(.1) try: main() finally: GPIO.cleanup() #End
First, we import uinput
and define the wiring of the keypad buttons. For each of the buttons in BTN
, we enable them as inputs with internal pull-ups enabled.
Next, we set up uinput
, defining the keys we want to emulate and adding them to the uinput.Device()
function. We wait a few seconds to allow uinput
to initialize, set the initial button and key states, and start our main
loop.
The main
loop is split into two sections: the first part checks through the buttons and records the states in btn_state
, and the second part compares the btn_state
with the current key_state
array. This way, we can detect a change in btn_state
and call device.emit()
to toggle the state of the key.
To allow us to run this script in the background, we can run it with &
as shown in the following command:
sudo python3 gpiokeys.py &
The &
character allows the command to run in the background, so we can continue with the command line to run other programs. You can use fg
to bring it back to the foreground, or %1
, %2
, and so on if you have several commands running. Use jobs
to get a list.
You can even put a process/program on hold to get to the command prompt by pressing Ctrl + Z and then resume it with bg
(which will let it run in the background).
You can test the keys using the game created in the Creating an overhead scrolling game recipe in Chapter 4, Creating Games and Graphics, which you can now control using your GPIO directional pad. Don't forget that if you are connecting to the Raspberry Pi remotely, any key presses will only be active on the locally connected screen.
We can do more using uinput
to provide hardware control for other programs, including those that require mouse input.
You can create several different key mappings in your file to support different programs. For instance, the events_z80
key mapping would be useful for a Spectrum Emulator such as
fuze (browse to http://raspi.tv/2012/how-to-install-fuse-zx-spectrum-emulator-on-raspberry-pi for details). The events_omx
key mappings are suitable for controlling video played through the OMX Player using the following command:
omxplayer filename.mp4
You can get a list of keys supported by omxplayer
by using the -k
parameter.
Replace the line that defines the events
list with a new key mapping, and select different ones by assigning them to events using the following code:
events_dpad = (uinput.KEY_UP,uinput.KEY_DOWN,uinput.KEY_LEFT, uinput.KEY_RIGHT,uinput.KEY_ENTER,uinput.KEY_ENTER) events_z80 = (uinput.KEY_Q,uinput.KEY_A,uinput.KEY_O, uinput.KEY_P,uinput.KEY_M,uinput.KEY_ENTER) events_omx = (uinput.KEY_EQUAL,uinput.KEY_MINUS,uinput.KEY_LEFT, uinput.KEY_RIGHT,uinput.KEY_P,uinput.KEY_Q)
You can find all the KEY
definitions in the input.h
file; you can view it using the less
command (press Q to exit) as shown in the following command:
less /usr/include/linux/input.h
The uinput
library can emulate mouse and joystick events as well as keyboard presses. To use the buttons to simulate a mouse, we can adjust the script to use mouse events (as well as defining mousemove
to set the step size of the movement) using the following code:
MSG = ["M_UP","M_DOWN","M_LEFT","M_RIGHT","1","Enter"] events_mouse=(uinput.REL_Y,uinput.REL_Y, uinput.REL_X, uinput.REL_X,uinput.BTN_LEFT,uinput.BTN_RIGHT) mousemove=1
We also need to modify the button handling to provide continuous movement, as we don't need to keep track of the state of the keys for the mouse. To do so, use the following code:
#Perform the button presses/releases #(but only change state once) for idx, val in enumerate(btn_state): if MSG[idx] == "M_UP" or MSG[idx] == "M_LEFT": state = -mousemove else: state = mousemove if val == True: device.emit(events[idx], state) # Press. elif val == False: device.emit(events[idx], 0) # Release. time.sleep(0.01)
18.188.66.13