gemini://://gs.vern.cc/gemlog/simple-keyboard-logger.gmi
#

Writing a simple keyboard logger in C (For Linux Kernel)

Several days ago, I've noticed /dev/input/event* files. I thought it might be a way to

capture keyboard events.

The document for this kinda file is located in the Linux Kernel. The path is:

> Documentation/input/input.rst

In the document, a data structure for events was introduced, which I will show it below:

```
    struct input_event {
```
	    struct timeval time;
```
	    unsigned short type;
```
	    unsigned short code;
```
	    unsigned int value;
```
    };

So, in this struct, time is for the timestamp, code is for the event code. We probably

not gonna use the timestamp. The event value can be used to identify whether the key's

pressed or released. The code indicates the keys you're pressing, which can be found

in 'include/uapi/linux/input-event-codes.h'.

And that's all the knowledge we'll use in the code. So, let's jump into it.

```
struct input_event *event = malloc(sizeof(struct input_event));
```
```
FILE *event_stream = fopen(argv[1], "r");

First, we allocated some memory for the event, and later we'll read to it. And we also

created a stream for reading events from the device.

```
while(1) {
```
	 fread(event, sizeof(struct input_event), 1, event_stream);
```
```
	 puts("Key event!");
```
}

We've read the event to that memory. Now, we could access the event!

For event->type, 1 is for keyboard event.

For event->value, 1 is for pressing, 0 is for releasing.

For event->code, it's defined in 'input-event-codes.h'.

In the input-event-codes.h, the key names were definely in macros:

```
#define KEY_RESERVED		0
```
#define KEY_ESC			1
```
#define KEY_1			2
```
#define KEY_2			3
```
...

Apparently, we can't use it directly. But because it's continuous,

we can convet it to a string array using the python script below:

```
source = open("origin_event_code.h", 'r')
```
output = open("event_code.c", 'w')
```
```
index = 0
```
```
output.write("char event_code[][32] = {\n")
```
```
rlines = source.readlines()
```
```
for l in rlines:
```
    if not l.startswith("#define"):
```
        continue
```
    parts = l.strip().split()
```
    output.write("\t\"<" + parts[1].replace("KEY_", "") + ">\"")
```
    if l == rlines[-1]:
```
        output.write("\n")
```
    else:
```
        output.write(",\n")
```
```
source.close()
```
output.write("};")
```
output.close()
```

It will generate something like this:

```
char event_code[][32] = {
```
	"<RESERVED>",
```
	"<ESC>",
```
	"<1>",
```
	"<2>",
```
	"<3>"
```
	// ...
```
}

We can get the key name using this expression 'event_code[event->code]'.

Now you can do whatever you want, e.g. write it to stdout or a file.

And here's the source code:

You're required to provide the input event device. And you can easily

find it in '/dev/input/by-id'.