3

I stumbled upon this question when trying to figure out how to get a python script to send a left or right keystroke after button presses (utilizing the GPIO pins).

It seems like the chosen answer to the linked question is what I need to get me going but after installing xautomation, trying to adapt the code to my script and reading up on the documentation for Popen (I even tried running a new file with the code verbatim) I keep getting the following error:

Traceback (most recent call last):
  File "/home/zdistaging/Documents/xte test.py", line 17, in <module>
    keypress(shift_a_sequence)
  File "/home/zdistaging/Documents/xte test.py", line 15, in keypress
    p.communicate(input=sequence)
  File "/usr/lib/python3.4/subprocess.py", line 941, in communicate
    self.stdin.write(input)
TypeError: 'str' does not support the buffer interface

I'm running Python3 on a Pi 3 model B, in Raspbian Jessie with Pixel (downloaded from raspberrypi.org)

Any ideas why it's erroring out?

If it helps at all, all I'm trying to do is allow a user to scroll left and right in a FEH slideshow... I might be totally off the mark with this approach given how seemingly simple a task this is. I'm not looking for someone to solve this for me outright - I like the challenge associated with coding - I'm just super new to python; nudging me in the right direction would be super helpful.

Any help is greatly appreciated!!!

EDIT: Sorry about not including the code!

from subprocess import Popen, PIPE

control_f4_sequence = '''keydown Control_L
key F4
keyup Control_L
'''

shift_a_sequence = '''keydown Shift_L
key A
keyup Shift_L
'''

def keypress(sequence):
    p = Popen(['xte'], stdin=PIPE)
    p.communicate(input=sequence)

keypress(shift_a_sequence)
keypress(control_f4_sequence)

EDIT EDIT:

Here's my updated code... it actually prints spaces for both left and right button presses.

import time
import RPi.GPIO as GPIO
from subprocess import Popen, PIPE
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

leftArrow = '''key \x1B[D'''  # I've tried '''key Left'''
rightArrow = '''key \x1B[C''' # and '''key Right''' with the same results

offButton   = 26     # Black wire
onButton    = 19     # White wire
leftButton  = 13     # Red wire
rightButton =  6     # Green wire


def keypress(sequence):
    if isinstance(sequence, str):
        sequence = sequence.encode('ascii')
    p = Popen(['xte'], stdin=PIPE)
    p.communicate(input=sequence)


GPIO.setup( offButton, GPIO.IN, GPIO.PUD_UP )
GPIO.setup( onButton, GPIO.IN, GPIO.PUD_UP )
GPIO.setup( leftButton, GPIO.IN, GPIO.PUD_UP )
GPIO.setup( rightButton, GPIO.IN, GPIO.PUD_UP )


while True:
    offButton_state = GPIO.input( offButton )
    onButton_state = GPIO.input( onButton )
    leftButton_state = GPIO.input( leftButton )
    rightButton_state = GPIO.input( rightButton )

    if offButton_state == GPIO.LOW:
        print( "Off button pressed" )

    if onButton_state == GPIO.LOW:
        print( "On button pressed" )

    if leftButton_state == GPIO.LOW:
        keypress(leftArrow)
        print( "Left button pressed" )

    if rightButton_state == GPIO.LOW:
        keypress(rightArrow)
        print( "Right button pressed" )

    time.sleep( 1 )

I've read up on subprocess and Popen.communicate() but couldn't really tell if the problem had something to do with that or with what xte is expecting as an argument. Thoughts?

Community
  • 1
  • 1
A.C.
  • 41
  • 8

2 Answers2

1

The error indicates that your control sequences are strings (i.e. unicode), but Subprocess seems to expect bytes.

In function keypress, convert the sequence into bytes like so:

if isinstance(sequence, str):
    sequence = sequence.encode('ascii')

A very good writeup about bytes, strings, and unicode can be found here: https://nedbatchelder.com/text/unipain.html

Torben Klein
  • 2,943
  • 1
  • 19
  • 24
  • Holy cow!!! That worked like a charm, thanks so much!!! It is doing something weird though... even though I defined different sequences for the left and right arrows, both are giving me spaces. – A.C. Mar 10 '17 at 21:58
  • Also, that's an awesome writeup, thanks for sharing! – A.C. Mar 10 '17 at 21:59
0

I've been looking at the same examples, here's my working example for 6 buttons: (it's somewhat messy, but my debug lines might help others too)

import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
from Xlib import X
from subprocess import Popen, PIPE

buttons = [18,         23,         24,         25,        8,     7 ]
opcodes = ['next', 'enter', 'alt tab', 'previous', 'spacebar', 'shift' ]
opcodes2 = ['key Left ', 'key Up ', 'key Down ', 'key Right ', 'key Enter ', 'key Shift_L ']

# set the gpio pins 
for button in buttons:
    GPIO.setup(button, GPIO.IN, GPIO.PUD_UP )

def keypress(sequence):
    #if isinstance(sequence, str):
    #sequence = sequence.encode('ascii')
    p = Popen(['xte', '-x:0'], stdin=PIPE)
    p.communicate(input=sequence)

def main():
    while True:
        button_state = []
        for button in buttons:
            button_state.append(GPIO.input(button))

        for item in range(len(button_state)):
            if button_state[item] == 0:
                print (opcodes2[item] ) #debugging
           # send X key for keystroke in (for the given iteration of the loop) opcodes[button.output(index)]
                #print (repr(str(opcodes2[item]).encode('ascii')))
                keypress(str(opcodes2[item]).encode('ascii'))
        print (repr(button_state)) #for debugging
        time.sleep(0.3)
        del button_state

if __name__ == '__main__':
    main()

note the trailing whitespace (could be any char) within opcodes2 per command. the ascii encode was dropping the last character on me, so this is my somewhat ugly workaround.