GestureDetector: add Tap interval setting, to avoid bounces

Also fix info_text not displayed, and add more
descriptive ones.
reviewable/pr6804/r1
poire-z 4 years ago
parent d9b658034d
commit b90f6db876

@ -47,22 +47,31 @@ local TimeVal = require("ui/timeval")
local logger = require("logger")
local util = require("util")
-- all the time parameters are in us
local ges_double_tap_interval = G_reader_settings:readSetting("ges_double_tap_interval") or 300 * 1000
local ges_two_finger_tap_duration = G_reader_settings:readSetting("ges_two_finger_tap_duration") or 300 * 1000
local ges_hold_interval = G_reader_settings:readSetting("ges_hold_interval") or 500 * 1000
local ges_pan_delayed_interval = G_reader_settings:readSetting("ges_pan_delayed_interval") or 500 * 1000
local ges_swipe_interval = G_reader_settings:readSetting("ges_swipe_interval") or 900 * 1000
-- default values (all the time parameters are in microseconds)
local TAP_INTERVAL = 0 * 1000
local DOUBLE_TAP_INTERVAL = 300 * 1000
local TWO_FINGER_TAP_DURATION = 300 * 1000
local HOLD_INTERVAL = 500 * 1000
local PAN_DELAYED_INTERVAL = 500 * 1000
local SWIPE_INTERVAL = 900 * 1000
-- current values
local ges_tap_interval = G_reader_settings:readSetting("ges_tap_interval") or TAP_INTERVAL
local ges_double_tap_interval = G_reader_settings:readSetting("ges_double_tap_interval") or DOUBLE_TAP_INTERVAL
local ges_two_finger_tap_duration = G_reader_settings:readSetting("ges_two_finger_tap_duration") or TWO_FINGER_TAP_DURATION
local ges_hold_interval = G_reader_settings:readSetting("ges_hold_interval") or HOLD_INTERVAL
local ges_pan_delayed_interval = G_reader_settings:readSetting("ges_pan_delayed_interval") or PAN_DELAYED_INTERVAL
local ges_swipe_interval = G_reader_settings:readSetting("ges_swipe_interval") or SWIPE_INTERVAL
local GestureDetector = {
-- must be initialized with the Input singleton class
input = nil,
-- default values (all the time parameters are in us)
DOUBLE_TAP_INTERVAL = 300 * 1000,
TWO_FINGER_TAP_DURATION = 300 * 1000,
HOLD_INTERVAL = 500 * 1000,
PAN_DELAYED_INTERVAL = 500 * 1000,
SWIPE_INTERVAL = 900 * 1000,
-- default values (accessed for display by plugins/gestures.koplugin)
TAP_INTERVAL = TAP_INTERVAL,
DOUBLE_TAP_INTERVAL = DOUBLE_TAP_INTERVAL,
TWO_FINGER_TAP_DURATION = TWO_FINGER_TAP_DURATION,
HOLD_INTERVAL = HOLD_INTERVAL,
PAN_DELAYED_INTERVAL = PAN_DELAYED_INTERVAL,
SWIPE_INTERVAL = SWIPE_INTERVAL,
-- pinch/spread direction table
DIRECTION_TABLE = {
east = "horizontal",
@ -103,6 +112,7 @@ function GestureDetector:init()
-- 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
@ -144,6 +154,15 @@ end
--[[
tap2 is the later tap
--]]
function GestureDetector:isTapBounce(tap1, tap2)
local tv_diff = tap2.timev - tap1.timev
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
(tv_diff.sec == 0 and (tv_diff.usec) < ges_tap_interval)
)
end
function GestureDetector:isDoubleTap(tap1, tap2)
local tv_diff = tap2.timev - tap1.timev
return (
@ -244,7 +263,9 @@ function GestureDetector:clearState(slot)
end
function GestureDetector:setNewInterval(type, interval)
if type == "ges_double_tap_interval" then
if type == "ges_tap_interval" then
ges_tap_interval = interval
elseif type == "ges_double_tap_interval" then
ges_double_tap_interval = interval
elseif type == "ges_two_finger_tap_duration" then
ges_two_finger_tap_duration = interval
@ -258,7 +279,9 @@ function GestureDetector:setNewInterval(type, interval)
end
function GestureDetector:getInterval(type)
if type == "ges_double_tap_interval" then
if type == "ges_tap_interval" then
return ges_tap_interval
elseif type == "ges_double_tap_interval" then
return ges_double_tap_interval
elseif type == "ges_two_finger_tap_duration" then
return ges_two_finger_tap_duration
@ -330,6 +353,8 @@ function GestureDetector:tapState(tev)
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
@ -368,6 +393,17 @@ function GestureDetector:handleDoubleTap(tev)
timev = tev.timev,
}
-- 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 ges_tap_interval > 0 and self.last_taps[slot] ~= nil and self:isTapBounce(self.last_taps[slot], cur_tap) 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
@ -381,16 +417,27 @@ function GestureDetector:handleDoubleTap(tev)
-- set current tap to last tap
self.last_taps[slot] = cur_tap
logger.dbg("set up tap timer")
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")
-- deadline should be calculated by adding current tap time and the interval
local deadline = cur_tap.timev + TimeVal:new{
sec = 0,
usec = not self.input.disable_double_tap and ges_double_tap_interval or 0,
}
self.input:setTimeout(function()
logger.dbg("in tap timer", self.last_taps[slot] ~= nil)
logger.dbg("in single/double tap timer", self.last_taps[slot] ~= nil)
-- double tap will set last_tap to nil so if it is not, then
-- user must only tapped once
-- 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

@ -437,6 +437,7 @@ function Gestures:addIntervals(menu_items)
sub_item_table = {
{
text = _("Text selection rate"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local current_value = G_reader_settings:readSetting("hold_pan_rate")
@ -444,18 +445,19 @@ function Gestures:addIntervals(menu_items)
current_value = Screen.low_pan_rate and 5.0 or 30.0
end
local items = SpinWidget:new{
text = T(_([[
title_text = _("Text selection rate"),
info_text = T(_([[
The rate is how often screen will be refreshed per second while selecting text.
Higher values mean faster screen updates, but also use more CPU.
Default value: %1]]), Screen.low_pan_rate and 5.0 or 30.0),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = current_value,
value_min = 1.0,
value_max = 60.0,
value_step = 1,
value_hold_step = 15,
ok_text = _("Set rate"),
title_text = _("Text selection rate"),
default_value = Screen.low_pan_rate and 5.0 or 30.0,
callback = function(spin)
G_reader_settings:saveSetting("hold_pan_rate", spin.value)
@ -466,24 +468,55 @@ Default value: %1]]), Screen.low_pan_rate and 5.0 or 30.0),
end,
separator = true,
},
{
text = _("Tap interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
title_text = _("Tap interval"),
info_text = T(_([[
Any other taps made within this interval after a first tap will be considered accidental and ignored.
The interval value is in milliseconds and can range from 0 (0 second) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.TAP_INTERVAL/1000),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_tap_interval")/1000,
value_min = 0,
value_max = 2000,
value_step = 50,
value_hold_step = 200,
ok_text = _("Set interval"),
default_value = GestureDetector.TAP_INTERVAL/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_tap_interval", spin.value*1000)
GestureDetector:setNewInterval("ges_tap_interval", spin.value*1000)
end
}
UIManager:show(items)
end,
},
{
text = _("Double tap interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
text = T(_([[
Set double tap interval in milliseconds.
The interval value can range from 100 (0.1 seconds) to 2000 (2 seconds).
title_text = _("Double tap interval"),
info_text = T(_([[
When double tap is enabled, this sets the time to wait for the second tap. A single tap will take at least this long to be detected.
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.DOUBLE_TAP_INTERVAL/1000),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_double_tap_interval")/1000,
value_min = 100,
value_max = 2000,
value_step = 100,
value_hold_step = 500,
ok_text = _("Set interval"),
title_text = _("Double tap interval"),
default_value = GestureDetector.DOUBLE_TAP_INTERVAL/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_double_tap_interval", spin.value*1000)
@ -495,22 +528,24 @@ Default value: %1]]), GestureDetector.DOUBLE_TAP_INTERVAL/1000),
},
{
text = _("Two finger tap duration"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
text = T(_([[
Set two finger tap duration in milliseconds.
The duration value can range from 100 (0.1 seconds) to 2000 (2 seconds).
title_text = _("Two finger tap duration"),
info_text = T(_([[
This sets the allowed duration of any of the two fingers touch/release for the combined event to be considered a two finger tap.
The duration value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.TWO_FINGER_TAP_DURATION/1000),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_two_finger_tap_duration")/1000,
value_min = 100,
value_max = 2000,
value_step = 100,
value_hold_step = 500,
ok_text = _("Set duration"),
title_text = _("Two finger tap duration"),
default_value = GestureDetector.TWO_FINGER_TAP_DURATION/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_two_finger_tap_duration", spin.value*1000)
@ -522,22 +557,24 @@ Default value: %1]]), GestureDetector.TWO_FINGER_TAP_DURATION/1000),
},
{
text = _("Hold interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
text = T(_([[
Set hold interval in milliseconds.
The interval value can range from 100 (0.1 seconds) to 2000 (2 seconds).
title_text = _("Hold interval"),
info_text = T(_([[
If a touch is not released in this interval, it is considered a hold (or long-press). On document's text, single word selection is then triggered.
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.HOLD_INTERVAL/1000),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_hold_interval")/1000,
value_min = 100,
value_max = 2000,
value_step = 100,
value_hold_step = 500,
ok_text = _("Set interval"),
title_text = _("Hold interval"),
default_value = GestureDetector.HOLD_INTERVAL/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_hold_interval", spin.value*1000)
@ -549,22 +586,24 @@ Default value: %1]]), GestureDetector.HOLD_INTERVAL/1000),
},
{
text = _("Pan delay interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
text = T(_([[
Set pan delay interval in milliseconds.
The interval value can range from 100 (0.1 seconds) to 2000 (2 seconds).
title_text = _("Pan delay interval"),
info_text = T(_([[
This is used where necessary to reduce potential activation of panning when swiping is intended (e.g., for the menu or for multiswipe).
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.PAN_DELAYED_INTERVAL/1000),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_pan_delayed_interval")/1000,
value_min = 100,
value_max = 2000,
value_step = 100,
value_hold_step = 500,
ok_text = _("Set interval"),
title_text = _("Pan delay interval"),
default_value = GestureDetector.PAN_DELAYED_INTERVAL/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_pan_delayed_interval", spin.value*1000)
@ -576,22 +615,24 @@ Default value: %1]]), GestureDetector.PAN_DELAYED_INTERVAL/1000),
},
{
text = _("Swipe interval"),
keep_menu_open = true,
callback = function()
local SpinWidget = require("ui/widget/spinwidget")
local GestureDetector = require("device/gesturedetector")
local items = SpinWidget:new{
text = T(_([[
Set swipe interval in milliseconds.
The interval value can range from 100 (0.1 seconds) to 2000 (2 seconds).
title_text = _("Swipe interval"),
info_text = T(_([[
This sets the maximum delay between the start and the end of a swipe for it to be considered a swipe. Above this interval, it's considered panning.
The interval value is in milliseconds and can range from 100 (0.1 seconds) to 2000 (2 seconds).
Default value: %1]]), GestureDetector.SWIPE_INTERVAL/1000),
width = math.floor(Screen:getWidth() * 0.6),
width = math.floor(Screen:getWidth() * 0.75),
value = GestureDetector:getInterval("ges_swipe_interval")/1000,
value_min = 100,
value_max = 2000,
value_step = 100,
value_hold_step = 500,
ok_text = _("Set interval"),
title_text = _("Swipe interval"),
default_value = GestureDetector.SWIPE_INTERVAL/1000,
callback = function(spin)
G_reader_settings:saveSetting("ges_swipe_interval", spin.value*1000)

Loading…
Cancel
Save