2
0
mirror of https://github.com/koreader/koreader synced 2024-11-16 06:12:56 +00:00

rM: Handle input shenanigans on mainline kernels (#10168)

Add a dedicated handler to handle mixed pen + panel, when panel sends both mt + st and stylus only st
Don't stomp on panel slots in the Wacom protocol handler
Get rid of a few superfluous nil guards
Return early in the EV_KEY handler for touch-related events (i.e., BTN_)
This commit is contained in:
NiLuJe 2023-03-02 18:08:56 +01:00 committed by GitHub
parent fe7b10f18d
commit 9f37863f00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 39 deletions

View File

@ -507,26 +507,28 @@ function Input:handleKeyBoardEv(ev)
-- Detect loss of contact for the "snow" protocol...
-- NOTE: Some ST devices may also behave similarly, but we handle those via ABS_PRESSURE
if self.snow_protocol then
if ev.code == C.BTN_TOUCH and ev.value == 0 then
-- Kernel sends it after loss of contact for *all* slots,
-- only once the final contact point has been lifted.
if #self.MTSlots == 0 then
-- Likely, since this is usually in its own event stream,
-- meaning self.MTSlots has *just* been cleared by our last EV_SYN:SYN_REPORT handler...
-- So, poke at the actual data to find the slots that are currently active (i.e., in the down state),
-- and re-populate a minimal self.MTSlots array that simply switches them to the up state ;).
for _, slot in pairs(self.ev_slots) do
if slot.id ~= -1 then
table.insert(self.MTSlots, slot)
slot.id = -1
if ev.code == C.BTN_TOUCH then
if ev.value == 0 then
-- Kernel sends it after loss of contact for *all* slots,
-- only once the final contact point has been lifted.
if #self.MTSlots == 0 then
-- Likely, since this is usually in its own event stream,
-- meaning self.MTSlots has *just* been cleared by our last EV_SYN:SYN_REPORT handler...
-- So, poke at the actual data to find the slots that are currently active (i.e., in the down state),
-- and re-populate a minimal self.MTSlots array that simply switches them to the up state ;).
for _, slot in pairs(self.ev_slots) do
if slot.id ~= -1 then
table.insert(self.MTSlots, slot)
slot.id = -1
end
end
else
-- Unlikely, given what we mentioned above...
-- Note that, funnily enough, its EV_KEY:BTN_TOUCH:1 counterpart
-- *can* be in the same initial event stream as the EV_ABS batch...
for _, MTSlot in ipairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "id", -1)
end
end
else
-- Unlikely, given what we mentioned above...
-- Note that, funnily enough, its EV_KEY:BTN_TOUCH:1 counterpart
-- *can* be in the same initial event stream as the EV_ABS batch...
for _, MTSlot in ipairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "id", -1)
end
end
@ -534,23 +536,30 @@ function Input:handleKeyBoardEv(ev)
end
elseif self.wacom_protocol then
if ev.code == C.BTN_TOOL_PEN then
-- Always send pen data to slot 0
self:setupSlotData(0)
-- Always send pen data to slot 2
self:setupSlotData(2)
if ev.value == 1 then
self:setCurrentMtSlot("tool", TOOL_TYPE_PEN)
else
self:setCurrentMtSlot("tool", TOOL_TYPE_FINGER)
end
return
elseif ev.code == C.BTN_TOUCH then
-- Much like on snow, use this to detect contact down & lift,
-- as ABS_PRESSURE may be entirely omitted from hover events,
-- and ABS_DISTANCE is not very clear cut...
self:setupSlotData(0)
if ev.value == 1 then
self:setCurrentMtSlot("id", 0)
else
self:setCurrentMtSlot("id", -1)
-- BTN_TOUCH is bracketed by BTN_TOOL_PEN, so we can limit this to pens, to avoid stomping on panel slots.
if self:getCurrentMtSlotData("tool") == TOOL_TYPE_PEN then
-- Much like on snow, use this to detect contact down & lift,
-- as ABS_PRESSURE may be entirely omitted from hover events,
-- and ABS_DISTANCE is not very clear cut...
self:setupSlotData(2)
if ev.value == 1 then
self:setCurrentMtSlot("id", 2)
else
self:setCurrentMtSlot("id", -1)
end
end
return
end
end
@ -772,10 +781,9 @@ function Input:handleTouchEv(ev)
self:setCurrentMtSlotChecked("x", ev.value)
elseif ev.code == C.ABS_MT_POSITION_Y or ev.code == C.ABS_Y then
self:setCurrentMtSlotChecked("y", ev.value)
elseif self.pressure_event and ev.code == self.pressure_event and ev.value == 0 then
elseif ev.code == self.pressure_event and ev.value == 0 then
-- Drop hovering *pen* events
local tool = self:getCurrentMtSlotData("tool")
if tool and tool == TOOL_TYPE_PEN then
if self:getCurrentMtSlotData("tool") == TOOL_TYPE_PEN then
self:setCurrentMtSlot("id", -1)
end
end
@ -797,6 +805,47 @@ function Input:handleTouchEv(ev)
end
end
-- This is a slightly modified version of the above, tailored to play nice with devices with multiple absolute input devices,
-- (i.e., screen + pen), where one or both of these send conflicting events that we need to hook... (e.g., rM on mainline).
function Input:handleMixedTouchEv(ev)
if ev.type == C.EV_ABS then
if ev.code == C.ABS_MT_SLOT then
self:setupSlotData(ev.value)
elseif ev.code == C.ABS_MT_TRACKING_ID then
self:setCurrentMtSlotChecked("id", ev.value)
elseif ev.code == C.ABS_MT_POSITION_X then
-- Panel
self:setCurrentMtSlotChecked("x", ev.value)
elseif ev.code == C.ABS_X then
-- Panel + Stylus, but we only want to honor stylus!
if self:getCurrentMtSlotData("tool") == TOOL_TYPE_PEN then
self:setCurrentMtSlotChecked("x", ev.value)
end
elseif ev.code == C.ABS_MT_POSITION_Y then
self:setCurrentMtSlotChecked("y", ev.value)
elseif ev.code == C.ABS_Y then
if self:getCurrentMtSlotData("tool") == TOOL_TYPE_PEN then
self:setCurrentMtSlotChecked("y", ev.value)
end
end
elseif ev.type == C.EV_SYN then
if ev.code == C.SYN_REPORT then
for _, MTSlot in ipairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "timev", time.timeval(ev.time))
end
-- feed ev in all slots to state machine
local touch_gestures = self.gesture_detector:feedEvent(self.MTSlots)
self:newFrame()
local ges_evs = {}
for _, touch_ges in ipairs(touch_gestures) do
self:gestureAdjustHook(touch_ges)
table.insert(ges_evs, Event:new("Gesture", self.gesture_detector:adjustGesCoordinate(touch_ges)))
end
return ges_evs
end
end
end
function Input:handleTouchEvPhoenix(ev)
-- Hack on handleTouchEV for the Kobo Aura
-- It seems to be using a custom protocol:

View File

@ -59,8 +59,7 @@ local Remarkable1 = Remarkable:extend{
function Remarkable1:adjustTouchEvent(ev, by)
if ev.type == C.EV_ABS then
-- Mirror X and Y and scale up both X & Y as touch input is different res from
-- display
-- Mirror X and Y and scale up both X & Y as touch input is different res from display
if ev.code == C.ABS_MT_POSITION_X then
ev.value = (Remarkable1.mt_width - ev.value) * by.mt_scale_x
end
@ -82,8 +81,7 @@ local Remarkable2 = Remarkable:extend{
function Remarkable2:adjustTouchEvent(ev, by)
if ev.type == C.EV_ABS then
-- Mirror Y and scale up both X & Y as touch input is different res from
-- display
-- Mirror Y and scale up both X & Y as touch input is different res from display
if ev.code == C.ABS_MT_POSITION_X then
ev.value = (ev.value) * by.mt_scale_x
end
@ -116,7 +114,6 @@ local adjustAbsEvt = function(self, ev)
end
end
function Remarkable:init()
local oxide_running = os.execute("systemctl is-active --quiet tarnish") == 0
logger.info(string.format("Oxide running?: %s", oxide_running))
@ -153,8 +150,46 @@ function Remarkable:init()
local scalex = screen_width / self.mt_width
local scaley = screen_height / self.mt_height
self.input:registerEventAdjustHook(adjustAbsEvt)
self.input:registerEventAdjustHook(self.adjustTouchEvent, {mt_scale_x=scalex, mt_scale_y=scaley})
-- Assume input stuff is saner on mainline kernels...
-- (c.f., https://github.com/koreader/koreader/issues/10012)
local is_mainline = false
--- @fixme: Find a better way to discriminate mainline from stock...
local std_out = io.popen("uname -r", "r")
if std_out then
local release = std_out:read("*line")
std_out:close()
release = release:match("^(%d+%.%d+)%.%d+.*$")
release = tonumber(release)
if release and release >= 6.2 then
is_mainline = true
end
end
if is_mainline then
-- NOTE: The panel sends *both* ABS_MT_ & ABS_ coordinates, while the pen only sends ABS_ coordinates.
-- Since we have to apply *different* mangling to each of them,
-- we use a custom input handler that'll ignore ABS_ coordinates from the panel...
self.input.handleTouchEv = self.input.handleMixedTouchEv
local mt_height = self.mt_height
local mainlineInputMangling = function(this, ev)
if ev.type == C.EV_ABS then
-- Mirror Y for the touch panel
if ev.code == C.ABS_MT_POSITION_Y then
ev.value = mt_height - ev.value
-- Handle the Wacom pen
elseif ev.code == C.ABS_X then
ev.code = C.ABS_Y
ev.value = (wacom_height - ev.value) * wacom_scale_y
elseif ev.code == C.ABS_Y then
ev.code = C.ABS_X
ev.value = ev.value * wacom_scale_x
end
end
end
self.input:registerEventAdjustHook(mainlineInputMangling)
else
self.input:registerEventAdjustHook(adjustAbsEvt)
self.input:registerEventAdjustHook(self.adjustTouchEvent, {mt_scale_x=scalex, mt_scale_y=scaley})
end
-- USB plug/unplug, battery charge/not charging are generated as fake events
self.input.open("fake_events")