2

I've been on a quest to "map" some bluetooth speaker buttons to corrospond to the letters "d" and "f" to a non-existent keyboard. That is, there is no physical keyboard connected to my raspberry-pi. I've been spinning my wheel, to say the least.

The bluetooth speaker I have, has three button on top of it. A button to play andpause music, and a button to go forward, and finally, a button to go to the previous track.

When using the evdev module, I can view these buttons when they are pressed:

from evdev import InputDevice, categorize, ecodes
dev = InputDevice('/dev/input/event0')
print(dev)

for event in dev.read_loop():
   if event.type == ecodes.EV_KEY:
      print(categorize(event))

I get:

key event at 1465055027.204988, 163 (KEY_NEXTSONG), down
key event at 1465055027.206383, 163 (KEY_NEXTSONG), up
key event at 1465055028.666699, 165 (KEY_PREVIOUSSONG), down
key event at 1465055028.668083, 165 (KEY_PREVIOUSSONG), up

Minus the (KEY_PLAYCD) output. I left it out intentionally.

Below is some code I cobbled together, which I believe is close. I'm trying to "inject" or "write" the key "d", which is the "track forward" in "mpg123". When I run "mpg123" (from the command line) with the "-C" option, I can press the key "d" to move the track forward. Also, key "f" moves the track back. I would like to map these keys to the "KEY_NEXTSONG" and the "KEY_PREVIOUSSONG" (ecodes?). Is it possible? Here some code I'm using:

#!/usr/bin/python
#
from subprocess import Popen, PIPE
from evdev import InputDevice, categorize, ecodes

dev = InputDevice('/dev/input/event0')

print(dev)

# Start mpg123
p = Popen(['mpg123', '-C', '--list', '/home/pi/bluemusic/playlist.txt','random']           
    , stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)

def getKey():
    for event in dev.read_loop():
        if event.type == ecodes.EV_KEY:
           c = categorize(event)
           if c.keystate == c.key_down:
               yield c.keycode

keygenerator = getKey()
while True:
    c = next(keygenerator)
    if c == 'KEY_NEXTSONG': p.stdin.write(ecodes.KEY[32])
    if c == 'KEY_PREVIOUSSONG': p.stdin.write(ecodes.KEY[33]
    if c == 'KEY_PLAYCD': print(c) #This doesn't output???


#p.stdin.write(' ') # sends a space to the running process

I know this code is miserably incorrect. When it comes to printing these events. That has been accomplished. I'm ready to start doing something useful with these buttons. Any help or suggestions would be appreciated.

-nitrolinux

3
  • Hello and welcome. Accepting an answer (as you did) is enough to mark a question solved. There's no need to change to title to reflect that and we tend to not use that here.
    – Ghanima
    Commented Jun 18, 2016 at 21:46
  • @Ghanima Sorry, new here. Will remember that in the future. Commented Jun 18, 2016 at 22:02
  • Not a problem, no harm done. Have a good time around.
    – Ghanima
    Commented Jun 18, 2016 at 22:09

1 Answer 1

1

The program mpg123 needs a pseudo-tty on stdin to work properly for interactive commands. Replace your Popen with something like

masterfd, slavefd = os.openpty()
pid = os.fork()
if pid==0:
  os.close(masterfd)
  os.dup2(slavefd, 0)
  os.close(slavefd)
  os.execlp('mpg123', 'mpg123', '-C', '--list', '/home/pi/bluemusic/playlist.txt', 'random')
os.close(slavefd)

and your loop's p.stdin.write() with os.write(masterfd, ecodes.KEY[32]) etc. The above opens a pty, forks and the child moves the pty file number to 0, ie stdin before running the program. Note you need 'mpg123' once as the program to run, and once again as argv 0, the name it has in this low-level call. The parent closes the slave end of the pty and writes to the master end.

3
  • Thank you. That worked! I will look over this code and try to make sense of it. I would had never figured that out on my own. I thought I would be able to write to "stdin" the original way I had it. Isn't the "os" module becoming deprecated in the future? Anyway thank you. I have something to build on. Commented Jun 18, 2016 at 21:31
  • Your code would be ok for many programs, though you would probably need to add a flush(), but mpg123 doesnt work well with a pipe (try eg (sleep 4;echo f;sleep 4)|mpg123...). Higher level python modules such as pty and pexpect are useful when you need a pty and you want the output of the command, but in this case we are not interested in capturing the stdout of mpg123.
    – meuh
    Commented Jun 19, 2016 at 6:38
  • Hello everyone. I know this post is getting old, but I wanted to inform all that was involved in helping me accomplish this task, that I have wrote a detailed "howto" on what I did. If you would like to check it out, go to lhsspirit.com/linux . Thanks to everyone, especially you meuh. Commented Sep 1, 2016 at 12:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.