How do keyboards and mice and power buttons work

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the unix category.

Last Updated: 2024-11-21

I wanted to understand how my mouse and power button worked with my machine

By viewing /proc/bus/input/devices I could see all my devices (including the mouse) along with some event handlers:

$ cat /proc/bus/input/devices
I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
U: Uniq=
H: Handlers=kbd event0
B: PROP=0
B: EV=3
B: KEY=10000000000000 0

I: Bus=0019 Vendor=0000 Product=0003 Version=0000
N: Name="Sleep Button"
P: Phys=LNXSLPBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSLPBN:00/input/input1
U: Uniq=
H: Handlers=kbd event1
B: PROP=0
B: EV=3
B: KEY=4000 0 0

I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input2
U: Uniq=
H: Handlers=sysrq kbd event2 leds
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7

I: Bus=0011 Vendor=0002 Product=0006 Version=0000
N: Name="ImExPS/2 Generic Explorer Mouse"
P: Phys=isa0060/serio1/input0
S: Sysfs=/devices/platform/i8042/serio1/input/input5
U: Uniq=
H: Handlers=mouse0 event4
B: PROP=1
B: EV=7
B: KEY=1f0000 0 0 0 0
B: REL=143

I: Bus=0001 Vendor=80ee Product=cafe Version=0600
N: Name="VirtualBox mouse integration"
P: Phys=
S: Sysfs=/devices/pci0000:00/0000:00:04.0/input/input6
U: Uniq=
H: Handlers=event5
B: PROP=0
B: EV=b
B: KEY=10000 0 0 0 0
B: ABS=3

The handlers are in /dev/input e.g mouse0 was mentioned in Generic Explorer Mouse. So I inspect this data next:

$ sudo cat /dev/input/mouse0
S3
E(B�(�(%�("�(�(
�(�(�8��8��8��8����
  �!�)��
�+$)

This just dumps a stream of data onto the screen

According to linux docs, all input events have a certain format: https://www.kernel.org/doc/Documentation/input/input.txt

struct input_event {
  // assuming a standard number of bytes for 64 bit system compiler: https://stackoverflow.com/questions/11438794/is-the-size-of-c-int-2-bytes-or-4-bytes
  struct timeval time; / 16 bytes
  unsigned short type; / 2 bytes
  unsigned short code; / 2 bytes
  unsigned int value; / 4 bytes
};

The mouse event is much simpler, just three bytes. I'll demo this in Python instead:

import struct
f = open( "/dev/input/mice", "rb" );
# Open the file in the read-binary mode
while True:
    data = f.read(3)  # Reads 3 byte message at a time
    print(struct.unpack('3b',data))  # Unpacks bytes to python ints - https://docs.python.org/3/library/struct.html

(8, 0, 0) # left click down
(9, 0, 0) # left click up
(8, 0, 0) # left click down again
(10, 0, 0) # right click down

When I first ran this program it failed because the open on the /dev/input required sudo permissions. Therefore I started again with sudo python3 and it worked.