diff --git a/frontend/device/input.lua b/frontend/device/input.lua index ca6e5e0a1..6079a4c93 100644 --- a/frontend/device/input.lua +++ b/frontend/device/input.lua @@ -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: diff --git a/frontend/device/remarkable/device.lua b/frontend/device/remarkable/device.lua index e2db4d8d4..7edb9d367 100644 --- a/frontend/device/remarkable/device.lua +++ b/frontend/device/remarkable/device.lua @@ -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")