2

Working on a project that uses a little keyboard and an E-ink display. I have tried a couple of keyboard packages for python (pynput, pyxhook) and have written/tested simple keystroke loggers that work fine on my desktop (ubuntu)

However I try to run them on the pi both libraries die

DisplayConnectionError: Can't connect to display ":0": [Errno 111] Connection refused

I know at least pyxhook has the ability to capture mouse movement so that makes sense why it would "Need" access to the monitor. But all I want is a way to capture the keyboard input in a process running in the background but with no monitor attached

The libraries can also return the current window that has focus as part of the key event, and that may be the other reason the monitor is tied in so deep.I tried

$export DISPLAY=":0"

did not help.

here is simple code for pynput, works with monitor but not when running headless

#!/usr/bin/env python

from pynput import keyboard

def on_press(key):
    print('Key {} pressed.'.format(key))
    if str(key) == 'Key.esc':
        print('Exiting...')
        return False


with keyboard.Listener(on_press = on_press) as listener:
    listener.join()

Is there any way to get these to work, or possibly a different way of a approaching this.

EDIT: full stack trace of above program failing

Traceback (most recent call last):
  File "./keylog.py", line 3, in <module>
    from pynput import keyboard
  File "/usr/local/lib/python2.7/dist-packages/pynput/__init__.py", line 23, in <module>
    from . import keyboard
  File "/usr/local/lib/python2.7/dist-packages/pynput/keyboard/__init__.py", line 49, in <module>
    from ._xorg import KeyCode, Key, Controller, Listener
  File "/usr/local/lib/python2.7/dist-packages/pynput/keyboard/_xorg.py", line 38, in <module>
    from pynput._util.xorg import (
  File "/usr/local/lib/python2.7/dist-packages/pynput/_util/xorg.py", line 38, in <module>
    _check()
  File "/usr/local/lib/python2.7/dist-packages/pynput/_util/xorg.py", line 36, in _check
    display = Xlib.display.Display()
  File "/usr/local/lib/python2.7/dist-packages/Xlib/display.py", line 89, in __init__
    self.display = _BaseDisplay(display)
  File "/usr/local/lib/python2.7/dist-packages/Xlib/display.py", line 71, in __init__
    protocol_display.Display.__init__(self, *args, **keys)
  File "/usr/local/lib/python2.7/dist-packages/Xlib/protocol/display.py", line 90, in __init__
    self.socket = connect.get_socket(name, protocol, host, displayno)
  File "/usr/local/lib/python2.7/dist-packages/Xlib/support/connect.py", line 87, in get_socket
    return mod.get_socket(dname, protocol, host, dno)
  File "/usr/local/lib/python2.7/dist-packages/Xlib/support/unix_connect.py", line 113, in get_socket
    raise error.DisplayConnectionError(dname, str(val))
Xlib.error.DisplayConnectionError: Can't connect to display ":0": [Errno 111] Connection refused
  • it is the print command that outputs to screen – jsotola Feb 28 '18 at 23:28
  • I am running it through an SSH connection, so the print() is fine. I will put the full stack trace in the question, it shows its coming from the keyboard listener. And to be clear, I do not want/expect to capture keyboard input from the remote machine, that is just how I am montoring logs and such. I only want to capture keyboard input from a keyboard connected to the pi directly. – Chad G Feb 28 '18 at 23:39
  • do you have the tty module available? – jsotola Mar 1 '18 at 0:54
  • @jsotola yes I do – Chad G Mar 1 '18 at 1:50
  • But so far everything i am seeing using tty and termios looks like is capturing from stdin, so as soon as that program is in the background it wont be able to capture anything. If fact the one sample piece I found would exit if i was running in the background, but worked fine in the foreground assuming I kept focus on that window – Chad G Mar 1 '18 at 2:02
1

Ok, i figured it out, figured I would post the answer.

pythons keyboard module, docs and source here

as stated in the "Known Limitations" section, (even though I don't think this is a limitation!)

"To avoid depending on X, the Linux parts reads raw device files (/dev/input/input*) but this requires root."

So this does bring up security issues obviously since the program now needs root privileges, but for my case this is not an issue.

pip install keyboard

simple program

import keyboard
import time

def key_press(key):
    print(key.name)

keyboard.on_press(key_press)

while True:
    time.sleep(1)
  • When I type the code from the last reply, I got this error: AttributeError: 'module' object has no attribute 'on_press' Please, can you advice me on this? – Johny 1984 Feb 13 at 14:24
  • @Johny1984 Is your script file name keyboard.py? or do you have such a file? This is conflicting with your import(its importing your file, not the correct module) need to change your file name to be unique. I just ran these commands from a terminal and they still work fine. – Chad G Feb 13 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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