Insert keypresses into the Linux console from Python
Asked Answered
B

2

7

I have recently been faced with a rather odd task, one result being the necessity for the ability to use DTMF (aka "Touch Tone") tones to control a non-X Linux computer's terminal. The computer has a modem which can be accessed through ALSA, and therefore the sox "rec" program, which is what I am reading the input through. The computer in question is otherwise completely isolated, having no Ethernet or other network interfaces whatsoever. The Goertzel algorithm implementation I am using works very well, as does the eSpeak speech synthesis engine which is the only source of output; this is supposed to work with any Touch Tone phone. It reads back both input (input being octal digits, one ASCII byte at a time)and whatever the dash shell feeds back -- the prompt, the output from commands, etc., using ASCII mnemonics for control characters.

The current method that I am using for interacting with dash and the programs launched through it is the pexpect module. However, I need it to be able to, on demand, read back the entire contents of the line on which the cursor is positioned, and I do not recall pexpect being able to do this (If it is, I cannot tell.). The only other solution that I can think of is to somehow use Python to either control, or act as, the keyboard and console drivers.

Is this, indeed, the only way to go about it (and if so, is it even possible with Python?), or is there another way of having direct access to the contents of the console?

Edit: Through dumb luck, I just recently found that the SVN version of PExpect has pexpect.screen. However, it does not have any way of actually running a program under it. I'll have to keep an eye on its development.

Badtempered answered 29/4, 2011 at 22:9 Comment(0)
T
3

The simple solution is to use the Linux kernel uinput interface. It allows you to insert keypresses and mouse events into the kernel, exactly as if they came from a physical human interface device. This would basically turn your application into a keyboard/mouse.

Since you are working with Python, I recommend you take a look at the python-uinput module.

If you are comfortable with binary I/O in Python, then you can certainly do the same without any libraries; just check out the /usr/include/linux/uinput.h header file for the structures involved (the interface is completely stable), and perhaps some uinput tutorials in C, too.

Note that accessing the /dev/uinput or /dev/input/uinput device (depending on your distribution) normally requires root privileges. I would personally run the Python service as a user and group dedicated to the service, and modify/add a udev rule (check all files under rules.d) to allow read-write access to the uinput device to that group, something like

SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
KERNEL=="uinput", MODE="0660", GROUP="the-dedicated-group"

However, if your Python application simply executes programs, you should make it a terminal emulator -- for example, using this. You can do it too without any extra libraries, using the Python pty; the main work is to however simulate a terminal with ANSI escape sequences, so that applications don't get confused, and the existing terminal emulators have such code.

Trichomoniasis answered 1/7, 2012 at 9:26 Comment(0)
C
0

If you want to manipulate the contents of the console, you probably want to use curses. It's well documented here. Look at window.getch() and window.getyx().

Cotyledon answered 30/4, 2011 at 0:6 Comment(4)
Ok, but how do I run a shell (like dash) inside of it?Badtempered
More precisely, how do I do so without re-implementing readline?Badtempered
Well, if readline is all you're using sh for, then there're python bindings for readline.Cotyledon
Yes, then, other than adding text (anyone for deleting text?), how can I manipulate that input buffer?Badtempered

© 2022 - 2024 — McMap. All rights reserved.