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/
. Use ioctl()
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
and KEY_KP0
to KEY_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
about SYN_DROPPED
Documentation/input
... read up on the rest if you want.
Best Answer
I don't think mirroring the USB interface is the most straightforward solution to your problem.
I haven't used
brltty
before; but, from what I understand, you should be able to use tmux to multiplex the terminal outside ofbrltty
altogether.To be honest, I haven't really used tmux, either; but going from this tutorial...
tmux -S /tmp/shared
chmod +r /tmp/shared
tmux -S /tmp/shared attach -r
The tutorial also gives some suggestions on how to have your client terminals automatically attach to the master terminal on login. That might or might not matter to you; but, if so, you could probably just stick it at the end of the client account's
.profile
, assuming you don't have any security concerns to worry about.exec /usr/bin/tmux -S /tmp/shared attach -r