When trying to read input_events from /dev/input/event16
I noticed that the size of the buffer I'm reading into may cause an exception. Here is the code I wrote:
public static void main(String[] args) throws IOException{
FileInputStream is = new FileInputStream("/dev/input/event16");
byte[] three_bytes = new byte[3];
byte[] twentyfour_bytes = new byte[24];
is.read(three_bytes); // fails
is.read(twentyfour_bytes); // does not fail
}
My initial experiments suggest that the buffer needs capacity for at least one full input_event
struct. But I could not find out why.
The problem is the line is.read(three_bytes);
causes the follwoing exception:
Exception in thread "main" java.io.IOException: Invalid argument
at java.base/java.io.FileInputStream.readBytes(Native Method)
at java.base/java.io.FileInputStream.read(FileInputStream.java:249)
at main.Test.main(Test.java:11)
I would like to figure out why the line is.read(three_bytes);
throws the exception while is.read(twentyfour_bytes);
reads the data as expected
For a start,
/dev/input/event16
is not a regular file. It is a device file, and device files often don't behave like regular files.In this case, the
/dev/input/event*
device files are for reading events from input devices. When you perform aread
syscall on them, they will return one or more complete events. These are binary data whose format is given by the following Cstruct
:The size of that struct is (presumably) 24 bytes on a typical 64bit Linux system, though.
The behavior of the event devices is documented in Linux Input drivers v1.0, section 5. It states that a
read
will always give a whole number ofinput_event
structs.It follows that the
read
syscall provides a buffer that is less thansizeof(input_event)
, the kernel cannot return anything. Apparently, this causes theread
syscall to fail with errno valueEINVAL
. (IMO, this is a reasonable design choice, and consistent with the documented meaning ofEINVAL
.)So, in Java, when you call
read(three_bytes)
, that will map to aread
syscall with a read size of 3 bytes which fails; see above. The syscall failure is signaled to the Java application by throw anIOException
.