diff --git a/frontend/apps/reader/modules/readerdictionary.lua b/frontend/apps/reader/modules/readerdictionary.lua index 780091fad..f78f2c508 100644 --- a/frontend/apps/reader/modules/readerdictionary.lua +++ b/frontend/apps/reader/modules/readerdictionary.lua @@ -20,6 +20,7 @@ local logger = require("logger") local time = require("ui/time") local util = require("util") local _ = require("gettext") +local Input = Device.input local T = ffiUtil.template -- We'll store the list of available dictionaries as a module local @@ -995,10 +996,10 @@ function ReaderDictionary:showDict(word, results, boxes, link) if not results.lookup_cancelled and self._lookup_start_time and (time.now() - self._lookup_start_time) > self.quick_dismiss_before_delay then -- If the search took more than a few seconds to be done, discard - -- queued and coming up events to avoid a voluntary dismissal + -- queued and coming up input events to avoid a voluntary dismissal -- (because the user felt the result would not come) to kill the -- result that finally came and is about to be displayed - UIManager:discardEvents(true) + Input:inhibitInputUntil(true) end end end diff --git a/frontend/apps/reader/modules/readerrolling.lua b/frontend/apps/reader/modules/readerrolling.lua index 6420958e4..e16abc1c4 100644 --- a/frontend/apps/reader/modules/readerrolling.lua +++ b/frontend/apps/reader/modules/readerrolling.lua @@ -12,6 +12,7 @@ local bit = require("bit") local logger = require("logger") local time = require("ui/time") local _ = require("gettext") +local Input = Device.input local Screen = Device.screen local T = require("ffi/util").template @@ -868,7 +869,7 @@ function ReaderRolling:onUpdatePos() return true end - UIManager:discardEvents(math.huge) -- Discard any past and upcoming input events for the next hour. + Input:inhibitInput(true) -- Inhibit any past and upcoming input events. Device:setIgnoreInput(true) -- Avoid ANRs on Android with unprocessed events. -- Calling this now ensures the re-rendering is done by crengine @@ -884,7 +885,7 @@ function ReaderRolling:onUpdatePos() self:updatePos() Device:setIgnoreInput(false) -- Allow processing of events (on Android). - UIManager:discardEvents(0.2) -- Discard events, which might have occurred (double tap). + Input:inhibitInputUntil(0.2) -- Discard input events, which might have occurred (double tap). -- We can use a smaller duration than the default (quite large to avoid accidental dismissals), -- to allow for quicker setting changes and rendering comparisons. end diff --git a/frontend/device/input.lua b/frontend/device/input.lua index c1e057891..83fc3e31e 100644 --- a/frontend/device/input.lua +++ b/frontend/device/input.lua @@ -258,6 +258,9 @@ function Input:init() if G_reader_settings:isTrue("backspace_as_back") then table.insert(self.group.Back, "Backspace") end + + -- setup inhibitInputUntil scheduling function + self._inhibitInputUntil_func = function() self:inhibitInputUntil() end end --[[-- @@ -1337,4 +1340,38 @@ function Input:inhibitInput(toggle) end end +--[[-- +Request all input events to be ignored for some duration. + +@param set_or_seconds either `true`, in which case a platform-specific delay is chosen, or a duration in seconds (***int***). +]] +function Input:inhibitInputUntil(set_or_seconds) + local UIManager = require("ui/uimanager") + UIManager:unschedule(self._inhibitInputUntil_func) + if not set_or_seconds then -- remove any previously set + self:inhibitInput(false) + return + end + local delay_s + if set_or_seconds == true then + -- Use an adequate delay to account for device refresh duration + -- so any events happening in this delay (ie. before a widget + -- is really painted on screen) are discarded. + if self.device:hasEinkScreen() then + -- A screen refresh can take a few 100ms, + -- sometimes > 500ms on some devices/temperatures. + -- So, block for 400ms (to have it displayed) + 400ms + -- for user reaction to it + delay_s = 0.8 + else + -- On non-eInk screen, display is usually instantaneous + delay_s = 0.4 + end + else -- we expect a number + delay_s = set_or_seconds + end + UIManager:scheduleIn(delay_s, self._inhibitInputUntil_func) + self:inhibitInput(true) +end + return Input diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 9d58348ec..6ff885981 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -42,7 +42,6 @@ local UIManager = { _exit_code = nil, _prevent_standby_count = 0, _prev_prevent_standby_count = 0, - _discard_events_till = nil, event_hook = require("ui/hook_container"):new() } @@ -1045,37 +1044,6 @@ function UIManager:quit() end end ---[[-- -Request all @{ui.event.Event|Event}s to be ignored for some duration. - -@param set_or_seconds either `true`, in which case a platform-specific delay is chosen, or a duration in seconds (***int***). -]] -function UIManager:discardEvents(set_or_seconds) - if not set_or_seconds then -- remove any previously set - self._discard_events_till = nil - return - end - local delay - if set_or_seconds == true then - -- Use an adequate delay to account for device refresh duration - -- so any events happening in this delay (ie. before a widget - -- is really painted on screen) are discarded. - if Device:hasEinkScreen() then - -- A screen refresh can take a few 100ms, - -- sometimes > 500ms on some devices/temperatures. - -- So, block for 400ms (to have it displayed) + 400ms - -- for user reaction to it - delay = time.ms(800) - else - -- On non-eInk screen, display is usually instantaneous - delay = time.ms(400) - end - else -- we expect a number - delay = time.s(set_or_seconds) - end - self._discard_events_till = time.now() + delay -end - --[[-- Transmits an @{ui.event.Event|Event} to active widgets, top to bottom. Stops at the first handler that returns `true`. @@ -1087,15 +1055,6 @@ which itself will take care of propagating an event to its members. function UIManager:sendEvent(event) if #self._window_stack == 0 then return end - -- Ensure discardEvents - if self._discard_events_till then - if time.now() < self._discard_events_till then - return - else - self._discard_events_till = nil - end - end - -- The top widget gets to be the first to get the event local top_widget = self._window_stack[#self._window_stack] @@ -1131,7 +1090,7 @@ function UIManager:sendEvent(event) if checked_widgets[widget] == nil then checked_widgets[widget] = true -- Widget's active widgets have precedence to handle this event - -- NOTE: While FileManager only has a single (screenshotter), ReaderUI has many active_widgets (each ReaderUI module gets added to the list). + -- NOTE: While FileManager only has a single (screenshotter), ReaderUI has a few active_widgets. if widget.widget.active_widgets then for _, active_widget in ipairs(widget.widget.active_widgets) do if active_widget:handleEvent(event) then return end diff --git a/frontend/ui/widget/confirmbox.lua b/frontend/ui/widget/confirmbox.lua index ea0c8db51..181769420 100644 --- a/frontend/ui/widget/confirmbox.lua +++ b/frontend/ui/widget/confirmbox.lua @@ -36,6 +36,7 @@ local UIManager = require("ui/uimanager") local VerticalGroup = require("ui/widget/verticalgroup") local VerticalSpan = require("ui/widget/verticalspan") local _ = require("gettext") +local Input = Device.input local Screen = Device.screen local ConfirmBox = InputContainer:new{ @@ -185,8 +186,8 @@ function ConfirmBox:onShow() return "ui", self[1][1].dimen end) if self.flush_events_on_show then - -- Discard queued and coming up events to avoid accidental dismissal - UIManager:discardEvents(true) + -- Discard queued and coming up input events to avoid accidental dismissal + Input:inhibitInputUntil(true) end end diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index 7ae72ff08..2edddf552 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -234,8 +234,8 @@ function InfoMessage:onShow() return "ui", self[1][1].dimen end) if self.flush_events_on_show then - -- Discard queued and coming up events to avoid accidental dismissal - UIManager:discardEvents(true) + -- Discard queued and coming up input events to avoid accidental dismissal + Input:inhibitInputUntil(true) end -- schedule us to close ourself if timeout provided if self.timeout then