Is it possible for a daemon (i.e. background) process to look for key-presses from a USB keyboard?
Devices most likely get a file in /dev/input/
named eventN
where N is the various devices like mouse, keyboard, jack, power-buttons etc.
ls -l /dev/input/by-{path,id}/
should give you a hint.
Also look at:
cat /proc/bus/input/devices
Where Sysfs
value is path under /sys
.
You can test by e.g.
cat /dev/input/event2 # if 2 is kbd.
To implement use ioctl and check devices + monitor.
EDIT 2:
OK. I'm expanding on this answer based on the assumption /dev/input/eventN
is used.
One way could be:
At startup loop all
event
files found in/dev/input/
. Useioctl()
to request event bits:ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
then check if
EV_KEY
-bit is set.IFF set then check for keys:
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), &keybit);
E.g. if number-keys are interesting, then check if bits for
KEY_0
-KEY9
andKEY_KP0
toKEY_KP9
.IFF keys found then start monitoring event file in thread.
Back to 1.
This way you should get to monitor all devices that meet the wanted criteria. You can't only check for EV_KEY
as e.g. power-button will have this bit set, but it obviously won't have KEY_A
etc. set.
Have seen false positives for exotic keys, but for normal keys this should suffice. There is no direct harm in monitoring e.g. event file for power button or a jack, but you those won't emit events in question (aka. bad code).
More in detail below.
EDIT 1:
In regards to "Explain that last statement …". Going over in stackoverflow land here … but:
A quick and dirty sample in C. You'll have to implement various code to check that you actually get correct device, translate event type, code and value. Typically key-down, key-up, key-repeat, key-code, etc.
Haven't time, (and is too much here), to add the rest.
Check out linux/input.h
, programs like dumpkeys
, kernel code etc. for mapping codes. E.g. dumpkeys -l
Anyhow:
Run as e.g.:
# ./testprog /dev/input/event2
Code:
#include <stdio.h>
#include <string.h> /* strerror() */
#include <errno.h> /* errno */
#include <fcntl.h> /* open() */
#include <unistd.h> /* close() */
#include <sys/ioctl.h> /* ioctl() */
#include <linux/input.h> /* EVIOCGVERSION ++ */
#define EV_BUF_SIZE 16
int main(int argc, char *argv[])
{
int fd, sz;
unsigned i;
/* A few examples of information to gather */
unsigned version;
unsigned short id[4]; /* or use struct input_id */
char name[256] = "N/A";
struct input_event ev[EV_BUF_SIZE]; /* Read up to N events ata time */
if (argc < 2) {
fprintf(stderr,
"Usage: %s /dev/input/eventN\n"
"Where X = input device number\n",
argv[0]
);
return EINVAL;
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr,
"ERR %d:\n"
"Unable to open `%s'\n"
"%s\n",
errno, argv[1], strerror(errno)
);
}
/* Error check here as well. */
ioctl(fd, EVIOCGVERSION, &version);
ioctl(fd, EVIOCGID, id);
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
fprintf(stderr,
"Name : %s\n"
"Version : %d.%d.%d\n"
"ID : Bus=%04x Vendor=%04x Product=%04x Version=%04x\n"
"----------\n"
,
name,
version >> 16,
(version >> 8) & 0xff,
version & 0xff,
id[ID_BUS],
id[ID_VENDOR],
id[ID_PRODUCT],
id[ID_VERSION]
);
/* Loop. Read event file and parse result. */
for (;;) {
sz = read(fd, ev, sizeof(struct input_event) * EV_BUF_SIZE);
if (sz < (int) sizeof(struct input_event)) {
fprintf(stderr,
"ERR %d:\n"
"Reading of `%s' failed\n"
"%s\n",
errno, argv[1], strerror(errno)
);
goto fine;
}
/* Implement code to translate type, code and value */
for (i = 0; i < sz / sizeof(struct input_event); ++i) {
fprintf(stderr,
"%ld.%06ld: "
"type=%02x "
"code=%02x "
"value=%02x\n",
ev[i].time.tv_sec,
ev[i].time.tv_usec,
ev[i].type,
ev[i].code,
ev[i].value
);
}
}
fine:
close(fd);
return errno;
}
EDIT 2 (continued):
Note that if you look at /proc/bus/input/devices
you have a letter at start of each line. Here B
means bit-map. That is for example:
B: PROP=0
B: EV=120013
B: KEY=20000 200 20 0 0 0 0 500f 2100002 3803078 f900d401 feffffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=7
Each of those bits correspond to a property of the device. Which by bit-map means, 1 indicate a property is present, as defined in linux/input.h
. :
B: PROP=0 => 0000 0000
B: EV=120013 => 0001 0010 0000 0000 0001 0011 (Event types sup. in this device.)
| | | ||
| | | |+-- EV_SYN (0x00)
| | | +--- EV_KEY (0x01)
| | +------- EV_MSC (0x04)
| +----------------------- EV_LED (0x11)
+--------------------------- EV_REP (0x14)
B: KEY=20... => OK, I'm not writing out this one as it is a bit huge.
B: MSC=10 => 0001 0000
|
+------- MSC_SCAN
B: LED=7 => 0000 0111 , indicates what LED's are present
|||
||+-- LED_NUML
|+--- LED_CAPSL
+---- LED_SCROLL
Have a look at /drivers/input/input.{h,c}
in the kernel source tree. A lot of good code there. (E.g. the devices properties are produced by this function.)
Each of these property maps can be attained by ioctl
. For example, if you want to check what LED properties are available say:
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), &ledbit);
Look at definition of struct input_dev
in input.h
for how ledbit
are defined.
To check status for LED's say:
ioctl(fd, EVIOCGLED(sizeof(ledbit)), &ledbit);
If bit 1 in ledbit
are 1 then num-lock are lit. If bit 2 is 1 then caps lock is lit etc.
input.h
has the various defines.
Notes when it comes to event monitoring:
Pseudo-code for monitoring could be something in the direction of:
WHILE TRUE
READ input_event
IF event->type == EV_SYN THEN
IF event->code == SYN_DROPPED THEN
Discard all events including next EV_SYN
ELSE
This marks EOF current event.
FI
ELSE IF event->type == EV_KEY THEN
SWITCH ev->value
CASE 0: Key Release (act accordingly)
CASE 1: Key Press (act accordingly)
CASE 2: Key Autorepeat (act accordingly)
END SWITCH
FI
END WHILE
Some related documents:
Documentation/input/input.txt
, esp. note section 5.Documentation/input/event-codes.txt
, description of various events etc. Take note to what is mentioned under e.g.EV_SYN
aboutSYN_DROPPED
Documentation/input
... read up on the rest if you want.
You can do this easily by referencing /dev/input/by-id/usb-manufacturername_*serialnumber*
. These appear as symbolic links which you can dereference using readlink -e
to determine the associated block device. These links are however created by udev
which might not be present in your embedded environment.
Or.. Look at the dmesg
after connecting the USB device. It should give you the /dev
node.