Linux keyboard raw reading, what's better, reading from /dev/input/event0 or reading from stdin? - c

I'm working on a small C videogames library for the Raspberry Pi. I'm coding the input system from scratch and after reading and seeing some examples about raw input reading, I got some doubts.
For mouse reading, I just use /dev/input/event1, I open() it as O_NONBLOCK, I read() input_event(s) and I also put the mouse reading in a separate pthread. Easy.
For keyboard reading, I saw some examples that reconfigure stdin to O_NONBLOCK (using fcntl()), then save and reconfigure keyboard termios attibutes (ICANON, ECHO), and some example also save and reconfigure keyboard mode with ioctl(). What's the point of doing all that stuff instead of just reading /dev/input/event0 input_event(s) (same way as mouse)?
Note that I undestand what those functions do, I just don't undestand why should be better to do all that stuff instead of just reading input_event(s).

Reading stdin is not limited to reading locally connected keyboards (but has other limitation making it mostly unsuitable for games). Then reading stdin you could be reading keystrokes from a user logged in remotely, using a locally connected serial terminal or a terminal emulator (possibly operated from a remote X server).
For terminal based games it might make sense to use stdin. But then it would probably be better to use GPM instead of reading /dev/input/event1 for the mouse. And possibly even better to use ncurses for everything.
Otherwise you might want to look at SDL, if not for using it directly, at least for learning about different ways to read input. For example, SDL has full support for network transparency using X. Which means a game can execute on one computer but be played on another.

Expanding on Fabel answer - standard input and event1 are entirely different things. Starting from that the event1 does not have to be mouse but can be an other device depending on udev, kernel version, phase of moon etc. - on my (non Raspberry Pi) system it's input device Sleep Button - which has a keyboard interface. In short you cannot and should not assume it's keyboard - or the only keyboard for that matter (for example also YubiKey emulates the keyboard for it's function but it's rather useless as gaming device, and while 2 keyboards are rarely connected to same Raspberry Pi I don't think it's good idea to assume such setup never happens).
Furthermore typically input devices can be read only by privileged user (on older/current systems) or by user holding a 'seat' (on rootless X systems) - assuming you're not using bleeding edge system it means your game can only by used by root user which is usually considered a bad idea.
Finally it only allows for user to play using a evdev subsystem, which probably should be considered Linux/X11 implementation detail. If you try to connect via network (X11, vnc or whaterver), try to use on-screen keyboard or any accessible input program - you might run into problems.
On the other hand what you can do is either use standard input directly, use some more portable libraries like readline (which should be sufficient for rougulike) or use graphics server (probably indirectly via library like QT or SDL as X11 is not the nicest protocol to program against).

Reading from /dev/input/eventN works only on GNU/Linux.
Configuring and using stdin works on any system implementing POSIX.1-2008, specifically chapter 11: General Terminal Interface. So if you want portable code, like say to work on Linux and OS X without rewriting the input system, you'd do it this way.

Related

How do I create a text wrapper for the kernel? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I studied the content from the osdev.org website and built a compiler, launched a test kernel, but I thought, how can I create a primitive text shell for the kernel with commands? Maybe someone can explain to me with an example how to implement this. There is nothing interesting on the site itself, of course there is an article but it is useless for me. I'm a beginner if that.
how can I create a primitive text shell for the kernel with commands?
The correct way is:
Write enough kernel code to manage various resources (memory, IRQs, IO ports, DMA channels, ...). This should include managing time (a scheduler), and should also include some kind of inter-process communication (so that the scheduler can be told "Don't give this task any more CPU time until/unless it receives data from inter-process communication").
Enumerate devices, determine each device's resources, and start drivers for whichever devices you find. Note that this is hierarchical. For example, if you enumerate PCI buses and find 2 USB controllers attached to PCI buses and start their device drivers, then you'll need to enumerate each of the USB controllers to find any USB devices attached to USB buses and might find 3 USB hubs, and then you'll need to enumerate all 3 USB hubs to see what is plugged into them. All of this should be coordinated by some kind of "device manager" which keeps track of a hierarchical tree of devices, so that (e.g.) if a device is unplugged or sent to a power saving state (or if its device driver crashes) you can inform drivers that depended on that device (e.g. if a USB hub is unplugged you can inform all drivers for devices that were attached to that hub).
write keyboard device driver/s. These should decode the data from the device (likely using tables and other information describing a "keyboard layout" that's loaded from file system) and send packets of data using the kernel's inter-process communication (so that any task can say "don't give me any CPU time until I receive data from the keyboard driver"). This will involve designing a standard way that all keyboard drivers (and all software emulating a keyboard - e.g. "on screen keyboard" for people using touchscreens, etc) will behave (e.g. the format of that data packet they send, etc); and probably should involve creating a formal "keyboard device driver interface" specification for your OS to describe whatever you designed (in addition to designing a file format for "keyboard layout files").
write video device driver/s. This will also include designing a suitable video driver interface for your OS (and should including writing a formal specification describing it). However; video is complex and you can cheat by only designing part of the video driver interface and leaving the rest of it (video mode setting, 3D, GPGPU, ...) until later. The same applies to the video driver itself - you will want to start with "generic raw frame buffer driver" (that just uses a frame buffer configured by the boot loader) and probably won't write actual drivers for specific video cards.
(optional) write some kind of upper layer to control which task is the main task for each set of user input/output devices. This allows the user to have multiple virtual consoles and switch between them (e.g. maybe with "control+alt+F1" to "control+alt+F12"), possibly allowing some virtual consoles to be associated with terminals and others to be associated with different GUIs. It can also make it easy to support "multiple seat" (e.g. if there's 2 keyboards and 2 monitors, then you can have 2 completely separate users with each user having one keyboard and one monitor).
create a task with a simple main loop that uses inter-process communication ("don't give me any more CPU time until/unless I receive data from the keyboard") and processes the data it received to build up a current command string, then (if/when the user presses the enter key) parses the command string and does whatever the command says. Note that if you get this far it's tempting to do a tiny little bit of extra work to support user-space, and make it a normal process instead of a kernel task.
The incorrect way is:
don't have a kernel that supports some/most of the things that device drivers and other code must rely on
don't do any kind of device enumeration. Instead, make wild assumptions about which devices are present and which resources they use.
don't put any thought into device driver interfaces. Just slap together whatever seemed convenient (and continually break everything whenever you change any device driver).
don't use tasks (or inter-process communication). Instead, build the "shell" into the keyboard driver's IRQ handler to make sure the entire OS "pauses" when someone enters any time consuming command.
don't continue working on the OS after you get the shell to "work". This will be necessary because the code will be too inflexible and too fragile (any attempt to do anything else will cause you to have to rewrite everything).
Note: In my experience people that ask questions like "how do I write a kernel shell" are likely to have skipped everything that matters (because they'd know how to write a shell if they've done everything that a shell depends on); and are so focused on having a shell that they're very tempted to do it all the incorrect way (and then get stuck later and regret it).

Why can't I see the full Linux kernel panic inside my terminal in display, but can through the COM-port?

There are some cases when it is needed to see the full log of Linux kernel panic.
But it often can't be done through the regular terminal in display.
I thought that it should be done through the COM-port, but can't figure out:
How can I do that?
What is the reason of working well through COM-port, but not through terminal in my display?
UPD: I use debian-based custom Linux (4.9 kernel) with HDMI-display.
Related: How to get a Linux panic output to a USB serial console when system has also a display adapter
Simple direct connected console / VTY use the graphics card to convert character bytes (0 - 255) into display character cells. 80x25 is a common format. This is very simple and not hard for a crashing kernel to manage. Just copy some memory around.
The graphical console is more complicated because the kernel now has to locate the font bitmap for a character and copy the bitmap onto the display. It also needs to handle scrolling with more memory copies, or IOCTL calls into the graphics driver, etc.
A console running in a Gnome or KDE GUI session is very complicated. The kernel isn't involved in drawing it at all and doesn't know how.
The more complex the output process is, the less likely that a kernel that is already crashing can manage it successfully.
Serial port output is once again very simple. A buffered UART makes it a bit more complicated, but if a crashing kernel wants to ignore that and simply output bytes at a 9,600 line rate, any serial port will work with that without needing buffers or interrupt management.

passing variables to a process from linux kernel

I want to make a program that will gather information about the keystrokes of a user (keycode, press and release times) and will use them as a biometric for authenticating the user continuously. My approach is to gather the keystrokes using a kernel module (because you can't just kill a kernel module), than the kernel module will send the information to another process that will analyze the data gathered by the kernel module, it will save it to a database and will return an answer to the kernel (the user is authenticated or not) and the kernel will lock the computer if the user is not authenticated. the whole module will not be distributed.
my questions are:
1. How can I call a process from the kernel and also send him the data?
2. how can I return a message to the kernel from the process?
#basile-starynkevitch 's answer and his arguments notwithstanding there is an approach you can take that is perfectly correct and technically allowed by the linux kernel.
Register a keyboard notifier call back function using the kernel call register_keyboard_notifier() in your kernel module. As a matter of fact it's designed for exactly this!
Your notifier call back function will look something like:
int keysniffer_callback(struct notifier_block *notifier_block,
unsigned long scancode,
void *param)
{
// do something with the scancode
return NOTIFY_OK;
}
See https://www.kernel.org/doc/Documentation/input/notifier.txt for starters.
I want to make a program that will gather information about the keystrokes of a user
That should go in practice into your display server, which you did not mention (Xorg, Wayland, MIR, ...?). Details matter a big lot!
My approach is to gather the keystrokes using a kernel module
I strongly believe this is a wrong approach, you don't need any kernel module.
I want to make a program that gathers data about the user keystrokes
Then use ordinary Unix machinery. The keyboard is some character device (and you could have several keyboards, or none, or some virtual one...) and you could read(2) from it. If you want to code a keylogger, please tell that explicitly.
(be aware that a keylogger or any other cyberspying activity can be illegal when used without consent and without permission; in most countries, that could send you to jail: in France, Article 323-1 du Code PĂ©nal punishes that by at least 2 years of jail; and most other countries have similar laws)
the kernel module will send the information to another process [....] it will save it to a database
This is practically very difficult to get (and you look confused). Databases are in user-land (e.g. some RDBMS like PostGresSQL, or some library accessing files like sqlite). Notice that a kernel driver cannot (easily and reliably) even access to files.
All application programs (and most daemons & servers) on Linux are started with execve(2) (e.g. by some unix shell process, or by some daemon, etc...), and I see no reason for you to make an exception. However, some programs (mostly init, but also a few others, e.g. /sbin/hotplug) are started by the kernel, but this is exceptional (and should be avoided, and you don't need that).
How can I call a process from the kernel
You should not do that. I see no reason for your program to avoid being started by execve from some other process (perhaps your init, e.g. systemd).
and also send him the data?
Your process, as all other processes, is interacting with the kernel thru system calls (listed in syscalls(2)). So your application program could use read(2), write(2), poll(2) etc.. Be aware of netlink(7).
how can I return a message to the kernel from the process?
You don't. Use system calls, initiated by application code.
the kernel will lock the computer if the user is not authenticated.
This does not have any sense. Screen locking is a GUI artefact (so is not done by kernel code, but by ad-hoc daemon processes). Of course some processes do continue to run when locking is enabled. And many processes are daemons or servers which don't belong to "the" user (and continue to run when "the computer is locked"). At heart, Linux & POSIX is a multi-user and multi-tasking operating system. Even on a desktop Linux system used by a single physical person, you have dozens of users (i.e. uid-s many of them specialized to a particular feature, look into your /etc/passwd file, see passwd(5)) and more than a hundred processes (each having its pid), use top(1) or ps(1) as ps auxw to list them.
I believe you have the wrong approach. Take first several days or weeks to understand more about Linux from the application point of view. So read some book about Linux programming, e.g. ALP or something newer. Read also something like: Operating Systems: Three Easy Pieces
Be aware that in practice, most Linux systems having a desktop environment are using some display server. So the (physical) keyboard is handled by the X11 or Wayland server. You need to read more about your display server (with X11, things like EWMH).
Hence, you need to be much more specific. You are likely to need to interact with the display server, not the kernel directly.
At last, a rule of thumb is to avoid bloating your kernel with extra and useless driver code. You very probably can do your thing in userland entirely.
So, spend a week or more reading about OSes & Linux before coding a single line of code. Avoid kernel modules, they will bite you, and you probably don't need them (but you might need to hack your display server or simply your window manager; of course details are different with X11 and with Wayland). Read also about multiseat Linux systems.
At last, most Linux distributions are made of free software, whose source code you can study. So take time to look into the source code of relevant software for your (ill-defined) goals. Use also strace(1) to understand the system calls dynamically done by commands and processes.

Read input device in C

I'm creating a 2-D platformer game in C that will run in the terminal. I need a way to register "KEY_DOWN" and "KEY_RELEASE" events. As far as I know getchar() reads from stdin and thus can not be used for registering "KEY_RELEASE" events. Neither can it be used for registering if multiple keys are being pressed down at the same time.
Is there a Mac OSX 10.10.5 C library that I can use to solve this problem? Maybe a library which reads input directly from the keyboard instead of the terminal?
None of the potential answers are likely to be simple:
if you are running an application in the terminal, and lacking (as OSX does) a set of system calls for reading the keyboard state directly, it won't work.
the available sources describe non-terminal applications (mostly using Cocoa, the OSX GUI, and mostly using ObjectiveC).
Here are a few:
How can I detect that the Shift key has been pressed?
Showing how to listen to all keypresses in OS X through the Cocoa API using Python and PyObjC
Listening for Global Keypresses in OSX
Mouse button and keypress counter for Mac OS X
OSX: Detect system-wide keyDown events?
For reference (Cocoa Event Handling Guide):
Handling Key Events
Monitoring Events

How to get Keyboard inputs into a kernel?

I am writing my own kernel in c. Now I want to code a Console to interact with the Kernel. It should work like the normal Terminal on Linux. How can I get a input over the Keyboard ? Do I have to use Keyboard specific drivers ?
You need to write a driver in your kernel for the keyboard. Assuming a standard PC, the 8042 keyboard controller is pretty well documented (see http://wiki.osdev.org/%228042%22_PS/2_Controller for example). You'll also need to write a driver for the display, and again assuming VGA it is pretty well documented (see http://wiki.osdev.org/VGA_Hardware). Then you'll have to write all of the terminal stuff that sits in between to connect the two.

Resources