@illera88 - however this may or may not be exactly the same as what values your PC may have for these delays, as I believe in most all systems, the user can change
these values and as far as I know there is no query function that a keyboard could do to query these values, as the keyboard does not need to know this as it
simply sends messages when a scan code state changes and typically this state will contain up to 6 keys being pressed at once...
In case anybody is interested, here's some further info.
We are talking about devices using the
USB Human Interface Device specification; the current being
Device Class Definition for Human Interface Devices 1.11 (PDF) (especially Appendix C: Keyboard implementation onwards) and
HID Usage tables 1.3 (PDF) (page 88 onwards).
HID subclass 1 defines two
boot devices:
boot keyboards and
boot mice, with specific report formats, that should be compatible with all USB devices that support keyboards and mice. See
Device Class Definition for Human Interface Devices 1.11 (PDF), Appendix B. Essentially, a boot keyboard reports keypresses and key releases using 8-byte reports, and accepts 1-byte output reports to set keyboard LEDs:
Code:
struct boot_keyboard_event {
unsigned char modifiers;
unsigned char reserved; /* Zero */
unsigned char keycodes[6];
};
struct boot_keyboard_output_event {
unsigned char state; /* Bit 0: NumLock, 1: CapsLock, 2: ScrollLock, 3: Compose, 4: Kana, 5-7: reserved. */
};
Each entry in the
keycodes[] array is either 0, or specifies a non-modifier key that is currently pressed; see
HID Usages and Descriptions, section 10: Keyboard/Keypad Page (0x07), usage type "SEL". Their order in the
keycodes[] array in
struct boot_keyboard_event should be irrelevant. Because of this limitation, boot protocol keyboards can support at most 6 simultaneous non-modifier keys. The modifier keys are from bit 0 (LSB) to bit 7 (MSB): Left Control, Left Shift, Left Alt, Left GUI, Right Control, Right Shift, Right Alt, and Right GUI. See the previous link, pages 93-94, codes 224-231 (0xE0-0xE7, marked DV in the table, as they comprise the modifier bits).
Similarly, a boot mouse reports events using 3-byte reports:
Code:
struct boot_mouse {
unsigned char buttons;
signed char deltaX;
signed char deltaY;
};
The USB device itself specifies what kinds of reports it produces using essentially a bit-packing format, various operating systems have certain expectations as to what they actually support. Values and bitmaps need to be byte-aligned, for example. Linux tends to be quite easy and forgiving, except for nonstandard workarounds that Windows may need, so ones best bet for maximum OS support is boot protocols, and device reports similar to commonly used joysticks and other devices.
I'm personally most familiar with the
Linux Input subsystem Event interface, i.e.
/dev/input/event* device interface. Essentially, you just open the device for reading, and read (complete) structures having format
Code:
struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
unsigned int value;
};
where
time is the timestamp;
type is one of the
EV_type constants defined in
<linux/input-event-codes.h>, for example
EV_KEY for a keyboard event, or
EV_SYN for report separator (which always follows a related set of events, so that multiple events like different axes on a joystick are treated as a single action instead of separate actions);
code identifies the key, button, axis, etc., for example
KEY_ENTER or
KEY_A (defined in the same file; for type
EV_FOO, look for constants
FOO_name); and
value specifies the action on that code, for example 0 for key release, 1 for key press, and 2 for autorepeat.
Autorepeat is indeed handled by the Linux kernel for keyboard devices. It internally detects how long a key has been pressed, and issues the above autorepeat events if needed.
The autorepeat timing is controlled by using an
ioctl() on the device; specifically,
EVIOCGREP (get) or
EVIOCSREP (set) ioctls that take an array of
REP_CNT (2)
ints, with the value at index
REP_DELAY (0) specifying the initial delay in milliseconds, and
REP_PERIOD (1) the repeat interval in milliseconds. The ioctl names are defined in
<linux/input.h>, and the values in
<linux/input-event-codes.h>.
In general, when more than one process has the same event device open, each of them receives a copy of the events. One can use the
EVIOCGRAB ioctl() to "grab" (and
EVIOCREVOKE to revoke) access to the events, so that only this (file description) receives the events.
The way Arduino et cetera without native USB generate these events, is that they have a simple daemon in Linux userspace, that opens and reads from a serial port, and then uses the
uinput (
/dev/uinput) device interface (link contains example code at Linux kernel device interface to emit events using the same interface as described above. Additional ioctls defined in
<linux/uinput.h> are used to set up the new virtual device (which will appear exactly as a physical input event device would!); for example, the
UI_DEV_SETUP ioctl is used to specify the USB Vendor and Product numbers and device name via the
struct uinput_setup structure. The
UI_DEV_CREATE ioctl is finally used to actually create the device, but note that although the kernel creates the device instantly, it takes a little while for the
udev daemon to create the character device nodes with configured owner, group, access mode, and symbolic links to. Whenever the uinput device file descriptor is closed, the virtual device is automatically removed by the kernel (again, it can take a fraction of a second for the
udev daemon to delete the device node and symlinks).
In normal use, the udev delay does not matter, since either applications use a symlink (to identify a specific device, defined using
SYMLINK+="symlink-name"[/URL] in a suitable udev rule), they detect the new device node appearing (which means udev's work is complete), or they use libudev to receive events informing them of a new device appearing or being removed. It is really only when a side channel (like a pipe or socket between applications) is used to directly notify another application that the device is now available, when the udev delay actually matters.
(Also, if you happen to stumble on my comment to a 2016 StackOverflow question, ioctl(fd, EVIOCGRAB, 1) is invalid for /dev/uinput, because it is essentially "grabbed" automatically: each open description (and thus file descriptor unless you duplicate the descriptor instead of reopening the device) refers to an independent interface to the input subsystem.)