How to tell which keyboard was used to press a key?
Disable device
Here's one idea towards identifying which keyboard is which. You can use the command xinput to enable and disable devices.
Example
$ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ SynPS/2 Synaptics TouchPad id=12 [slave pointer (2)]
⎜ ↳ TPPS/2 IBM TrackPoint id=13 [slave pointer (2)]
⎜ ↳ Logitech USB Receiver id=9 [slave pointer (2)]
⎜ ↳ Logitech USB Receiver id=10 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Sleep Button id=8 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=11 [slave keyboard (3)]
↳ ThinkPad Extra Buttons id=14 [slave keyboard (3)]
The above output shows the various devices that I have on my Thinkpad laptop. I only have 1 keyboard attached, this one:
↳ AT Translated Set 2 keyboard id=11 [slave keyboard (3)]
Now take a look at the properties available through this device:
$ xinput list-props "AT Translated Set 2 keyboard"
Device 'AT Translated Set 2 keyboard':
Device Enabled (124): 1
Coordinate Transformation Matrix (126): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.
From the above you can see that it's enabled, so let's disable it:
$ xinput set-prop "AT Translated Set 2 keyboard" "Device Enabled" 0
To enable it:
$ xinput set-prop "AT Translated Set 2 keyboard" "Device Enabled" 1
The idea?
You could enable disable one of the keyboards using this command to determine which one you're on.
References
- second keyboard to run commands
The question sounds a bit contradictory since you're citing X tools but ask for a solution that "ideally should work without X".
About your 4th finding:
xinput
will give you the correspondence
$ xinput list-props 11
Device 'AT Translated Set 2 keyboard':
Device Enabled (145): 1
Coordinate Transformation Matrix (147): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
Device Product ID (266): 1, 1
Device Node (267): "/dev/input/event0"
at least with the following version
$ xinput --version
xinput version 1.6.1
XI version on server: 2.3
First step: detecting the keyboard event device in C
#include <stdio.h>
//#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
// typical use : sudo ./a.out /dev/input/event*
int main (int argc, char *argv[])
{
struct input_event ev[64];
int fd[argc],rd,idev,value, size = sizeof (struct input_event);
char name[256] = "Unknown";
if(argc==1) return -1;
int ndev=1;
while(ndev<argc && (fd[ndev] = open (argv[ndev], O_RDONLY|O_NONBLOCK)) != -1){
ndev++;
}
fprintf (stderr,"Found %i devices.\n", ndev);
if(ndev==1) return -1;
while (1){
for(idev=1; idev<argc; idev++){
if( (rd=read (fd[idev], ev, size * 64)) >= size){
value = ev[0].value;
if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){
ioctl (fd[idev], EVIOCGNAME (sizeof (name)), name);
printf ("%s\n", name);
return idev;
}
}
}
// sleep(1);
}
return -1;
}
Many thanks to this page. I've stripped most safety checks from the code I borrowed there, for clarity, in real code you probably want them.
Note that key presses are echoed, so you may indeed want to kindly ask the user to hit a modifier key (Shift, Control...) rather than any key.
Second step: use xinput to get the X ID from the device name
Compile the above C source and use this way:
xinput list --id-only "keyboard:$(sudo ./a.out /dev/input/event*)"