mirror of
https://github.com/koreader/koreader
synced 2024-11-13 19:11:25 +00:00
input: drop use of ffi/input
Get rid of the weird interaction between device implementations, `ffi.util` (`isSDL`, `noSDL`) and the device input code: each device knows if it's using SDL or not, so rely on that to load the right underlying input implementation.
This commit is contained in:
parent
283c764351
commit
0c0d2ab9f1
2
base
2
base
@ -1 +1 @@
|
||||
Subproject commit e65c7dd5f867cb026e6058a680f14da6adb77dd3
|
||||
Subproject commit be7404777ba0b45b551084c708b460e5a623007d
|
@ -4,54 +4,46 @@ local util = require("ffi/util")
|
||||
|
||||
local function probeDevice()
|
||||
if isAndroid then
|
||||
util.noSDL()
|
||||
return require("device/android/device")
|
||||
end
|
||||
|
||||
local kindle_test_stat = lfs.attributes("/proc/usid")
|
||||
if kindle_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/kindle/device")
|
||||
end
|
||||
|
||||
local kobo_test_stat = lfs.attributes("/bin/kobo_config.sh")
|
||||
if kobo_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/kobo/device")
|
||||
end
|
||||
|
||||
local pbook_test_stat = lfs.attributes("/ebrmain")
|
||||
if pbook_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/pocketbook/device")
|
||||
end
|
||||
|
||||
local remarkable_test_stat = lfs.attributes("/usr/bin/xochitl")
|
||||
if remarkable_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/remarkable/device")
|
||||
end
|
||||
|
||||
local sony_prstux_test_stat = lfs.attributes("/etc/PRSTUX")
|
||||
if sony_prstux_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/sony-prstux/device")
|
||||
end
|
||||
|
||||
local cervantes_test_stat = lfs.attributes("/usr/bin/ntxinfo")
|
||||
if cervantes_test_stat then
|
||||
util.noSDL()
|
||||
return require("device/cervantes/device")
|
||||
end
|
||||
|
||||
-- add new ports here:
|
||||
--
|
||||
-- if --[[ implement a proper test instead --]] false then
|
||||
-- util.noSDL()
|
||||
-- return require("device/newport/device")
|
||||
-- end
|
||||
|
||||
if util.isSDL() then
|
||||
if util.loadSDL2() then
|
||||
return require("device/sdl/device")
|
||||
end
|
||||
|
||||
|
@ -123,9 +123,9 @@ function Cervantes:init()
|
||||
[116] = "Power",
|
||||
}
|
||||
}
|
||||
self.input.open("/dev/input/event0") -- Keys
|
||||
self.input.open("/dev/input/event1") -- touchscreen
|
||||
self.input.open("fake_events") -- usb events
|
||||
self.input:open("/dev/input/event0") -- Keys
|
||||
self.input:open("/dev/input/event1") -- touchscreen
|
||||
self.input:open("fake_events") -- usb events
|
||||
self:initEventAdjustHooks()
|
||||
Generic.init(self)
|
||||
end
|
||||
|
@ -608,7 +608,7 @@ function Device:exit()
|
||||
G_reader_settings:close()
|
||||
|
||||
-- I/O teardown
|
||||
self.input.teardown()
|
||||
self.input:teardown()
|
||||
end
|
||||
|
||||
-- Lifted from busybox's libbb/inet_cksum.c
|
||||
|
@ -9,7 +9,6 @@ local GestureDetector = require("device/gesturedetector")
|
||||
local Key = require("device/key")
|
||||
local UIManager
|
||||
local framebuffer = require("ffi/framebuffer")
|
||||
local input = require("ffi/input")
|
||||
local logger = require("logger")
|
||||
local time = require("ui/time")
|
||||
local _ = require("gettext")
|
||||
@ -211,6 +210,31 @@ function Input:new(o)
|
||||
end
|
||||
|
||||
function Input:init()
|
||||
-- Setup underlying input implementation.
|
||||
if self.input then -- luacheck: ignore 542
|
||||
-- Already setup (e.g. stubbed by the testsuite).
|
||||
elseif self.device:isSDL() then
|
||||
self.input = require("ffi/input_SDL2_0")
|
||||
self.hasClipboardText = function()
|
||||
return self.input.hasClipboardText()
|
||||
end
|
||||
self.getClipboardText = function()
|
||||
return self.input.getClipboardText()
|
||||
end
|
||||
self.setClipboardText = function(text)
|
||||
return self.input.setClipboardText(text)
|
||||
end
|
||||
self.gameControllerRumble = function(left_intensity, right_intensity, duration)
|
||||
return self.input.gameControllerRumble(left_intensity, right_intensity, duration)
|
||||
end
|
||||
elseif self.device:isAndroid() then
|
||||
self.input = require("ffi/input_android")
|
||||
elseif self.device:isPocketBook() then
|
||||
self.input = require("ffi/input_pocketbook")
|
||||
else
|
||||
self.input = require("libs/libkoreader-input")
|
||||
end
|
||||
|
||||
-- Initialize instance-specific tables
|
||||
-- NOTE: All of these arrays may be destroyed & recreated at runtime, so we don't want a parent/class object for those.
|
||||
self.timer_callbacks = {}
|
||||
@ -306,10 +330,13 @@ Note that we adhere to the "." syntax here for compatibility.
|
||||
|
||||
The `name` argument is optional, and used for logging purposes only.
|
||||
--]]
|
||||
function Input.open(path, name)
|
||||
function Input:open(path, name)
|
||||
if self.input.is_ffi then
|
||||
return self.input.open(path, name)
|
||||
end
|
||||
-- Make sure we don't open the same device twice.
|
||||
if not Input.opened_devices[path] then
|
||||
local fd = input.open(path)
|
||||
local fd = self.input.open(path)
|
||||
if fd then
|
||||
Input.opened_devices[path] = fd
|
||||
if name then
|
||||
@ -332,10 +359,10 @@ Note that we adhere to the "." syntax here for compatibility.
|
||||
The `name` argument is optional, and used for logging purposes only.
|
||||
`path` is mandatory, though!
|
||||
--]]
|
||||
function Input.fdopen(fd, path, name)
|
||||
function Input:fdopen(fd, path, name)
|
||||
-- Make sure we don't open the same device twice.
|
||||
if not Input.opened_devices[path] then
|
||||
input.fdopen(fd)
|
||||
self.input.fdopen(fd)
|
||||
-- As with input.open, it will throw on error (closing the fd first)
|
||||
Input.opened_devices[path] = fd
|
||||
if name then
|
||||
@ -352,11 +379,14 @@ Wrapper for our Lua/C input module's close.
|
||||
|
||||
Note that we adhere to the "." syntax here for compatibility.
|
||||
--]]
|
||||
function Input.close(path)
|
||||
function Input:close(path)
|
||||
if self.input.is_ffi then
|
||||
return self.input.close(path)
|
||||
end
|
||||
-- Make sure we actually know about this device
|
||||
local fd = Input.opened_devices[path]
|
||||
if fd then
|
||||
local ok, err = input.close(fd)
|
||||
local ok, err = self.input.close(fd)
|
||||
if ok or err == C.ENODEV then
|
||||
-- Either the call succeeded,
|
||||
-- or the backend had already caught an ENODEV in waitForInput and closed the fd internally.
|
||||
@ -374,25 +404,11 @@ Wrapper for our Lua/C input module's closeAll.
|
||||
|
||||
Note that we adhere to the "." syntax here for compatibility.
|
||||
--]]
|
||||
function Input.teardown()
|
||||
input.closeAll()
|
||||
function Input:teardown()
|
||||
self.input.closeAll()
|
||||
Input.opened_devices = {}
|
||||
end
|
||||
|
||||
-- Wrappers for the custom FFI implementations with no concept of paths or fd
|
||||
if input.is_ffi then
|
||||
-- Pass args as-is. None of 'em actually *take* arguments, but some may be invoked as methods...
|
||||
function Input.open(...)
|
||||
return input.open(...)
|
||||
end
|
||||
function Input.close(...)
|
||||
return input.close(...)
|
||||
end
|
||||
function Input.teardown(...)
|
||||
return input.closeAll(...)
|
||||
end
|
||||
end
|
||||
|
||||
--[[--
|
||||
Different device models can implement their own hooks and register them.
|
||||
--]]
|
||||
@ -536,7 +552,7 @@ function Input:setTimeout(slot, ges, cb, origin, delay)
|
||||
|
||||
-- If we're on a platform with the timerfd backend, handle that
|
||||
local timerfd
|
||||
if input.setTimer then
|
||||
if self.input.setTimer then
|
||||
-- If GestureDetector's clock source probing was inconclusive, do this on the UI timescale instead.
|
||||
if clock_id == -1 then
|
||||
deadline = time.now() + delay
|
||||
@ -548,7 +564,7 @@ function Input:setTimeout(slot, ges, cb, origin, delay)
|
||||
-- instead of ensuring that ourselves via a polling timeout.
|
||||
-- This ensures perfect accuracy, and allows it to be computed in the event's own timescale.
|
||||
local sec, usec = time.split_s_us(deadline)
|
||||
timerfd = input.setTimer(clock_id, sec, usec)
|
||||
timerfd = self.input.setTimer(clock_id, sec, usec)
|
||||
end
|
||||
if timerfd then
|
||||
-- It worked, tweak the table a bit to make it clear the deadline will be handled by the kernel
|
||||
@ -582,7 +598,7 @@ function Input:clearTimeout(slot, ges)
|
||||
if item.slot == slot and (not ges or item.gesture == ges) then
|
||||
-- If the timerfd backend is in use, close the fd and free the list's node, too.
|
||||
if item.timerfd then
|
||||
input.clearTimer(item.timerfd)
|
||||
self.input.clearTimer(item.timerfd)
|
||||
end
|
||||
table.remove(self.timer_callbacks, i)
|
||||
end
|
||||
@ -591,10 +607,10 @@ end
|
||||
|
||||
function Input:clearTimeouts()
|
||||
-- If the timerfd backend is in use, close the fds, too
|
||||
if input.setTimer then
|
||||
if self.input.setTimer then
|
||||
for _, item in ipairs(self.timer_callbacks) do
|
||||
if item.timerfd then
|
||||
input.clearTimer(item.timerfd)
|
||||
self.input.clearTimer(item.timerfd)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1354,7 +1370,7 @@ function Input:waitEvent(now, deadline)
|
||||
|
||||
local timerfd
|
||||
local sec, usec = time.split_s_us(poll_timeout)
|
||||
ok, ev, timerfd = input.waitForEvent(sec, usec)
|
||||
ok, ev, timerfd = self.input.waitForEvent(sec, usec)
|
||||
-- We got an actual input event, go and process it
|
||||
if ok then break end
|
||||
|
||||
@ -1404,7 +1420,7 @@ function Input:waitEvent(now, deadline)
|
||||
-- GestureDetector has guards in place to avoid double frees in case the callback itself
|
||||
-- affected the timerfd or timer_callbacks list (e.g., by dropping a contact).
|
||||
if timerfd then
|
||||
input.clearTimer(timerfd)
|
||||
self.input.clearTimer(timerfd)
|
||||
end
|
||||
table.remove(self.timer_callbacks, timer_idx)
|
||||
|
||||
@ -1441,7 +1457,7 @@ function Input:waitEvent(now, deadline)
|
||||
end
|
||||
|
||||
local sec, usec = time.split_s_us(poll_timeout)
|
||||
ok, ev = input.waitForEvent(sec, usec)
|
||||
ok, ev = self.input.waitForEvent(sec, usec)
|
||||
end -- if #timer_callbacks > 0
|
||||
|
||||
-- Handle errors
|
||||
|
@ -489,7 +489,7 @@ function Kindle:openInputDevices()
|
||||
for i = 0, tonumber(dev_count[0]) - 1 do
|
||||
local dev = devices[i]
|
||||
if dev.matched then
|
||||
self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
self.input:fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
end
|
||||
end
|
||||
C.free(devices)
|
||||
@ -498,11 +498,11 @@ function Kindle:openInputDevices()
|
||||
logger.warn("We failed to auto-detect the proper input devices, input handling may be inconsistent!")
|
||||
if self.touch_dev then
|
||||
-- We've got a preferred path specified for the touch panel
|
||||
self.input.open(self.touch_dev)
|
||||
self.input:open(self.touch_dev)
|
||||
else
|
||||
-- That generally works out well enough on legacy devices...
|
||||
self.input.open("/dev/input/event0")
|
||||
self.input.open("/dev/input/event1")
|
||||
self.input:open("/dev/input/event0")
|
||||
self.input:open("/dev/input/event1")
|
||||
end
|
||||
end
|
||||
|
||||
@ -516,14 +516,14 @@ function Kindle:openInputDevices()
|
||||
for i = 0, tonumber(dev_count[0]) - 1 do
|
||||
local dev = devices[i]
|
||||
if dev.matched then
|
||||
self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
self.input:fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
end
|
||||
end
|
||||
C.free(devices)
|
||||
end
|
||||
end
|
||||
|
||||
self.input.open("fake_events")
|
||||
self.input:open("fake_events")
|
||||
end
|
||||
|
||||
function Kindle:otaModel()
|
||||
|
@ -880,9 +880,9 @@ function Kobo:init()
|
||||
-- We need to single out whichever device provides pagination buttons or sleep cover events, as we'll want to tweak key repeat there...
|
||||
-- The first one will do, as it's extremely likely to be event0, and that's pretty fairly set in stone on NTX boards.
|
||||
if (bit.band(dev.type, C.INPUT_PAGINATION_BUTTONS) ~= 0 or bit.band(dev.type, C.INPUT_SLEEP_COVER) ~= 0) and not self.ntx_fd then
|
||||
self.ntx_fd = self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
self.ntx_fd = self.input:fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
else
|
||||
self.input.fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
self.input:fdopen(tonumber(dev.fd), ffi.string(dev.path), ffi.string(dev.name))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -891,9 +891,9 @@ function Kobo:init()
|
||||
-- Auto-detection failed, warn and fall back to defaults
|
||||
logger.warn("We failed to auto-detect the proper input devices, input handling may be inconsistent!")
|
||||
-- Various HW Buttons, Switches & Synthetic NTX events
|
||||
self.ntx_fd = self.input.open(self.ntx_dev)
|
||||
self.ntx_fd = self.input:open(self.ntx_dev)
|
||||
-- Touch panel
|
||||
self.input.open(self.touch_dev)
|
||||
self.input:open(self.touch_dev)
|
||||
end
|
||||
|
||||
-- NOTE: On devices with a gyro, there may be a dedicated input device outputting the raw accelerometer data
|
||||
|
@ -243,7 +243,7 @@ function PocketBook:init()
|
||||
self._model_init()
|
||||
-- NOTE: This is the odd one out actually calling input.open as a *method*,
|
||||
-- which the imp supports to get access to self.input.raw_input
|
||||
if (not self.input.raw_input) or (not pcall(self.input.open, self.input)) then
|
||||
if (not self.input.raw_input) or (not pcall(self.input.open, self.input, self.input)) then
|
||||
inkview.OpenScreen()
|
||||
-- Raw mode open failed (no permissions?), so we'll run the usual way.
|
||||
-- Disable touch coordinate translation as inkview will do that.
|
||||
|
@ -167,9 +167,9 @@ function Remarkable:init()
|
||||
self.input_ts = "/dev/input/touchscreen0"
|
||||
end
|
||||
|
||||
self.input.open(self.input_wacom) -- Wacom
|
||||
self.input.open(self.input_ts) -- Touchscreen
|
||||
self.input.open(self.input_buttons) -- Buttons
|
||||
self.input:open(self.input_wacom) -- Wacom
|
||||
self.input:open(self.input_ts) -- Touchscreen
|
||||
self.input:open(self.input_buttons) -- Buttons
|
||||
|
||||
local scalex = screen_width / self.mt_width
|
||||
local scaley = screen_height / self.mt_height
|
||||
@ -202,7 +202,7 @@ function Remarkable:init()
|
||||
end
|
||||
|
||||
-- USB plug/unplug, battery charge/not charging are generated as fake events
|
||||
self.input.open("fake_events")
|
||||
self.input:open("fake_events")
|
||||
|
||||
local rotation_mode = self.screen.DEVICE_ROTATED_UPRIGHT
|
||||
self.screen.native_rotation_mode = rotation_mode
|
||||
|
@ -193,7 +193,6 @@ function Device:init()
|
||||
local ok, re = pcall(self.screen.setWindowIcon, self.screen, "resources/koreader.png")
|
||||
if not ok then logger.warn(re) end
|
||||
|
||||
local input = require("ffi/input")
|
||||
self.input = require("device/input"):new{
|
||||
device = self,
|
||||
event_map = dofile("frontend/device/sdl/event_map_sdl2.lua"),
|
||||
@ -296,18 +295,6 @@ function Device:init()
|
||||
UIManager:sendEvent(Event:new("TextInput", tostring(ev.value)))
|
||||
end
|
||||
end,
|
||||
hasClipboardText = function()
|
||||
return input.hasClipboardText()
|
||||
end,
|
||||
getClipboardText = function()
|
||||
return input.getClipboardText()
|
||||
end,
|
||||
setClipboardText = function(text)
|
||||
return input.setClipboardText(text)
|
||||
end,
|
||||
gameControllerRumble = function(left_intensity, right_intensity, duration)
|
||||
return input.gameControllerRumble(left_intensity, right_intensity, duration)
|
||||
end,
|
||||
}
|
||||
|
||||
self.keyboard_layout = dofile("frontend/device/sdl/keyboard_layout.lua")
|
||||
|
@ -59,10 +59,10 @@ function SonyPRSTUX:init()
|
||||
event_map = dofile("frontend/device/sony-prstux/event_map.lua"),
|
||||
}
|
||||
|
||||
self.input.open("/dev/input/event0") -- Keys
|
||||
self.input.open("/dev/input/event1") -- touchscreen
|
||||
self.input.open("/dev/input/event2") -- power button
|
||||
self.input.open("fake_events") -- usb plug-in/out and charging/not-charging
|
||||
self.input:open("/dev/input/event0") -- Keys
|
||||
self.input:open("/dev/input/event1") -- touchscreen
|
||||
self.input:open("/dev/input/event2") -- power button
|
||||
self.input:open("fake_events") -- usb plug-in/out and charging/not-charging
|
||||
self.input:registerEventAdjustHook(adjustTouchEvt)
|
||||
|
||||
local rotation_mode = self.screen.DEVICE_ROTATED_COUNTER_CLOCKWISE
|
||||
|
@ -247,7 +247,7 @@ function ExternalKeyboard:_onEvdevInputRemove(event_path)
|
||||
end
|
||||
|
||||
-- Close our Input handle on it
|
||||
Device.input.close(event_path)
|
||||
Device.input:close(event_path)
|
||||
|
||||
ExternalKeyboard.keyboard_fds[event_path] = nil
|
||||
ExternalKeyboard.connected_keyboards = ExternalKeyboard.connected_keyboards - 1
|
||||
@ -363,7 +363,7 @@ function ExternalKeyboard:setupKeyboard(data)
|
||||
logger.dbg("ExternalKeyboard:setupKeyboard", keyboard_info.name, "@", keyboard_info.event_path, "- has_dpad:", keyboard_info.has_dpad)
|
||||
-- Check if we already know about this event file.
|
||||
if ExternalKeyboard.keyboard_fds[keyboard_info.event_path] == nil then
|
||||
local ok, fd = pcall(Device.input.fdopen, keyboard_info.event_fd, keyboard_info.event_path, keyboard_info.name)
|
||||
local ok, fd = pcall(Device.input.fdopen, Device.input, keyboard_info.event_fd, keyboard_info.event_path, keyboard_info.name)
|
||||
if not ok then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = "Error opening keyboard:\n" .. tostring(fd),
|
||||
|
@ -41,6 +41,8 @@ describe("device module", function()
|
||||
before_each(function()
|
||||
package.loaded["ffi/framebuffer_mxcfb"] = mock_fb
|
||||
mock_input = require("device/input")
|
||||
mock_input.input = {}
|
||||
mock_input.gameControllerRumble = function() return false end
|
||||
stub(mock_input, "open")
|
||||
stub(os, "getenv")
|
||||
stub(os, "execute")
|
||||
@ -308,9 +310,8 @@ describe("device module", function()
|
||||
package.unload("device/kindle/device")
|
||||
io.open = make_io_open_kindle_model_override("G0B0GCXXX")
|
||||
|
||||
mock_ffi_input = require("ffi/input")
|
||||
stub(mock_ffi_input, "waitForEvent")
|
||||
mock_ffi_input.waitForEvent.returns(true, {
|
||||
stub(mock_input.input, "waitForEvent")
|
||||
mock_input.input.waitForEvent.returns(true, {
|
||||
{
|
||||
type = C.EV_ABS,
|
||||
time = {
|
||||
@ -333,7 +334,7 @@ describe("device module", function()
|
||||
kindle_dev.input:waitEvent()
|
||||
assert.stub(UIManager.onRotation).was_called()
|
||||
|
||||
mock_ffi_input.waitForEvent:revert()
|
||||
mock_input.input.waitForEvent:revert()
|
||||
UIManager.onRotation:revert()
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user