Created
February 13, 2020 07:16
-
-
Save pondahai/52fc80e72456b7979e93790e2c24dce5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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