Virtual keyboard for Raspberry Pi using 'uinput'
So you have a Raspberry Pi and you want to control it with a virtual keyboard. Once you know how things work it's quite easy (isn't always?). The hardest part is to find the right information. This blog describes all required steps.
Basic setup
The basic setup that I use:
process that creates 'uinput' device runs in first terminal session. process that runs via ssh in other terminal session
The process that 'hosts' the 'uinput'
opens a file descriptor sets the allowed input keys fills the device descriptor creates the device
// open a device file descriptor
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CREAT);
// specify with keys are allowed
for (i=0; i < 255; i++)
{
ioctl(fd, UI_SET_KEYBIT, i);
}
memset(&uidev, 0, sizeof(uidev));
// fill the device descriptors
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-fsays");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 2;
write(fd, &uidev, sizeof(uidev));
// create the device
ioctl(fd, UI_DEV_CREATE);
The program that writes keys to the newly created '/dev/input/event0' gets keystrokes and buffers the byte values in a chain. When the nth character is an ESCAPE character it determines whether it is an ESCAPE sequence (ESC + 2...4 bytes) or just a single character. When there's a match found, the match is written to '/dev/input/event0'. After that, it continues to read the bytes in the chained buffer.
Abstract view of key translation.
In order to run the uinput device in 'terminal 0', you need to start it via init.d.
Create a script in /etc/init.d Call this script 'fsaysuidev' Add 'fsaysuidev' to TARGETS in /etc/init.d/.depend.start sudo vim /etc/init.d/.depend.start' Create symbolic links from '/etc/init.d/fsaysuidev' to '/etc/rc.[2-5]/fsaysuidev' sudo ln -s /etc/init.d/fsaysuidev /etc/rc2.d/S05fsaysuidev sudo ln -s /etc/init.d/fsaysuidev /etc/rc3.d/S05fsaysuidev sudo ln -s /etc/init.d/fsaysuidev /etc/rc4.d/S05fsaysuidev sudo ln -s /etc/init.d/fsaysuidev /etc/rc5.d/S05fsaysuidev
The '/etc/init.d/fsaysuidev' script:
#! /bin/sh
### BEGIN INIT INFO
# Provides: fsaysuiinput
# Required-Start: $sudo
# Required-Stop:
# X-Start-Before: not applicable
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Provides a uinput device for pi's without a keyboard
# Description: Provide a uinput device for receiving keyboard input without having a physical keyboard connected to the pi
### END INIT INFO
N=/etc/init.d/fsaysuidev
set -e
case "$1" in
start )
# make sure privileges don't persist across reboots
echo "FSays input is starting in background..."
sudo /home/pi/fsaysuinput&
;;
stop|reload|restart|force-reload|status)
;;
* )
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
As you can see, my uinput device program is called 'fsaysuinput' and located in '/home/pi'. The program is started as background process, see the '&' behind the sudo command.
The program that writes the keys to '/dev/input/event0' is called fsayskeyboard. Mine is located at '/home/pi'. Depending on your settings and rights, you either can run it as user 'pi' or as user 'root'.
/home/pi/fsayskeyboard
sudo /home/pi/fsayskeyboard
So now I can start a terminal session on my laptop via 'putty'. Login as user 'pi'. Start the virtual keyboard program. Type characters and the characters not magically typed in the 'terminal 0' of the Raspberry. I can login in this session by just typing
pi
< ENTER >
[PASSWORD]
< ENTER >
Start programs, for example './c64.sh', which start VICE x64 emulator on my Rpi. Even inside this 'x64', the remote keyboard feature works. I can control 'Boulder' in 'Boulder Dash' just as if I would have normally with a real keyboard attached to the Rpi. You can download all source code
here .
N.B.: I developed the virtual keyboard more as a proof of concept. What I actually want to achieve is communicate via I2C to the Rpi, then translate this data to actual key strokes...