Support auto-detection of input devices via fbink_input (#11807)

* Kobo: Drop a bunch of if ladder crap and switch to auto-detection of input devices via fbink_input
* Kindle: Drop an even larger bundle of crap to do the same ;p. (re: #11392)
* ExternalKeyboard: Switch to fbink_input to whitelist keyboards instead of the manual parsing of caps via its FindKeyboard class
* Input: Extended open/close wrappers to handle logging & tracking of dupe open/close calls.
This commit is contained in:
NiLuJe
2024-05-15 05:42:48 +02:00
committed by GitHub
parent 79be8a10b1
commit fd5260f2ce
8 changed files with 258 additions and 259 deletions

View File

@@ -1,5 +1,4 @@
local Event = require("ui/event")
local FindKeyboard = require("find-keyboard")
local Device = require("device")
local InfoMessage = require("ui/widget/infomessage")
local InputText = require("ui/widget/inputtext")
@@ -14,6 +13,7 @@ local _ = require("gettext")
local ffi = require("ffi")
local C = ffi.C
require("ffi/posix_h")
require("ffi/fbink_input_h")
-- The include/linux/usb/role.h calls the USB roles "host" and "device".
local USB_ROLE_DEVICE = "device"
@@ -224,18 +224,17 @@ function ExternalKeyboard:onExit()
end
end
function ExternalKeyboard:_onEvdevInputInsert(evdev)
self:setupKeyboard("/dev/input/event" .. tostring(evdev))
function ExternalKeyboard:_onEvdevInputInsert(event_path)
self:setupKeyboard(event_path)
end
function ExternalKeyboard:onEvdevInputInsert(evdev)
function ExternalKeyboard:onEvdevInputInsert(path)
-- Leave time for the kernel to actually create the device
UIManager:scheduleIn(0.5, self._onEvdevInputInsert, self, evdev)
UIManager:scheduleIn(0.5, self._onEvdevInputInsert, self, path)
end
function ExternalKeyboard:_onEvdevInputRemove(evdev)
function ExternalKeyboard:_onEvdevInputRemove(event_path)
-- Check that a keyboard we know about really was disconnected. Another input device could've been unplugged.
local event_path = "/dev/input/event" .. tostring(evdev)
if not ExternalKeyboard.keyboard_fds[event_path] then
logger.dbg("ExternalKeyboard:onEvdevInputRemove:", event_path, "was not a keyboard we knew about")
return
@@ -248,6 +247,9 @@ function ExternalKeyboard:_onEvdevInputRemove(evdev)
return
end
-- Close our Input handle on it
Device.input.close(event_path)
ExternalKeyboard.keyboard_fds[event_path] = nil
ExternalKeyboard.connected_keyboards = ExternalKeyboard.connected_keyboards - 1
logger.dbg("ExternalKeyboard: USB keyboard", event_path, "was disconnected; total:", ExternalKeyboard.connected_keyboards)
@@ -277,34 +279,84 @@ function ExternalKeyboard:_onEvdevInputRemove(evdev)
self:_broadcastDisconnected()
end
function ExternalKeyboard:onEvdevInputRemove(path)
UIManager:scheduleIn(0.5, self._onEvdevInputRemove, self, path)
end
ExternalKeyboard._broadcastDisconnected = UIManager:debounce(0.5, false, function()
InputText.initInputEvents()
UIManager:broadcastEvent(Event:new("PhysicalKeyboardDisconnected"))
end)
-- Implement FindKeyboard:find & check via FBInkInput
local function findKeyboards()
local keyboards = {}
local FBInkInput = ffi.load("fbink_input")
local dev_count = ffi.new("size_t[1]")
local devices = FBInkInput.fbink_input_scan(C.INPUT_KEYBOARD, 0, C.SCAN_ONLY, dev_count)
if devices ~= nil then
for i = 0, tonumber(dev_count[0]) - 1 do
local dev = devices[i]
if dev.matched then
-- Check if it provides a DPad, too.
local has_dpad = bit.band(dev.type, C.INPUT_DPAD) ~= 0
table.insert(keyboards, { event_path = ffi.string(dev.path), has_dpad = has_dpad })
end
end
C.free(devices)
end
return keyboards
end
local function checkKeyboard(path)
local keyboard
local FBInkInput = ffi.load("fbink_input")
local dev = FBInkInput.fbink_input_check(path, C.INPUT_KEYBOARD, 0, C.SCAN_ONLY)
if dev ~= nil then
if dev.matched then
keyboard = {
event_path = ffi.string(dev.path),
has_dpad = bit.band(dev.type, C.INPUT_DPAD) ~= 0
}
end
C.free(dev)
end
return keyboard
end
-- The keyboard events with the same key codes would override the original events.
-- That may cause embedded buttons to lose their original function and produce letters,
-- as we cannot tell which device a key press comes from.
function ExternalKeyboard:findAndSetupKeyboards()
local keyboards = FindKeyboard:find()
local keyboards = findKeyboards()
-- A USB keyboard may be recognized as several devices under a hub. And several of them may
-- have keyboard capabilities set. Yet, only one would emit the events. The solution is to open all of them.
for __, keyboard_info in ipairs(keyboards) do
self:setupKeyboard(keyboard_info.event_path)
self:setupKeyboard(keyboard_info)
end
end
function ExternalKeyboard:onEvdevInputRemove(evdev)
UIManager:scheduleIn(0.5, self._onEvdevInputRemove, self, evdev)
end
function ExternalKeyboard:setupKeyboard(data)
local keyboard_info
if type(data) == "table" then
-- We came from findAndSetupKeyboards, no need to-re-check the device
keyboard_info = data
else
-- We came from a USB hotplug event handler, check the specified path
local event_path = data
function ExternalKeyboard:setupKeyboard(event_path)
local keyboard_info = FindKeyboard:check(event_path:match(".+/(.+)")) -- FindKeyboard only wants eventN, not the full path
if not keyboard_info then
logger.dbg("ExternalKeyboard:setupKeyboard:", event_path, "doesn't look like a keyboard")
return
keyboard_info = checkKeyboard(event_path)
if not keyboard_info then
logger.dbg("ExternalKeyboard:setupKeyboard:", event_path, "doesn't look like a keyboard")
return
end
end
local has_dpad_func = Device.hasDPad
logger.dbg("ExternalKeyboard:setupKeyboard", keyboard_info.event_path, "has_dpad", keyboard_info.has_dpad)