|
|
|
--[[--
|
|
|
|
This module detects gestures.
|
|
|
|
|
|
|
|
Current detectable gestures:
|
|
|
|
|
|
|
|
* `touch` (user touched screen)
|
|
|
|
* `tap` (touch action detected as single tap)
|
|
|
|
* `pan`
|
|
|
|
* `hold`
|
|
|
|
* `swipe`
|
|
|
|
* `pinch`
|
|
|
|
* `spread`
|
|
|
|
* `rotate`
|
|
|
|
* `hold_pan`
|
|
|
|
* `double_tap`
|
|
|
|
* `inward_pan`
|
|
|
|
* `outward_pan`
|
|
|
|
* `pan_release`
|
|
|
|
* `hold_release`
|
|
|
|
* `two_finger_tap`
|
|
|
|
* `two_finger_pan`
|
|
|
|
* `two_finger_swipe`
|
|
|
|
* `two_finger_pan_release`
|
|
|
|
|
|
|
|
You change the state machine by feeding it touch events, i.e. calling
|
|
|
|
@{GestureDetector:feedEvent|GestureDetector:feedEvent(tev)}.
|
|
|
|
|
|
|
|
|
|
|
|
a touch event should have following format:
|
|
|
|
|
|
|
|
tev = {
|
|
|
|
slot = 1,
|
|
|
|
id = 46,
|
|
|
|
x = 0,
|
|
|
|
y = 1,
|
|
|
|
timev = time.s(123.23),
|
|
|
|
}
|
|
|
|
|
|
|
|
Don't confuse `tev` with raw evs from kernel, `tev` is built according to ev.
|
|
|
|
|
|
|
|
@{GestureDetector:feedEvent|GestureDetector:feedEvent(tev)} will return a
|
|
|
|
detection result when you feed a touch release event to it.
|
|
|
|
--]]
|
|
|
|
|
|
|
|
local Geom = require("ui/geometry")
|
|
|
|
local logger = require("logger")
|
|
|
|
local time = require("ui/time")
|
|
|
|
local util = require("util")
|
|
|
|
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- We're going to need some clockid_t constants
|
|
|
|
local ffi = require("ffi")
|
|
|
|
local C = ffi.C
|
|
|
|
require("ffi/posix_h")
|
|
|
|
|
|
|
|
-- default values (time parameters are in milliseconds (ms))
|
|
|
|
local TAP_INTERVAL_MS = 0
|
|
|
|
local DOUBLE_TAP_INTERVAL_MS = 300
|
|
|
|
local TWO_FINGER_TAP_DURATION_MS = 300
|
|
|
|
local HOLD_INTERVAL_MS = 500
|
|
|
|
local SWIPE_INTERVAL_MS = 900
|
|
|
|
|
|
|
|
local GestureDetector = {
|
|
|
|
-- must be initialized with the Input singleton class
|
|
|
|
input = nil,
|
|
|
|
-- default values (accessed for display by plugins/gestures.koplugin)
|
|
|
|
TAP_INTERVAL_MS = TAP_INTERVAL_MS,
|
|
|
|
DOUBLE_TAP_INTERVAL_MS = DOUBLE_TAP_INTERVAL_MS,
|
|
|
|
TWO_FINGER_TAP_DURATION_MS = TWO_FINGER_TAP_DURATION_MS,
|
|
|
|
HOLD_INTERVAL_MS = HOLD_INTERVAL_MS,
|
|
|
|
SWIPE_INTERVAL_MS = SWIPE_INTERVAL_MS,
|
|
|
|
-- pinch/spread direction table
|
|
|
|
DIRECTION_TABLE = {
|
|
|
|
east = "horizontal",
|
|
|
|
west = "horizontal",
|
|
|
|
north = "vertical",
|
|
|
|
south = "vertical",
|
|
|
|
northeast = "diagonal",
|
|
|
|
northwest = "diagonal",
|
|
|
|
southeast = "diagonal",
|
|
|
|
southwest = "diagonal",
|
|
|
|
},
|
|
|
|
-- states are stored in separated slots
|
|
|
|
states = {},
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
pending_hold_timer = {},
|
|
|
|
track_ids = {},
|
|
|
|
tev_stacks = {},
|
|
|
|
-- latest touch events fed in each slot
|
|
|
|
last_tevs = {},
|
|
|
|
first_tevs = {},
|
|
|
|
-- for multiswipe gestures
|
|
|
|
multiswipe_directions = {},
|
|
|
|
-- detecting status on each slot
|
|
|
|
detectings = {},
|
|
|
|
-- for single/double tap
|
|
|
|
last_taps = {},
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- for timestamp clocksource detection
|
|
|
|
clock_id = nil,
|
|
|
|
-- current values
|
|
|
|
ges_tap_interval = time.ms(G_reader_settings:readSetting("ges_tap_interval_ms") or TAP_INTERVAL_MS),
|
|
|
|
ges_double_tap_interval = time.ms(G_reader_settings:readSetting("ges_double_tap_interval_ms")
|
|
|
|
or DOUBLE_TAP_INTERVAL_MS),
|
|
|
|
ges_two_finger_tap_duration = time.ms(G_reader_settings:readSetting("ges_two_finger_tap_duration_ms")
|
|
|
|
or TWO_FINGER_TAP_DURATION_MS),
|
|
|
|
ges_hold_interval = time.ms(G_reader_settings:readSetting("ges_hold_interval_ms") or HOLD_INTERVAL_MS),
|
|
|
|
ges_swipe_interval = time.ms(G_reader_settings:readSetting("ges_swipe_interval_ms") or SWIPE_INTERVAL_MS),
|
|
|
|
}
|
|
|
|
|
|
|
|
function GestureDetector:new(o)
|
|
|
|
o = o or {}
|
|
|
|
setmetatable(o, self)
|
|
|
|
self.__index = self
|
|
|
|
if o.init then o:init() end
|
|
|
|
return o
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:init()
|
|
|
|
local scaler = self.screen:getDPI() / 167
|
|
|
|
-- distance parameters
|
|
|
|
self.TWO_FINGER_TAP_REGION = 20 * scaler
|
|
|
|
self.DOUBLE_TAP_DISTANCE = 50 * scaler
|
|
|
|
self.SINGLE_TAP_BOUNCE_DISTANCE = self.DOUBLE_TAP_DISTANCE
|
|
|
|
self.PAN_THRESHOLD = self.DOUBLE_TAP_DISTANCE
|
|
|
|
self.MULTISWIPE_THRESHOLD = self.DOUBLE_TAP_DISTANCE
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Feeds touch events to state machine.
|
|
|
|
|
|
|
|
Note that, in a single input frame, if the same slot gets multiple events, only the last one is kept.
|
|
|
|
Every slot in the input frame is consumed, and that in FIFO order (slot order based on appearance in the frame).
|
|
|
|
--]]
|
|
|
|
function GestureDetector:feedEvent(tevs)
|
|
|
|
local gestures = {}
|
|
|
|
for _, tev in ipairs(tevs) do
|
|
|
|
local slot = tev.slot
|
|
|
|
if not self.states[slot] then
|
|
|
|
self:clearState(slot) -- initialize slot state
|
|
|
|
end
|
|
|
|
local ges = self.states[slot](self, tev)
|
|
|
|
if tev.id ~= -1 then
|
|
|
|
-- NOTE: tev is actually a simple reference to Input's self.ev_slots[slot],
|
|
|
|
-- which means self.last_tevs[slot] doesn't actually point to the *previous*
|
|
|
|
-- input frame for a given slot, but always points to the *current* input frame for that slot!
|
|
|
|
-- Compare to self.first_tevs below, which does create a copy...
|
|
|
|
self.last_tevs[slot] = tev
|
|
|
|
end
|
|
|
|
if ges then
|
|
|
|
table.insert(gestures, ges)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return gestures
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:deepCopyEv(tev)
|
|
|
|
return {
|
|
|
|
x = tev.x,
|
|
|
|
y = tev.y,
|
|
|
|
id = tev.id,
|
|
|
|
slot = tev.slot,
|
|
|
|
timev = tev.timev, -- No need to make a copy of this one, tev.timev is re-assigned to a new object on every SYN_REPORT
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
|
|
tap2 is the later tap
|
|
|
|
--]]
|
|
|
|
function GestureDetector:isTapBounce(tap1, tap2, interval)
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- NOTE: If time went backwards, make the delta infinite to avoid misdetections,
|
|
|
|
-- as we can no longer compute a sensible value...
|
|
|
|
local time_diff = tap2.timev - tap1.timev
|
|
|
|
if time_diff < 0 then
|
|
|
|
time_diff = time.huge
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
return (
|
|
|
|
math.abs(tap1.x - tap2.x) < self.SINGLE_TAP_BOUNCE_DISTANCE and
|
|
|
|
math.abs(tap1.y - tap2.y) < self.SINGLE_TAP_BOUNCE_DISTANCE and
|
|
|
|
time_diff < interval
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:isDoubleTap(tap1, tap2)
|
|
|
|
local time_diff = tap2.timev - tap1.timev
|
|
|
|
if time_diff < 0 then
|
|
|
|
time_diff = time.huge
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
return (
|
|
|
|
math.abs(tap1.x - tap2.x) < self.DOUBLE_TAP_DISTANCE and
|
|
|
|
math.abs(tap1.y - tap2.y) < self.DOUBLE_TAP_DISTANCE and
|
|
|
|
time_diff < self.ges_double_tap_interval
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Takes times as input, not a tev
|
|
|
|
function GestureDetector:isHold(time1, time2)
|
|
|
|
local time_diff = time2 - time1
|
|
|
|
if time_diff < 0 then
|
|
|
|
time_diff = 0
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
-- NOTE: We cheat by not checking a distance because we're only checking that in tapState,
|
|
|
|
-- which already ensures a stationary finger, by elimination ;).
|
|
|
|
return time_diff >= self.ges_hold_interval
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:isTwoFingerTap()
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
|
|
|
|
if self.last_tevs[s1] == nil or self.last_tevs[s2] == nil then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
local x_diff0 = math.abs(self.last_tevs[s1].x - self.first_tevs[s1].x)
|
|
|
|
local x_diff1 = math.abs(self.last_tevs[s2].x - self.first_tevs[s2].x)
|
|
|
|
local y_diff0 = math.abs(self.last_tevs[s1].y - self.first_tevs[s1].y)
|
|
|
|
local y_diff1 = math.abs(self.last_tevs[s2].y - self.first_tevs[s2].y)
|
|
|
|
local time_diff0 = self.last_tevs[s1].timev - self.first_tevs[s1].timev
|
|
|
|
if time_diff0 < 0 then
|
|
|
|
time_diff0 = time.huge
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
local time_diff1 = self.last_tevs[s2].timev - self.first_tevs[s2].timev
|
|
|
|
if time_diff1 < 0 then
|
|
|
|
time_diff1 = time.huge
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
return (
|
|
|
|
x_diff0 < self.TWO_FINGER_TAP_REGION and
|
|
|
|
x_diff1 < self.TWO_FINGER_TAP_REGION and
|
|
|
|
y_diff0 < self.TWO_FINGER_TAP_REGION and
|
|
|
|
y_diff1 < self.TWO_FINGER_TAP_REGION and
|
|
|
|
time_diff0 < self.ges_two_finger_tap_duration and
|
|
|
|
time_diff1 < self.ges_two_finger_tap_duration
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Compares `last_pan` with `first_tev` in this slot.
|
|
|
|
|
|
|
|
The second boolean argument `simple` results in only four directions if true.
|
|
|
|
|
|
|
|
@return (direction, distance) pan direction and distance
|
|
|
|
--]]
|
|
|
|
function GestureDetector:getPath(slot, simple, diagonal, first_tev)
|
|
|
|
first_tev = first_tev or self.first_tevs
|
|
|
|
|
|
|
|
local x_diff = self.last_tevs[slot].x - first_tev[slot].x
|
|
|
|
local y_diff = self.last_tevs[slot].y - first_tev[slot].y
|
|
|
|
local direction = nil
|
|
|
|
local distance = math.sqrt(x_diff*x_diff + y_diff*y_diff)
|
|
|
|
if x_diff ~= 0 or y_diff ~= 0 then
|
|
|
|
local v_direction = y_diff < 0 and "north" or "south"
|
|
|
|
local h_direction = x_diff < 0 and "west" or "east"
|
|
|
|
if (not simple
|
|
|
|
and math.abs(y_diff) > 0.577*math.abs(x_diff)
|
|
|
|
and math.abs(y_diff) < 1.732*math.abs(x_diff))
|
|
|
|
or (simple and diagonal)
|
|
|
|
then
|
|
|
|
direction = v_direction..h_direction
|
|
|
|
elseif (math.abs(x_diff) > math.abs(y_diff)) then
|
|
|
|
direction = h_direction
|
|
|
|
else
|
|
|
|
direction = v_direction
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return direction, distance
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:isSwipe(slot)
|
|
|
|
if not self.first_tevs[slot] or not self.last_tevs[slot] then return end
|
|
|
|
local time_diff = self.last_tevs[slot].timev - self.first_tevs[slot].timev
|
|
|
|
if time_diff < 0 then
|
|
|
|
time_diff = time.huge
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
if time_diff < self.ges_swipe_interval then
|
|
|
|
local x_diff = self.last_tevs[slot].x - self.first_tevs[slot].x
|
|
|
|
local y_diff = self.last_tevs[slot].y - self.first_tevs[slot].y
|
|
|
|
if x_diff ~= 0 or y_diff ~= 0 then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:getRotate(orig_point, start_point, end_point)
|
|
|
|
local a = orig_point:distance(start_point)
|
|
|
|
local b = orig_point:distance(end_point)
|
|
|
|
local c = start_point:distance(end_point)
|
|
|
|
return math.acos((a*a + b*b - c*c)/(2*a*b))*180/math.pi
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
|
|
Warning! this method won't update self.state, you need to do it
|
|
|
|
in each state method!
|
|
|
|
--]]
|
|
|
|
function GestureDetector:switchState(state_new, tev, param)
|
|
|
|
--- @todo Do we need to check whether state is valid? (houqp)
|
|
|
|
return self[state_new](self, tev, param)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:clearState(slot)
|
|
|
|
self.states[slot] = self.initialState
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
self.pending_hold_timer[slot] = nil
|
|
|
|
self.detectings[slot] = false
|
|
|
|
self.first_tevs[slot] = nil
|
|
|
|
self.last_tevs[slot] = nil
|
|
|
|
self.multiswipe_directions = {}
|
|
|
|
self.multiswipe_type = nil
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
|
|
|
|
-- Also clear any pending hold callbacks on that slot.
|
|
|
|
-- (single taps call this, so we can't clear double_tap callbacks without being caught in an obvious catch-22 ;)).
|
|
|
|
self.input:clearTimeout(slot, "hold")
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:clearStates()
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
for k, _ in pairs(self.states) do
|
|
|
|
self:clearState(k)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:initialState(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
if tev.id then
|
|
|
|
-- an event ends
|
|
|
|
if tev.id == -1 then
|
|
|
|
self.detectings[slot] = false
|
|
|
|
else
|
|
|
|
self.track_ids[slot] = tev.id
|
|
|
|
if tev.x and tev.y then
|
|
|
|
-- user starts a new touch motion
|
|
|
|
if not self.detectings[slot] then
|
|
|
|
self.detectings[slot] = true
|
|
|
|
-- NOTE: We can't use a simple reference, because tev is actually Input's self.ev_slots[slot],
|
|
|
|
-- and *that* is a fixed reference for a given slot!
|
|
|
|
-- Here, we really want to rememver the *first* tev, so, make a copy of it.
|
|
|
|
self.first_tevs[slot] = self:deepCopyEv(tev)
|
|
|
|
-- default to tap state
|
|
|
|
return self:switchState("tapState", tev)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
--[[--
|
|
|
|
Attempts to figure out which clock source tap events are using...
|
|
|
|
]]
|
|
|
|
function GestureDetector:probeClockSource(timev)
|
|
|
|
-- We'll check if that timestamp is +/- 2.5s away from the three potential clock sources supported by evdev.
|
|
|
|
-- We have bigger issues than this if we're parsing events more than 3s late ;).
|
|
|
|
local threshold = time.s(2) + time.ms(500)
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
|
|
|
|
-- Start w/ REALTIME, because it's the easiest to detect ;).
|
|
|
|
local realtime = time.realtime_coarse()
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- clock-threshold <= timev <= clock+threshold
|
|
|
|
if timev >= realtime - threshold and timev <= realtime + threshold then
|
|
|
|
self.clock_id = C.CLOCK_REALTIME
|
|
|
|
logger.dbg("GestureDetector:probeClockSource: Touch event timestamps appear to use CLOCK_REALTIME")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Then MONOTONIC, as it's (hopefully) more common than BOOTTIME (and also guaranteed to be an usable clock source)
|
|
|
|
local monotonic = time.monotonic_coarse()
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
if timev >= monotonic - threshold and timev <= monotonic + threshold then
|
|
|
|
self.clock_id = C.CLOCK_MONOTONIC
|
|
|
|
logger.dbg("GestureDetector:probeClockSource: Touch event timestamps appear to use CLOCK_MONOTONIC")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Finally, BOOTTIME
|
|
|
|
local boottime = time.boottime()
|
|
|
|
-- NOTE: It was implemented in Linux 2.6.39, so, reject 0, which would mean it's unsupported...
|
|
|
|
if not boottime == 0 and timev >= boottime - threshold and timev <= boottime + threshold then
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
self.clock_id = C.CLOCK_BOOTTIME
|
|
|
|
logger.dbg("GestureDetector:probeClockSource: Touch event timestamps appear to use CLOCK_BOOTTIME")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If we're here, the detection was inconclusive :/
|
|
|
|
self.clock_id = -1
|
|
|
|
logger.dbg("GestureDetector:probeClockSource: Touch event clock source detection was inconclusive")
|
|
|
|
-- Print all all the gory details in debug mode when this happens...
|
|
|
|
logger.dbg("Input frame :", time.format_time(timev))
|
|
|
|
logger.dbg("CLOCK_REALTIME :", time.format_time(realtime))
|
|
|
|
logger.dbg("CLOCK_MONOTONIC:", time.format_time(monotonic))
|
|
|
|
logger.dbg("CLOCK_BOOTTIME :", time.format_time(boottime))
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:getClockSource()
|
|
|
|
return self.clock_id
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:resetClockSource()
|
|
|
|
self.clock_id = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Handles both single and double tap.
|
|
|
|
--]]
|
|
|
|
function GestureDetector:tapState(tev)
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- Attempt to detect the clock source for these events (we reset it on suspend to discriminate MONOTONIC from BOOTTIME).
|
|
|
|
if not self.clock_id then
|
|
|
|
self:probeClockSource(tev.timev)
|
|
|
|
end
|
|
|
|
|
|
|
|
local slot = tev.slot
|
|
|
|
logger.dbg("slot", slot, "in tap state...")
|
|
|
|
if tev.id == -1 then
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
-- end of tap event
|
|
|
|
if self.detectings[s1] and self.detectings[s2] then
|
|
|
|
if self:isTwoFingerTap() then
|
|
|
|
local pos0 = Geom:new{
|
|
|
|
x = self.last_tevs[s1].x,
|
|
|
|
y = self.last_tevs[s1].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local pos1 = Geom:new{
|
|
|
|
x = self.last_tevs[s2].x,
|
|
|
|
y = self.last_tevs[s2].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local tap_span = pos0:distance(pos1)
|
|
|
|
logger.dbg("two-finger tap detected with span", tap_span)
|
|
|
|
self:clearState(s1)
|
|
|
|
self:clearState(s2)
|
|
|
|
return {
|
|
|
|
ges = "two_finger_tap",
|
|
|
|
pos = pos0:midpoint(pos1),
|
|
|
|
span = tap_span,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
else
|
|
|
|
self:clearState(slot)
|
|
|
|
end
|
|
|
|
elseif self.last_tevs[slot] ~= nil then
|
|
|
|
-- Normal single tap seems to always go thru here
|
|
|
|
-- (the next 'else' might be there for edge cases)
|
|
|
|
return self:handleDoubleTap(tev)
|
|
|
|
else
|
|
|
|
-- last tev in this slot is cleared by last two finger tap
|
|
|
|
self:clearState(slot)
|
|
|
|
return {
|
|
|
|
ges = "tap",
|
|
|
|
pos = Geom:new{
|
|
|
|
x = tev.x,
|
|
|
|
y = tev.y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
},
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return self:handleNonTap(tev)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handleDoubleTap(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
local ges_ev = {
|
|
|
|
-- default to single tap
|
|
|
|
ges = "tap",
|
|
|
|
pos = Geom:new{
|
|
|
|
x = self.last_tevs[slot].x,
|
|
|
|
y = self.last_tevs[slot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
},
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
-- cur_tap is used for double tap detection
|
|
|
|
local cur_tap = {
|
|
|
|
x = tev.x,
|
|
|
|
y = tev.y,
|
|
|
|
timev = tev.timev,
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Tap interval / bounce detection may be tweaked by widget (i.e. VirtualKeyboard)
|
|
|
|
local tap_interval = self.input.tap_interval_override or self.ges_tap_interval
|
|
|
|
-- We do tap bounce detection even when double tap is enabled (so, double tap
|
|
|
|
-- is triggered when: ges_tap_interval <= delay < ges_double_tap_interval)
|
|
|
|
if tap_interval ~= 0 and self.last_taps[slot] ~= nil and self:isTapBounce(self.last_taps[slot], cur_tap, tap_interval) then
|
|
|
|
logger.dbg("tap bounce detected in slot", slot, ": ignored")
|
|
|
|
-- Simply ignore it, and clear state as this is the end of a touch event
|
|
|
|
-- (this doesn't clear self.last_taps[slot], so a 3rd tap can be detected
|
|
|
|
-- as a double tap)
|
|
|
|
self:clearState(slot)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if not self.input.disable_double_tap and self.last_taps[slot] ~= nil and
|
|
|
|
self:isDoubleTap(self.last_taps[slot], cur_tap) then
|
|
|
|
-- it is a double tap
|
|
|
|
self:clearState(slot)
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
self.input:clearTimeout(slot, "double_tap")
|
|
|
|
ges_ev.ges = "double_tap"
|
|
|
|
self.last_taps[slot] = nil
|
|
|
|
logger.dbg("double tap detected in slot", slot)
|
|
|
|
return ges_ev
|
|
|
|
end
|
|
|
|
|
|
|
|
-- set current tap to last tap
|
|
|
|
self.last_taps[slot] = cur_tap
|
|
|
|
|
|
|
|
if self.input.disable_double_tap then
|
|
|
|
-- We can send the event immediately (no need for the
|
|
|
|
-- timer stuff needed for double tap support)
|
|
|
|
logger.dbg("single tap detected in slot", slot, ges_ev.pos)
|
|
|
|
self:clearState(slot)
|
|
|
|
return ges_ev
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Double tap enabled: we can't send this single tap immediately as it
|
|
|
|
-- may be the start of a double tap. We'll send it as a single tap after
|
|
|
|
-- a timer if no second tap happened in the double tap delay.
|
|
|
|
logger.dbg("set up single/double tap timer")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- setTimeout will handle computing the deadline in the least lossy way possible given the platform.
|
|
|
|
self.input:setTimeout(slot, "double_tap", function()
|
|
|
|
logger.dbg("in single/double tap timer, single tap:", self.last_taps[slot] ~= nil)
|
|
|
|
-- double tap will set last_tap to nil so if it is not, then
|
|
|
|
-- user has not double-tap'ed: it's a single tap
|
|
|
|
if self.last_taps[slot] ~= nil then
|
|
|
|
self.last_taps[slot] = nil
|
|
|
|
-- we are using closure here
|
|
|
|
logger.dbg("single tap detected in slot", slot, ges_ev.pos)
|
|
|
|
return ges_ev
|
|
|
|
end
|
|
|
|
end, tev.timev, self.ges_double_tap_interval)
|
|
|
|
-- we are already at the end of touch event
|
|
|
|
-- so reset the state
|
|
|
|
self:clearState(slot)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handleNonTap(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
if self.states[slot] ~= self.tapState then
|
|
|
|
-- switched from other state, probably from initialState
|
|
|
|
-- we return nil in this case
|
|
|
|
self.states[slot] = self.tapState
|
|
|
|
logger.dbg("set up hold timer")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- Invalidate previous hold timers on that slot so that the following setTimeout will only react to *this* tapState.
|
|
|
|
self.input:clearTimeout(slot, "hold")
|
|
|
|
self.pending_hold_timer[slot] = true
|
|
|
|
self.input:setTimeout(slot, "hold", function()
|
|
|
|
-- If the pending_hold_timer we set on our first switch to tapState on this slot (e.g., first finger down event),
|
|
|
|
-- back when the timer was setup, is still relevant (e.g., the slot wasn't run through clearState by a finger up gesture),
|
|
|
|
-- then check that we're still in a stationary finger down state (e.g., tapState).
|
|
|
|
if self.pending_hold_timer[slot] and self.states[slot] == self.tapState then
|
|
|
|
-- That means we can switch to hold
|
|
|
|
logger.dbg("hold gesture detected in slot", slot)
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
self.pending_hold_timer[slot] = nil
|
|
|
|
return self:switchState("holdState", tev, true)
|
|
|
|
end
|
|
|
|
end, tev.timev, self.ges_hold_interval)
|
|
|
|
return {
|
|
|
|
ges = "touch",
|
|
|
|
pos = Geom:new{
|
|
|
|
x = tev.x,
|
|
|
|
y = tev.y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
},
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
else
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- We're still inside a stream of input events, see if we need to switch to other states.
|
|
|
|
if (tev.x and math.abs(tev.x - self.first_tevs[slot].x) >= self.PAN_THRESHOLD) or
|
|
|
|
(tev.y and math.abs(tev.y - self.first_tevs[slot].y) >= self.PAN_THRESHOLD) then
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- If user's finger moved far enough on the X or Y axes, switch to pan state.
|
|
|
|
return self:switchState("panState", tev)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:panState(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
logger.dbg("slot", slot, "in pan state...")
|
|
|
|
if tev.id == -1 then
|
|
|
|
-- end of pan, signal swipe gesture if necessary
|
|
|
|
if self:isSwipe(slot) then
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
if self.detectings[s1] and self.detectings[s2] then
|
|
|
|
local ges_ev = self:handleTwoFingerPan(tev)
|
|
|
|
self:clearState(s1)
|
|
|
|
self:clearState(s2)
|
|
|
|
if ges_ev then
|
|
|
|
if ges_ev.ges == "two_finger_pan" then
|
|
|
|
ges_ev.ges = "two_finger_swipe"
|
|
|
|
elseif ges_ev.ges == "inward_pan" then
|
|
|
|
ges_ev.ges = "pinch"
|
|
|
|
elseif ges_ev.ges == "outward_pan" then
|
|
|
|
ges_ev.ges = "spread"
|
|
|
|
end
|
|
|
|
logger.dbg(ges_ev.ges, ges_ev.direction, ges_ev.distance, "detected")
|
|
|
|
end
|
|
|
|
return ges_ev
|
|
|
|
else
|
|
|
|
return self:handleSwipe(tev)
|
|
|
|
end
|
|
|
|
else -- if end of pan is not swipe then it must be pan release.
|
|
|
|
return self:handlePanRelease(tev)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if self.states[slot] ~= self.panState then
|
|
|
|
self.states[slot] = self.panState
|
|
|
|
end
|
|
|
|
return self:handlePan(tev)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handleSwipe(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
local swipe_direction, swipe_distance = self:getPath(slot)
|
|
|
|
local start_pos = Geom:new{
|
|
|
|
x = self.first_tevs[slot].x,
|
|
|
|
y = self.first_tevs[slot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local ges = "swipe"
|
|
|
|
local multiswipe_directions
|
|
|
|
|
|
|
|
if #self.multiswipe_directions > 1 then
|
|
|
|
ges = "multiswipe"
|
|
|
|
multiswipe_directions = ""
|
|
|
|
for k, v in ipairs(self.multiswipe_directions) do
|
|
|
|
local sep = ""
|
|
|
|
if k > 1 then
|
|
|
|
sep = " "
|
|
|
|
end
|
|
|
|
multiswipe_directions = multiswipe_directions .. sep .. v[1]
|
|
|
|
end
|
|
|
|
logger.dbg("multiswipe", multiswipe_directions)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- @todo dirty hack for some weird devices, replace it with better solution
|
|
|
|
if swipe_direction == "west" and DCHANGE_WEST_SWIPE_TO_EAST then
|
|
|
|
swipe_direction = "east"
|
|
|
|
elseif swipe_direction == "east" and DCHANGE_EAST_SWIPE_TO_WEST then
|
|
|
|
swipe_direction = "west"
|
|
|
|
end
|
|
|
|
logger.dbg("swipe", swipe_direction, swipe_distance, "detected in slot", slot)
|
|
|
|
self:clearState(slot)
|
|
|
|
return {
|
|
|
|
ges = ges,
|
|
|
|
-- use first pan tev coordination as swipe start point
|
|
|
|
pos = start_pos,
|
|
|
|
direction = swipe_direction,
|
|
|
|
multiswipe_directions = multiswipe_directions,
|
|
|
|
distance = swipe_distance,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handlePan(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
if self.detectings[s1] and self.detectings[s2] then
|
|
|
|
return self:handleTwoFingerPan(tev)
|
|
|
|
else
|
|
|
|
local pan_direction, pan_distance = self:getPath(slot)
|
|
|
|
local pan_ev = {
|
|
|
|
ges = "pan",
|
|
|
|
relative = {
|
|
|
|
-- default to pan 0
|
|
|
|
x = 0,
|
|
|
|
y = 0,
|
|
|
|
},
|
|
|
|
pos = nil,
|
|
|
|
direction = pan_direction,
|
|
|
|
distance = pan_distance,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
|
|
|
|
-- regular pan
|
|
|
|
pan_ev.relative.x = tev.x - self.first_tevs[slot].x
|
|
|
|
pan_ev.relative.y = tev.y - self.first_tevs[slot].y
|
|
|
|
|
|
|
|
pan_ev.pos = Geom:new{
|
|
|
|
x = self.last_tevs[slot].x,
|
|
|
|
y = self.last_tevs[slot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
local msd_cnt = #self.multiswipe_directions
|
|
|
|
local msd_direction_prev = (msd_cnt > 0) and self.multiswipe_directions[msd_cnt][1] or ""
|
|
|
|
local prev_ms_ev, fake_first_tev
|
|
|
|
|
|
|
|
if msd_cnt == 0 then
|
|
|
|
-- determine whether to initiate a straight or diagonal multiswipe
|
|
|
|
self.multiswipe_type = "straight"
|
|
|
|
if pan_direction ~= "north" and pan_direction ~= "south"
|
|
|
|
and pan_direction ~= "east" and pan_direction ~= "west" then
|
|
|
|
self.multiswipe_type = "diagonal"
|
|
|
|
end
|
|
|
|
-- recompute a more accurate direction and distance in a multiswipe context
|
|
|
|
elseif msd_cnt > 0 then
|
|
|
|
prev_ms_ev = self.multiswipe_directions[msd_cnt][2]
|
|
|
|
fake_first_tev = {
|
|
|
|
[slot] = {
|
|
|
|
["x"] = prev_ms_ev.pos.x,
|
|
|
|
["y"] = prev_ms_ev.pos.y,
|
|
|
|
["slot"] = slot,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- the first time fake_first_tev is nil, so self.first_tevs is automatically used instead
|
|
|
|
local msd_direction, msd_distance
|
|
|
|
if self.multiswipe_type == "straight" then
|
|
|
|
msd_direction, msd_distance = self:getPath(slot, true, false, fake_first_tev)
|
|
|
|
else
|
|
|
|
msd_direction, msd_distance = self:getPath(slot, true, true, fake_first_tev)
|
|
|
|
end
|
|
|
|
|
|
|
|
if msd_distance > self.MULTISWIPE_THRESHOLD then
|
|
|
|
local pan_ev_multiswipe = pan_ev
|
|
|
|
-- store a copy of pan_ev without rotation adjustment
|
|
|
|
-- for multiswipe calculations when rotated
|
|
|
|
if self.screen:getTouchRotation() > self.screen.ORIENTATION_PORTRAIT then
|
|
|
|
pan_ev_multiswipe = util.tableDeepCopy(pan_ev)
|
|
|
|
end
|
|
|
|
if msd_direction ~= msd_direction_prev then
|
|
|
|
self.multiswipe_directions[msd_cnt+1] = {
|
|
|
|
[1] = msd_direction,
|
|
|
|
[2] = pan_ev_multiswipe,
|
|
|
|
}
|
|
|
|
-- update ongoing swipe direction to the new maximum
|
|
|
|
else
|
|
|
|
self.multiswipe_directions[msd_cnt] = {
|
|
|
|
[1] = msd_direction,
|
|
|
|
[2] = pan_ev_multiswipe,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return pan_ev
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handleTwoFingerPan(tev)
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
-- triggering slot
|
|
|
|
local tslot = tev.slot
|
|
|
|
-- reference slot
|
|
|
|
local rslot = tslot == s2 and s1 or s2
|
|
|
|
local tpan_dir, tpan_dis = self:getPath(tslot)
|
|
|
|
local tstart_pos = Geom:new{
|
|
|
|
x = self.first_tevs[tslot].x,
|
|
|
|
y = self.first_tevs[tslot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local tend_pos = Geom:new{
|
|
|
|
x = self.last_tevs[tslot].x,
|
|
|
|
y = self.last_tevs[tslot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local rstart_pos = Geom:new{
|
|
|
|
x = self.first_tevs[rslot].x,
|
|
|
|
y = self.first_tevs[rslot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
if self.states[rslot] == self.panState then
|
|
|
|
local rpan_dir, rpan_dis = self:getPath(rslot)
|
|
|
|
local rend_pos = Geom:new{
|
|
|
|
x = self.last_tevs[rslot].x,
|
|
|
|
y = self.last_tevs[rslot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local start_distance = tstart_pos:distance(rstart_pos)
|
|
|
|
local end_distance = tend_pos:distance(rend_pos)
|
|
|
|
local ges_ev = {
|
|
|
|
ges = "two_finger_pan",
|
|
|
|
-- use midpoint of tstart and rstart as swipe start point
|
|
|
|
pos = tstart_pos:midpoint(rstart_pos),
|
|
|
|
distance = tpan_dis + rpan_dis,
|
|
|
|
direction = tpan_dir,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
if tpan_dir ~= rpan_dir then
|
|
|
|
if start_distance > end_distance then
|
|
|
|
ges_ev.ges = "inward_pan"
|
|
|
|
else
|
|
|
|
ges_ev.ges = "outward_pan"
|
|
|
|
end
|
|
|
|
ges_ev.direction = self.DIRECTION_TABLE[tpan_dir]
|
|
|
|
end
|
|
|
|
logger.dbg(ges_ev.ges, ges_ev.direction, ges_ev.distance, "detected")
|
|
|
|
return ges_ev
|
|
|
|
elseif self.states[rslot] == self.holdState then
|
|
|
|
local angle = self:getRotate(rstart_pos, tstart_pos, tend_pos)
|
|
|
|
logger.dbg("rotate", angle, "detected")
|
|
|
|
return {
|
|
|
|
ges = "rotate",
|
|
|
|
pos = rstart_pos,
|
|
|
|
angle = angle,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:handlePanRelease(tev)
|
|
|
|
local slot = tev.slot
|
|
|
|
local release_pos = Geom:new{
|
|
|
|
x = self.last_tevs[slot].x,
|
|
|
|
y = self.last_tevs[slot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
local pan_ev = {
|
|
|
|
ges = "pan_release",
|
|
|
|
pos = release_pos,
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
local s1 = self.input.main_finger_slot
|
|
|
|
local s2 = self.input.main_finger_slot + 1
|
|
|
|
if self.detectings[s1] and self.detectings[s2] then
|
|
|
|
logger.dbg("two finger pan release detected")
|
|
|
|
pan_ev.ges = "two_finger_pan_release"
|
|
|
|
self:clearState(s1)
|
|
|
|
self:clearState(s2)
|
|
|
|
else
|
|
|
|
logger.dbg("pan release detected in slot", slot)
|
|
|
|
self:clearState(slot)
|
|
|
|
end
|
|
|
|
return pan_ev
|
|
|
|
end
|
|
|
|
|
|
|
|
function GestureDetector:holdState(tev, hold)
|
|
|
|
local slot = tev.slot
|
|
|
|
logger.dbg("slot", slot, "in hold state...")
|
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
4 years ago
|
|
|
-- When we switch to hold state, we pass an additional boolean param "hold".
|
|
|
|
if tev.id ~= -1 and hold and self.last_tevs[slot].x and self.last_tevs[slot].y then
|
|
|
|
self.states[slot] = self.holdState
|
|
|
|
return {
|
|
|
|
ges = "hold",
|
|
|
|
pos = Geom:new{
|
|
|
|
x = self.last_tevs[slot].x,
|
|
|
|
y = self.last_tevs[slot].y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
},
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
elseif tev.id == -1 and self.last_tevs[slot] ~= nil then
|
|
|
|
-- end of hold, signal hold release
|
|
|
|
logger.dbg("hold_release detected in slot", slot)
|
|
|
|
local last_x = self.last_tevs[slot].x
|
|
|
|
local last_y = self.last_tevs[slot].y
|
|
|
|
self:clearState(slot)
|
|
|
|
return {
|
|
|
|
ges = "hold_release",
|
|
|
|
pos = Geom:new{
|
|
|
|
x = last_x,
|
|
|
|
y = last_y,
|
|
|
|
w = 0, h = 0,
|
|
|
|
},
|
|
|
|
time = tev.timev,
|
|
|
|
}
|
|
|
|
elseif (tev.x and math.abs(tev.x - self.first_tevs[slot].x) >= self.PAN_THRESHOLD) or
|
|
|
|
(tev.y and math.abs(tev.y - self.first_tevs[slot].y) >= self.PAN_THRESHOLD) then
|
|
|
|
local ges_ev = self:handlePan(tev)
|
|
|
|
if ges_ev ~= nil then ges_ev.ges = "hold_pan" end
|
|
|
|
return ges_ev
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local ges_coordinate_translation_270 = {
|
|
|
|
north = "west",
|
|
|
|
south = "east",
|
|
|
|
east = "north",
|
|
|
|
west = "south",
|
|
|
|
northeast = "northwest",
|
|
|
|
northwest = "southwest",
|
|
|
|
southeast = "northeast",
|
|
|
|
southwest = "southeast",
|
|
|
|
}
|
|
|
|
local ges_coordinate_translation_180 = {
|
|
|
|
north = "south",
|
|
|
|
south = "north",
|
|
|
|
east = "west",
|
|
|
|
west = "east",
|
|
|
|
northeast = "southwest",
|
|
|
|
northwest = "southeast",
|
|
|
|
southeast = "northwest",
|
|
|
|
southwest = "northeast",
|
|
|
|
}
|
|
|
|
local ges_coordinate_translation_90 = {
|
|
|
|
north = "east",
|
|
|
|
south = "west",
|
|
|
|
east = "south",
|
|
|
|
west = "north",
|
|
|
|
northeast = "southeast",
|
|
|
|
northwest = "northeast",
|
|
|
|
southeast = "southwest",
|
|
|
|
southwest = "northwest",
|
|
|
|
}
|
|
|
|
local function translateGesDirCoordinate(direction, translation_table)
|
|
|
|
return translation_table[direction]
|
|
|
|
end
|
|
|
|
local function translateMultiswipeGesDirCoordinate(multiswipe_directions, translation_table)
|
|
|
|
return multiswipe_directions:gsub("%S+", translation_table)
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Changes gesture's `x` and `y` coordinates according to screen view mode.
|
|
|
|
|
|
|
|
@param ges gesture that you want to adjust
|
|
|
|
@return adjusted gesture.
|
|
|
|
--]]
|
|
|
|
function GestureDetector:adjustGesCoordinate(ges)
|
|
|
|
local mode = self.screen:getTouchRotation()
|
|
|
|
if mode == self.screen.ORIENTATION_LANDSCAPE then
|
|
|
|
-- in landscape mode rotated 90
|
|
|
|
if ges.pos then
|
|
|
|
ges.pos.x, ges.pos.y = (self.screen:getWidth() - ges.pos.y), (ges.pos.x)
|
|
|
|
end
|
|
|
|
if ges.ges == "swipe" or ges.ges == "pan"
|
|
|
|
or ges.ges == "multiswipe"
|
|
|
|
or ges.ges == "two_finger_swipe"
|
|
|
|
or ges.ges == "two_finger_pan"
|
|
|
|
then
|
|
|
|
ges.direction = translateGesDirCoordinate(ges.direction, ges_coordinate_translation_90)
|
|
|
|
if ges.ges == "multiswipe" then
|
|
|
|
ges.multiswipe_directions = translateMultiswipeGesDirCoordinate(ges.multiswipe_directions, ges_coordinate_translation_90)
|
|
|
|
end
|
|
|
|
if ges.relative then
|
|
|
|
ges.relative.x, ges.relative.y = -ges.relative.y, ges.relative.x
|
|
|
|
end
|
|
|
|
elseif ges.ges == "pinch" or ges.ges == "spread"
|
|
|
|
or ges.ges == "inward_pan"
|
|
|
|
or ges.ges == "outward_pan" then
|
|
|
|
if ges.direction == "horizontal" then
|
|
|
|
ges.direction = "vertical"
|
|
|
|
elseif ges.direction == "vertical" then
|
|
|
|
ges.direction = "horizontal"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif mode == self.screen.ORIENTATION_LANDSCAPE_ROTATED then
|
|
|
|
-- in landscape mode rotated 270
|
|
|
|
if ges.pos then
|
|
|
|
ges.pos.x, ges.pos.y = (ges.pos.y), (self.screen:getHeight() - ges.pos.x)
|
|
|
|
end
|
|
|
|
if ges.ges == "swipe" or ges.ges == "pan"
|
|
|
|
or ges.ges == "multiswipe"
|
|
|
|
or ges.ges == "two_finger_swipe"
|
|
|
|
or ges.ges == "two_finger_pan"
|
|
|
|
then
|
|
|
|
ges.direction = translateGesDirCoordinate(ges.direction, ges_coordinate_translation_270)
|
|
|
|
if ges.ges == "multiswipe" then
|
|
|
|
ges.multiswipe_directions = translateMultiswipeGesDirCoordinate(ges.multiswipe_directions, ges_coordinate_translation_270)
|
|
|
|
end
|
|
|
|
if ges.relative then
|
|
|
|
ges.relative.x, ges.relative.y = ges.relative.y, -ges.relative.x
|
|
|
|
end
|
|
|
|
elseif ges.ges == "pinch" or ges.ges == "spread"
|
|
|
|
or ges.ges == "inward_pan"
|
|
|
|
or ges.ges == "outward_pan" then
|
|
|
|
if ges.direction == "horizontal" then
|
|
|
|
ges.direction = "vertical"
|
|
|
|
elseif ges.direction == "vertical" then
|
|
|
|
ges.direction = "horizontal"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif mode == self.screen.ORIENTATION_PORTRAIT_ROTATED then
|
|
|
|
-- in portrait mode rotated 180
|
|
|
|
if ges.pos then
|
|
|
|
ges.pos.x, ges.pos.y = (self.screen:getWidth() - ges.pos.x), (self.screen:getHeight() - ges.pos.y)
|
|
|
|
end
|
|
|
|
if ges.ges == "swipe" or ges.ges == "pan"
|
|
|
|
or ges.ges == "multiswipe"
|
|
|
|
or ges.ges == "two_finger_swipe"
|
|
|
|
or ges.ges == "two_finger_pan"
|
|
|
|
then
|
|
|
|
ges.direction = translateGesDirCoordinate(ges.direction, ges_coordinate_translation_180)
|
|
|
|
if ges.ges == "multiswipe" then
|
|
|
|
ges.multiswipe_directions = translateMultiswipeGesDirCoordinate(ges.multiswipe_directions, ges_coordinate_translation_180)
|
|
|
|
end
|
|
|
|
if ges.relative then
|
|
|
|
ges.relative.x, ges.relative.y = -ges.relative.x, -ges.relative.y
|
|
|
|
end
|
|
|
|
elseif ges.ges == "pinch" or ges.ges == "spread"
|
|
|
|
or ges.ges == "inward_pan"
|
|
|
|
or ges.ges == "outward_pan" then
|
|
|
|
if ges.direction == "horizontal" then
|
|
|
|
ges.direction = "horizontal"
|
|
|
|
elseif ges.direction == "vertical" then
|
|
|
|
ges.direction = "vertical"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
logger.dbg("adjusted ges:", ges.ges, ges.multiswipe_directions or ges.direction)
|
|
|
|
return ges
|
|
|
|
end
|
|
|
|
|
|
|
|
return GestureDetector
|