Skip to content

Instantly share code, notes, and snippets.

@pondahai
Created February 13, 2020 07:16
Show Gist options
  • Save pondahai/52fc80e72456b7979e93790e2c24dce5 to your computer and use it in GitHub Desktop.
Save pondahai/52fc80e72456b7979e93790e2c24dce5 to your computer and use it in GitHub Desktop.
# GPIOkbd.py
# written by Roger Woollett
# This is a python equivalent to the Adafruit Retrogame program.
# It translates GPIO button presses into keyboard presses.
# It assumes that buttons will gound their GPIO when pressed.
# All testing has been done using python3
# This program must have root priviledge. This is fine if run from rc.local
# but if you are testing use sudo python3 GPIOkbd.py
# You must install uinport for this to work
# sudo pip3 install python-uinport
# Help(ui) shows a list of the symbols that represent keyboard keys.
# You can also define a button that causes system shutdown when pressed
# for more than 2 seconds.
# modify for scratchboy by Dahai Pon
#
import uinput as ui
import RPi.GPIO as gp
from os import system
from time import sleep
import pyautogui
# gpio 16 @ left down key, gpio 5 @ right down key
# funciton key
FUNC_GPIO = 5
CLICK_GPIO = 16
# create bindings between keys and gpio
# TODO - change this to suit your needs
bindings = ((-1,CLICK_GPIO),(-1,FUNC_GPIO),(ui.KEY_VOLUMEDOWN,-1),(ui.KEY_VOLUMEUP,-1),(ui.KEY_F5,-1),(ui.KEY_UP,6),(ui.KEY_SPACE,20),(ui.KEY_UP,26),(ui.KEY_RIGHT,12),(ui.KEY_LEFT,27),(ui.KEY_DOWN,22))
# define gpio for shutdown (exit) button
# comment out the last line of this program
# if you do not want to cause a system shutdown
# TODO change this to suit your needs
# if you do not want a shutdown key set to 0
#SHUTDOWN_GPIO = 4
# make sure kernal module is loaded
system("modprobe uinput")
# always use Broadcom numbers
gp.setmode(gp.BCM)
oldkey = [1]*28
funckey = 0
left_click_signal = 0
right_click_signal = 0
exit_btn_count = 0
class KeyBtn:
# class to associate a GPIO button with a keyboard press
def __init__(self,device,key,gpio):
self.device = device
self.key = key
gp.setup(gpio,gp.IN,pull_up_down = gp.PUD_UP)
gp.add_event_detect(gpio,gp.BOTH,callback = self.callback)
def key_process(self, channel):
global funckey
global left_click_signal
global right_click_signal
global exit_btn_count
try:
if gp.input(channel) == 0:
if channel == FUNC_GPIO:
funckey = 1
right_click_signal = 1
else:
if funckey == 1 and channel == CLICK_GPIO:
self.device.emit(ui.KEY_F5, 1)
self.device.emit(ui.KEY_F5, 0)
elif funckey == 1 and channel == 26:
self.device.emit(ui.KEY_VOLUMEUP, 1)
self.device.emit(ui.KEY_VOLUMEUP, 0)
exit_btn_count = 0
elif funckey == 1 and channel == 22:
self.device.emit(ui.KEY_VOLUMEDOWN, 1)
self.device.emit(ui.KEY_VOLUMEDOWN, 0)
exit_btn_count = 0
else:
if funckey == 0 and channel == CLICK_GPIO:
left_click_signal = 1
elif self.key != -1:
self.device.emit(self.key, 1)
oldkey[channel] = 1
else:
if channel == FUNC_GPIO:
funckey = 0
else:
if funckey == 1 and channel == CLICK_GPIO:
self.device.emit(ui.KEY_F5, 0)
elif funckey == 1 and channel == 26:
self.device.emit(ui.KEY_VOLUMEUP, 0)
elif funckey == 1 and channel == 22:
self.device.emit(ui.KEY_VOLUMEDOWN, 0)
else:
if self.key != -1:
self.device.emit(self.key, 0)
oldkey[channel] = 0
sleep(0.03)
# global oldkey
# sleep(0.04)
# gpinput = gp.input(channel)
# if gpinput != oldkey[channel]:
# sleep(0.1)
# if gpinput != oldkey[channel]:
# oldkey[channel] = gpinput
# if gpinput == 0:
# self.device.emit(self.key, 1)
# else:
# self.device.emit(self.key, 0)
except:
pass
def callback(self,channel):
# because of key bounce check button is really down
#print(oldkey)
#sleep(0.05)
self.key_process(channel)
class ExitBtn:
# class to implement a button that causes program to terminate
def __init__(self,gpio):
if gpio != 0:
gp.setup(gpio,gp.IN,pull_up_down = gp.PUD_UP)
self.gpio = gpio
def check_continue(self):
if self.gpio == 0:
return True
# return False if button pressed for longer than 2 seconds
count = 20
while count:
if gp.input(self.gpio):
# button is not pressed
return True
sleep(0.1)
count -= 1
# if we get here it is time to exit
return False
# create uinput device
events = []
for(key,gpio) in bindings:
if key != -1:
events.append(key)
device = ui.Device(events)
# create KeyBtn objects
for(key,gpio) in bindings:
if gpio != -1:
KeyBtn(device,key,gpio)
## This button causes program to exit
#exit_button = ExitBtn(SHUTDOWN_GPIO)
# check if we should exit every half second
def mouse_click_screen_center():
try:
x,y = pyautogui.size()
#pyautogui.moveTo(x//2,y//2)
pyautogui.click(x//2,y//2)
pyautogui.moveTo(x//2,y-8)
except:
pass
def mouse_right_click_screen_center():
try:
x,y = pyautogui.size()
#pyautogui.moveTo(x//2,y//2)
pyautogui.click(button='right',x=x//2,y=y-8)
pyautogui.moveTo(x//2,y-8)
except:
pass
x,y = pyautogui.size()
pyautogui.moveTo(x//2,y-8)
while True:
#while exit_button.check_continue():
try:
for(key,gpio) in bindings:
if gpio != -1:
if gpio != CLICK_GPIO and gp.input(gpio) == 1 and oldkey[gpio] == 0:
# release process, somehow callback not deal with release
if key != -1:
device.emit(key,0)
oldkey[gpio] = 1
if left_click_signal == 1:
# mouse function can not running in callback
mouse_click_screen_center()
left_click_signal = 0
if right_click_signal == 1:
mouse_right_click_screen_center()
right_click_signal = 0
if gp.input(FUNC_GPIO) == 0:
exit_btn_count=exit_btn_count+1
if gp.input(FUNC_GPIO) == 1:
exit_btn_count = 0
if exit_btn_count > 99:
break
sleep(0.06)
except:
pass
# All done so exit
device.destroy()
gp.cleanup()
sleep(3)
system("reboot")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment