boot/lib: Implement evdev query through FFI
module Evdev
- # TODO: Remove dependency on `evtest` and rather rely on direct evdev bindings.
+ module FFI
+ extend Fiddle::BasicTypes
+ extend Fiddle::Importer
+
+ # Indirection to pass an int as an output argument.
+ Int = union ["int value"]
+
+ dlload("libevdev.so.2")
+
+ # https://www.freedesktop.org/software/libevdev/doc/latest/
+ extern "struct libevdev * libevdev_new ()"
+ extern "int libevdev_set_fd ( struct libevdev * , int )"
+ extern "void libevdev_free ( struct libevdev * )"
+ extern "int libevdev_has_event_type ( const struct libevdev * , unsigned int )"
+ extern "const char* libevdev_get_name ( const struct libevdev * )"
+ extern "int libevdev_fetch_event_value ( const struct libevdev *, unsigned int, unsigned int, int *)"
+ end
+
+ # Checks whether any of the given keys (by symbol) are held.
+ # Thus, this is an OR type of operation.
def self.keys_held(keys)
- # See:
- # * https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+ # Temp var for holding return value while we clean up.
+ ret = false
# `evdev` works on `/dev/input/event*` nodes.
# Check them *all*. We can't know which is a keyboard.
- Dir.glob("/dev/input/event*").each do |ev|
- # `evtest` only tests one key at a time with `--query`...
- keys.each do |key|
- system("evtest", "--query", ev, "EV_KEY", key)
- # One of the keys desired is held
- if $?.exitstatus == 10
- puts "#{key} is being held"
- return true
+ Dir.glob("/dev/input/event*").each do |dev_path|
+
+ File.open(dev_path, "r") do |dev|
+ fd = dev.fileno
+ evdev = FFI.libevdev_new()
+
+ if FFI.libevdev_set_fd(evdev, fd) != 0
+ $stderr.puts("warning: Could not set fd for #{dev_path}.")
+ else
+ # 0 is the initial value.
+ buf = FFI::Int.malloc(0)
+
+ keys.each do |key_name|
+ FFI.libevdev_fetch_event_value(
+ evdev,
+ Linux::InputEventCodes::EV_KEY,
+ Linux::InputEventCodes.const_get(key_name),
+ buf
+ )
+
+ # Delay returning until after we free'd
+ ret = true if buf.value == 1
+ end
end
- # Failed for other reason
- puts "Failed to run evtest, #{$?.exitstatus}" unless $?.exitstatus == 0
+ FFI.libevdev_free(evdev)
+ return ret if ret
end
end
