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:

  1. At startup loop all event files found in /dev/input/. Use ioctl() to request event bits:

    ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
    

    then check if EV_KEY-bit is set.

  2. 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 and KEY_KP0 to KEY_KP9.

  3. IFF keys found then start monitoring event file in thread.

  4. 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:

  1. Documentation/input/input.txt, esp. note section 5.
  2. Documentation/input/event-codes.txt, description of various events etc. Take note to what is mentioned under e.g. EV_SYN about SYN_DROPPED
  3. 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.