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:
parent
fe7b10f18d
commit
9f37863f00
@ -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:
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user