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
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.
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...
On 24-8-2014 17:41:30, neema_t wrote:

comment=You+say+your+goal+is+to+communicate+via+I2C+then+translate+the+data+to+keystrokes%2C+I'm+trying+to+do+something+similar%3B+I+want+to+hook+up+a+keyboard+matrix+to+some+shift+registers+then%2C+um%2C+jiggle+some+bits+to+and+from+the+registers+to+get+keystroke+data+then+use+that+to+give+me+keystrokes.+So+far+I+haven't+tried+that+with+SPI+or+I2C+or+whatever%2C+it's+just+been+bit-banging+with+other+GPIO+pins.+Anyway%2C+did+you+have+much+success%3F+There's+no+post+date+on+this+so+I'm+just+assuming+it's+at+least+a+few+months+old.+Thanks+for+this%2C+though%2C+when+I+finish+my+soup+I'll+get+back+to+my+Pi+and+see+if+I+can+make+it+do+things.

On 26-8-2014 19:29:01, Erwin van Dijk wrote:

comment=Yes%2C+I+have+things+working.+In+my+blog+http%3A%2F%2Fwww.fsays.eu%2FBlogging%2FBlog%2FDetails%2F27+you+can+see+my+arcade+controller+and+there+are+links+to+the+previous+steps.+Which+reminds+me+that+I+have+to+update+the+other+posts+to+link+to+the+next+steps...+%0D%0AI+you+have+any+questions+about+one+of+the+steps%2C+just+let+me+know.

On 11-3-2015 11:26:12, magdesign wrote:

comment=Thanks+for+sharing+this!%0D%0AI+tried+your+solution+but+have+a+little+problem%3A+My+application+is+looking+for+a+keyboard+in+%2Fdev%2Finput%2Fby-path%2F+and+your+solution+as+described+creates+only+a+keyboard+event+in+%2Fdev%2Finput.%0D%0A%0D%0AIs+there+a+possibility+to+modify+your+code+to+create+a+fake+keyboard+as+mentioned%3F%0D%0AIf+yes%2C+what+do+I+have+to+add%2Fchange%3F%0D%0AMany+thanks+

On 11-3-2015 14:20:40, magdesign wrote:

comment=Just+to+answer+my+question+by+myself%3A%0D%0A%0D%0Ajust+create+symlinks+in+%2Fdev%2Finput%2Fby-path+to+event0%0D%0A%0D%0Ain+my+example+I+did%3A+%0D%0Aln+-s+%2Fdev%2Finput%2Fevent0+%2Fdev%2Finput%2Fby-path%2Fplatform-bcm2708_usb-usb-0%3A1.2.4%3A1.0-event-kbd%0D%0A%0D%0Aand%0D%0A%0D%0Aln+-s+%2Fdev%2Finput%2Fevent0+%2Fdev%2Finput%2Fby-id%2Fusb-046a_0023-event-kbd%0D%0A%0D%0Athanks+for+your+lovely+code!

On 11-3-2015 20:41:42, Erwin van Dijk wrote:

comment=Hi+magdesign%2C+%0D%0AThank+you+for+answering+your+own+question.+I+think+it+is+valuable+for+other+people+as+well.+Keep+the+code+rockin'+!%0D%0A%0D%0ARegards%2C%0D%0AErwin

On 22-9-2017 00:04:03, Kamil wrote:

comment=Hi%2C+your+project+works+fine+but+what+about+when+mouse+is+connected+to+rpi%3F%0D%0AMouse+is+connected+to+%2Fdev%2Finput%2Fevent0%2C+fsaysuinput+starts+then+on+event1+and+fsayskeyboard+send+keys+to+event0...+

On 22-9-2017 09:06:04, Erwin van Dijk wrote:

comment=You+can+make+the+hardcode+link+to+event0+configurable.+If+you+change+the+program+such+that+you+can+specify+the+event%23+number%2C+than+your+problem+is+solved%2C+I+guess.+%0D%0AAs+I+stated+in+the+blog%2C+the+program+was+used+as+a+proof+of+concept+and+the+basic+use+case+is+simulating++keystrokes+either+from+other+terminal+session+or+from+a+program.+So+in+my+setup%2C+no+HIDs+were+attached.+I've+successfully+applied+this+concept+to+my+Arcade+box+with+VICE%2C+a+C64+emulator.+The+Arcade+buttons+simulate+key+strokes++which+are+interpreted+by+VICE+as+if+it+where+real+key+strokes.+Let+me+ask+you+something%2C+just+out+of+curiosity%3A+which+use+case+are+you+trying+to+solve%3F+Kind+regards%2C+Erwin+van+Dijk

On 22-9-2017 09:12:10, Erwin van Dijk wrote:

comment=The+code+that+links+to+event0+is+located+in+'fsayskeyboard.cpp'%0D%0A%0D%0AFSaysKeyboard%3A%3AFSaysKeyboard(char*+eventPath)%7B%0D%0A++++_p_firstKeystroke+%3D+NULL%3B%0D%0A++++_p_lastKeystroke+%3DNULL%3B%0D%0A%0D%0A++++fd+%3D+open(%22%2Fdev%2Finput%2Fevent0%22%2C+O_RDWR)%3B%0D%0A++++%2F%2Ffd+%3D+open(eventPath%2C+O_RDWR)%3B%0D%0A++++if(fd)%7B%0D%0A++++++++memset(%26event%2C+0%2C+sizeof(event))%3B%0D%0A++++++++memset(%26event%2C+0%2C+sizeof(event_end))%3B%0D%0A++++++++keepRunning+%3D+true%3B%0D%0A++++++++status+%3D+0%3B%0D%0A++++%7D%0D%0A++++else%0D%0A++++%7B%0D%0A++++++++printf(%22Errro+open+keyboard%3A%26%23000%3Bs%5Cn%22%2C+strerror(errno))%3B%0D%0A++++++++status+%3D+-1%3B%0D%0A++++%7D%0D%0A++++%0D%0A%7D

On 22-9-2017 09:32:06, Kamil wrote:

comment=Thx+for+your+reply.+I've+solved+this+already+%3A)

On 22-9-2017 11:07:50, Erwin van Dijk wrote:

comment=You're+welcome!

On 2-3-2018 12:36:12, Andy H wrote:

comment=Sorry+if+I'm+being+stupid+here%2C+but+I'm+a+real+Raspberry+Pi+noob+and+came+across+this+post+via+the+PocketVJ+project+by+magdesign+(who+commented+previously)...%0D%0A%0D%0AYou+mention+3+files+but+there+are+only+2+code+examples+in+this+post+-+the+init.d%2Ffsaysuidev+script+is+clearly+identified%2C+but+I+am+not+sure+what+should+be+in+fsaysuinput+and+what+should+be+in+fsayskeyboard+or+where+those+files+need+to+be+placed!

On 3-3-2018 11:17:22, Erwin van Dijk wrote:

comment=All+code+is+available+for+download+at%3A%0D%0Ahttps%3A%2F%2Fwww.fsays.eu%2Fdownloads%2Ffsaysuinput.tgz%0D%0A%0D%0AIt+contains+fsayskeyboard%2C+fsaysuinput+and+fsaysuidev+which+should+be+placed+in+%2Fetc%2Finit.d%2F+as+described.+The+compiled+versions+of++fsayskeyboard+and+fsaysuinput+should+be+stored+in+%2Fhome%2Fpi+in+this+example.+Hope+this+helps+you+in+getting+things+up+and+running!

On 25-9-2018 11:26:53, YusufBAYLAV wrote:

comment=Hello+Erwin%2C%0D%0A%0D%0AI+need+to+implement+something+very+similar+to+your+project.+I've+got+an+HID%2C+which+is+actually+a+touch+device.+It+is+something+called+AirBar+in+shape+of+a+stick.+This+device+is+emitting+IR+and+can+detect+x%2Cy+coordinates.+It+can+turn+any+surface+into+a+touchpad.+But+I've+got+a+relatively+complicated+problem+in+my+hand.+%0D%0AWhat+I+want+to+achieve+is+turning+this+device+into+a+programmable+touch+device.+At+that+point%2C+I+decided+to+get+a+raspberry+pi+zero+w+as+it+is+the+smallest%2C+lightest+and+the+cheapest+on+among+its+alternatives.+%0D%0AI+managed+to+compile+the+code+of+the+device+for+RPI%2C+I+can+attach+the+device+to+RPI+via+usb+port+and+get+the+x%2Cy+coordinates.+But+I+needed+also+simulate+the+keystrokes+and+map+each+x%2Cy+range+to+a+particular+character+or+character+group+such+as+%2212a%22%2C+%22125%5Cr%5Cn%22%2C+%22abC%22.+And+send+this+string+to+a+%22Windows%22+device(either+via+usb+or+bluetooth+or+any+other+way+you+can+offer).+And+replace+a+normal+barcode+reader+with+my+programmable+touch+device.+Since+RPI0+has+only+one+usb+port+I+attached+my+HID+aka+AirBAR+from+usb+port.+By+the+help+of+some+tutorials+I+found+on+the+internet+I+turned+RPI+into+an+Bluetooth+keyboard+and+send+characters.+If+I+unplug+the+Airbar+and+replace+it+with+a+keyboard%2C+the+normal+usb+keyboard+the+characters+I+type+via+that+very+keyboard+can+be+sent+to+the+attached+android+phone+of+mine.+(I+mean+I+can+use+the+cable+usb+keyboard+%2B+RPI0+as+simple+bluetooth+keyboard)+But+I+could+not+manage+it+to+work+with+Windows+or+Mac+machines.+Also+the+client+application+of+the+bluetooth+trick+is+not+working+without+any+physical+usb+keyboard+attached+directly+to+raspberry%2C+is+not+sending+characters+other+that+very+keyboard.+(Although+I'm+getting+connected+to+the+RPI+via+ssh+and+start+the+client+from+there%2C+no+characters+typed+in+that+ssh+session+are+sent)+Could+you+give+me+a+hand+on+that%3F+%0D%0A%0D%0ABR%2C%0D%0AYusuf

Back to List

All form fields are required.
A confirmation mail for the comments will be send to you.