key-repetition for multiple keys in c - c

I was wondering if it was possible to change the key repetition behaviour(on Linux) in such a way that instead of it starting to spam one key as input it goes through all the pressed keys instead (perhaps system("something")?) So instead of when pressing two keys the keys going "wssssssssss", it should go like "wswswswswswsws" instead.

Yes, if you implement an Input Event daemon that grabs (for exclusive access) that keyboard input event device, and produces suitable autorepeat events for keys being pressed long enough, emitting press, autorepeat, and release events back to the system via the uinput device.
I am not aware of anything that already does that, but I estimate it would be less than 500 lines of code in C to implement such a daemon. Such a daemon would need superuser privileges ("run as root"), though.
For command-line game or utility that needs to detect multiple keypresses, using ncurses is way simpler. For graphical applications, the widget toolkit (GTK+, Qt, SDL2, Tcl/Tk, FLTK, and so on) do support multiple keypress detection natively.
If you wanted to write C code without ncurses, you can use termios to control the terminal interface, turn off echoing and line buffering, and achieve the same thing as ncurses – but ncurses also provides nice terminal output functions, and works on basically all terminals and emulators, too.

Related

is there a higher level (character?) based way to access a Linux keyboard other than /dev/input/eventx?

I'm trying to write a Linux daemon that needs to take input from a keyboard-like (HID) device - it's not the console keyboard, but a second device (it's actually a 1D barcode scanner if it makes any difference). The daemon will process the data it receives ("keystrokes" from alphanumeric barcodes).
I know the daemon can use ioctl(EVIOCGRAB) to grab that device from /dev/input/eventx and then read() events (struct input_event from <linux/input.h>), that works, but it's too low level for my needs. I don't need to know about every up and down key event and I would rather not have to decode/handle simultaneous keys, i.e. I don't want to know KEY_DOWN+KEY_RTSHIFT, KEY_DOWN+KEY_A, KEY_UP+KEY_RTSHIFT, KEY_UP+KEY_A, I just want to receive "A".
Using the input events needs a whole pile of extra code to be written, just to get "A" out of it - and that seems a waste of time and effort when there are almost certainly existing keyboard handlers (or something like that) that will do a far better job than me hacking code together - I just can't find them!
Is there any way to put an existing layer of (keyboard?) software onto /dev/input/eventx that the daemon can then exclusively read a stream of simple ascii from?
For this device, /proc/bus/input/devices reports ...
H: Handlers=sysrq kbd leds event9
... which might suggest that something has already put a "kbd" layer on it, but how to access it?
If I don't EVIOCGRAB, then when I scan a barcode I see syslogs about "failed login on /dev/tty1", so that keyboard input is clearly trying to login to a terminal/shell somewhere :-/ (There's no X, desktop etc on this machine either.)
I am not aware of such library or daemon.
However, writing a daemon to do exactly that is not nearly as hard as you think. In my opinion/experience, if you do not need to implement autorepeat (that is, only do autorepeat if the keyboard-like device sends autorepeat keypresses), the daemon is surprisingly simple.
In particular, the main loop is just a blocking read followed by zero or more blocking writes, with an array look-up in the middle.
You can use either a named pipe (in which case you open the pipe before opening the device, because the open succeeds only after another process opens the named pipe or FIFO for reading), or a socket; either Unix Domain socket, or a TCP or UDP socket (on the loopback interface). I'd probably use a named pipe, /var/run/barcode-scanner.
I would use a separate configuration file for the input mapping, and I'd support the preprocessor macro names (KEY_) from /usr/include/linux/input-event-codes.h, parsed to an array using a helper awk script. The key mapping file would probably live in /etc/barcode-scanner/keymap, and contain definitions similar to
KEY_1 = 1
KEY_NUMERIC_1 = 1
KEY_E = e
shift KEY_E = E
ctrl KEY_E = \5
altgr KEY_E = €
KEY_UP = \033[A
and so on. Events not listed in the definition file would be ignored or optionally logged.
You can use an array, because there are up to 768 (0 to KEY_MAX, inclusive; although 0 is KEY_RESERVED) different keyboard events; as a two-dimensional array, you'll probably want something like 16 arrays, for supporting all kombinations of Shift, Ctrl, Alt, and AltGr (or right alt key), when each key is pressed. Internally, you'll just need to handle KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KEY_CAPSLOCK (to manage the shift state); KEY_LEFTALT (to manage the alt state); KEY_RIGHTALT (to manage the altgr state); and KEY_LEFTCTRL and KEY_RIGHTCTRL (to manage the ctrl state). If you use a bit mask to indicate the current states, you can use it as an index to the outer dimension of the lookup array. It really is very straightforward.
Note that each array element is then a string, that is emitted when a key of that state is pressed (ev.value == 1 for keypress, ev.value == 2 for autorepeat). Aside from the above special keys, you do not need to handle key releases at all.
Hm. I wonder if there are others who would need such a daemon? Would you use a GPL3-licensed one, if the sources were at GitHub?
The libevdev library is not exactly what you ask for. But it is widely used (e.g. by the Xorg server evdev and libinput drivers).
As state on the home page:
libevdev is essentially a read(2) on steroids for /dev/input/eventX devices.
It manages ioctl calls for you, handles an events queue, etc.
One additional feature you didn't ask for, but it is really helpful: it can handles events from multiple devices at once. It allows you to listen on multiple devices located in /dev/input and handle the same event type in a single thread.

Linux kernel replace keys

I have to write a linux kernel module, which change character printed on the screen after pressing a key (let's say - I want 'a' to be printed when I press 'b' on keyboard). What is the best way to do it? I'he thought that good idea is to create module for keyboard. I did some research, i saw few keyloggers (as kernel modules) but all of them where able only to listen what key was pressed, and any change of scancode was imposible (which is pretty obvious in keyloggers). I read 3rd chapter from Linux Device Drivers, and i started to read 6th, but they are talking only about virtual devices, when i want to connect my module with the real device. I saw also this https://stackoverflow.com/questions/33836541/linux-kernel-how-to-capture-a-key-press-and-replace-it-with-another-key, but it wasn't working. My teacher said there is much eaysier way than using interrupts, but I have no idea how to do it (neither using interrupts and any other way).
What should I do? just read next chapters of LDD? Or any other book? Or maybe just lie down and cry?
Here's a very simple example of keyboard driver kernel module: https://github.com/raleighlittles/Olympus-MAJ-1428-Keyboard-Linux-driver/blob/main/hid-olympus-maj1428.c
I had a keyboard that generated weird scancodes for certain non-character keys (read the file, it explains more). Instead of using those scancodes, I wrote code to remap them to the extended function keys (F13, F14, etc.). You could use the code and instead simply switch the scan codes that you want by changing the key_mapping variable.

"Push-to-make" style use of keyboard keys

I am using C in Fedora Linux to build a voice streaming application. I have audio running between two clients, but the next stage is to implement the user interface.
I am aiming to use different keyboard keys in a "push to talk" style, ie holding the "Q" key allows the user to talk to one user, "W" another and so on.
My question is, how would I go about implementing this? The transmit thread is just a while loop that reads 180 bytes from the sound card and sends it as a UDP packet. THe mist obvious issue is echoing of the key pressed, filling the screen with q's and w's, and how I can detect key down/key up in C. I am looking at ncurses but it is a big topic!
Any ideas or further reading would be greatly appreciated.
J
The first part of your question, as to how to detect keypress without using ncurses is answered excellently, using termios, by #jim mcnamara
And ncurses doesn't seem to be as scary as it sounds :-). Here is an ncurses implementation which exactly ( almost ) satisfies your requirement. But according to this post, you need to add a notimeout() call so that getch()(ncurses one) doesn't wait for next keypress.

Linux C - Get Lock Keys Status'

How exactly does one find out the status of the lock keys on Linux (2.6.x), using C?
(I have a crappy keyboard without LED's for this stuff, and I need to write an X11 app to do this)
If such an app exists (and is DE agnostic - I run e16), I'd also like to hear it as well.
You can use the led addon to gkrellm. If you want to develop your own app, you can always look a the gkrellm-led sources (Ubuntu). And, of course, you can always go with xkbvleds (source).
Anyway, you can always use XkbGetIndicatorState to read the indicators from your keyboard.

Using keyboard interrupt to display something different than what the user typed

In the C language, using keyboard interrupt, how can I display an alternate key from what the user typed? E.g., when I press 'Q' on the keyboard, then the screen should display 'A'.
Handling keyboard interrupt is not a good idea on any platform.
What about usb keyboards, there is no interrupt you can catch ?
For Windows OS's you probably want to write filter driver, you can find this replay partly relevant.
Sample of keyboard filter driver can be found here.
For Linux you probably need to patch HID layer driver. Mac is out my scope completely :)
We need a little more information about Your environment.
As far as I understand Your question, You want to replace the
keyboard interrupt handler with Your own in this way:
Save the entry address of the original keyboard handler.
Install Your own that calls the original and manipulates the keycode value.
However, on most modern operating systems it is much easier to define and install a new keyboard layout.

Resources