• No results found

The GPIO keypad input

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/.

Getting ready

Perform the following steps to install uInput: 1. First we need to download 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

2. Install the required packages (if you have installed them already, the apt-get command will ignore them) using the following commands:

sudo apt-get install python3-setuptools python3-dev sudo apt-get install libudev-dev

3. Compile and install uInput using the following commands:

cd python-uinput-master sudo python3 setup.py install

4. Finally, we load the new 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

5. Create the following circuit using the following equipment:

‰ Breadboard (half-sized or larger) ‰ 7x Dupont female to male patch wires ‰ Six push buttons

‰ 6x 470 ohm resistors

‰ Breadboarding wire (solid core)

GPIO keypad circuit layout

The keypad circuit can also be built into a permanent circuit by soldering the components into vero prototype board (also known as stripboard), as shown in the following image:

6. Connect the circuit to the Raspberry Pi P1 GPIO pins as follows:

Button P1 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

How to do it…

Create a gpiokeys.py script as follows: #!/usr/bin/python3

#gpiokeys.py import time

import RPi.GPIO as GPIO import uinput #HARDWARE SETUP # P1 # 2[==G=====<=V==]26 # 1[===2=1>^=====]25 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)

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:

How it works…

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.

There's more…

We can do more using uinput to provide hardware control for other programs, including those that require mouse input.

Generating other key combinations

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:

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

Emulating mouse events

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)