mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
first demo of gesture parsing
This commit is contained in:
@@ -146,8 +146,8 @@ for points, it is basically an equality check
|
||||
function Geom:contains(rect_b)
|
||||
if self.x <= rect_b.x
|
||||
and self.y <= rect_b.y
|
||||
and self.x + self.w <= rect_b.x + rect_b.w
|
||||
and self.y + self.h <= rect_b.y + rect_b.h
|
||||
and self.x + self.w >= rect_b.x + rect_b.w
|
||||
and self.y + self.h >= rect_b.y + rect_b.h
|
||||
then
|
||||
return true
|
||||
end
|
||||
|
||||
115
frontend/ui/gesturedetector.lua
Normal file
115
frontend/ui/gesturedetector.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
require "ui/geometry"
|
||||
|
||||
-- Synchronization events (SYN.code).
|
||||
SYN_REPORT = 0
|
||||
SYN_CONFIG = 1
|
||||
SYN_MT_REPORT = 2
|
||||
|
||||
-- For multi-touch events (ABS.code).
|
||||
ABS_MT_SLOT = 47
|
||||
ABS_MT_POSITION_X = 53
|
||||
ABS_MT_POSITION_Y = 54
|
||||
ABS_MT_TRACKING_ID = 57
|
||||
ABS_MT_PRESSURE = 58
|
||||
|
||||
GestureRange = {
|
||||
ges = nil,
|
||||
range = nil,
|
||||
}
|
||||
|
||||
function GestureRange:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function GestureRange:match(gs)
|
||||
if gs.ges ~= self.ges then
|
||||
return false
|
||||
end
|
||||
|
||||
if self.range:contains(gs.pos) then
|
||||
DEBUG(self, gs)
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
GestureDetector = {
|
||||
ev_stack = {},
|
||||
cur_ev = {},
|
||||
}
|
||||
|
||||
--[[
|
||||
MT_TRACK_ID: 0
|
||||
MT_X: 310
|
||||
MT_Y: 174
|
||||
SYN REPORT
|
||||
MT_TRACK_ID: -1
|
||||
SYN REPORT
|
||||
|
||||
MT_TRACK_ID: 0
|
||||
MT_X: 222
|
||||
MT_Y: 207
|
||||
SYN REPORT
|
||||
MT_TRACK_ID: -1
|
||||
SYN REPORT
|
||||
--]]
|
||||
|
||||
function GestureDetector:feedEvent(ev)
|
||||
if ev.type == EV_SYN then
|
||||
if ev.code == SYN_REPORT then
|
||||
-- end of one event or release touch?
|
||||
if self.cur_ev.id == -1 then
|
||||
-- touch release?
|
||||
return self:guessGesture()
|
||||
else
|
||||
table.insert(self.ev_stack, self.cur_ev)
|
||||
self.cur_ev = {}
|
||||
--DEBUG(self.ev_stack)
|
||||
end
|
||||
end
|
||||
elseif ev.type == EV_ABS then
|
||||
if ev.code == ABS_MT_SLOT then
|
||||
elseif ev.code == ABS_MT_TRACKING_ID then
|
||||
self.cur_ev.id = ev.value
|
||||
elseif ev.code == ABS_MT_POSITION_X then
|
||||
self.cur_ev.x = ev.value
|
||||
elseif ev.code == ABS_MT_POSITION_Y then
|
||||
self.cur_ev.y = ev.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GestureDetector:guessGesture()
|
||||
local is_recognized = false
|
||||
local result = nil
|
||||
local last_ev = {pos = Geom:new{}}
|
||||
|
||||
for k,ev in ipairs(self.ev_stack) do
|
||||
--@TODO do real recognization here (houqp)
|
||||
is_recognized = true
|
||||
result = {
|
||||
ges = "tap",
|
||||
pos = Geom:new{
|
||||
x = ev.x or last_ev.x,
|
||||
y = ev.y or last_ev.x,
|
||||
w = 0,
|
||||
h = 0,
|
||||
}
|
||||
}
|
||||
last_ev = ev
|
||||
end
|
||||
|
||||
if is_recognized then
|
||||
self.ev_stack = {}
|
||||
return result
|
||||
else
|
||||
DEBUG("Unknown gesture!!", self.ev_stack)
|
||||
self.ev_stack = {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require "ui/event"
|
||||
require "ui/device"
|
||||
require "ui/gesturedetector"
|
||||
require "settings"
|
||||
|
||||
-- constants from <linux/input.h>
|
||||
@@ -7,18 +8,6 @@ EV_SYN = 0
|
||||
EV_KEY = 1
|
||||
EV_ABS = 3
|
||||
|
||||
-- Synchronization events (SYN.code).
|
||||
SYN_REPORT = 0
|
||||
SYN_CONFIG = 1
|
||||
SYN_MT_REPORT = 2
|
||||
|
||||
-- For multi-touch events (ABS.code).
|
||||
ABS_MT_SLOT = 47
|
||||
ABS_MT_POSITION_X = 53
|
||||
ABS_MT_POSITION_Y = 54
|
||||
ABS_MT_TRACKING_ID = 57
|
||||
ABS_MT_PRESSURE = 58
|
||||
|
||||
-- key press event values (KEY.value)
|
||||
EVENT_VALUE_KEY_PRESS = 1
|
||||
EVENT_VALUE_KEY_REPEAT = 2
|
||||
@@ -341,29 +330,35 @@ function Input:waitEvent(timeout_us, timeout_s)
|
||||
elseif ev.value == EVENT_VALUE_KEY_RELEASE then
|
||||
return Event:new("KeyRelease", key)
|
||||
end
|
||||
elseif ev.type == EV_ABS then
|
||||
if ev.code == ABS_MT_SLOT then
|
||||
DEBUG("MT_SLOT:", ev.value)
|
||||
elseif ev.code == ABS_MT_TRACKING_ID then
|
||||
DEBUG("MT_TRACK_ID:", ev.value)
|
||||
elseif ev.code == ABS_MT_POSITION_X then
|
||||
DEBUG("MT_X:", ev.value)
|
||||
elseif ev.code == ABS_MT_POSITION_Y then
|
||||
DEBUG("MT_Y:", ev.value)
|
||||
else
|
||||
DEBUG("unknown touch event!", ev)
|
||||
return Event:new("UnkonwnTouchEvent", ev)
|
||||
end
|
||||
elseif ev.type == EV_SYN then
|
||||
if ev.code == SYN_REPORT then
|
||||
DEBUG("SYN REPORT")
|
||||
elseif ev.code == SYN_MT_REPORT then
|
||||
DEBUG("SYN MT_REPORT")
|
||||
elseif ev.code == SYN_CONFIG then
|
||||
DEBUG("SYN CONFIG")
|
||||
else
|
||||
DEBUG(ev)
|
||||
elseif ev.type == EV_ABS or ev.type == EV_SYN then
|
||||
local touch_ges = GestureDetector:feedEvent(ev)
|
||||
DEBUG(touch_ges)
|
||||
if touch_ges then
|
||||
return Event:new("Gesture", touch_ges)
|
||||
end
|
||||
--elseif ev.type == EV_ABS then
|
||||
--if ev.code == ABS_MT_SLOT then
|
||||
--DEBUG("MT_SLOT:", ev.value)
|
||||
--elseif ev.code == ABS_MT_TRACKING_ID then
|
||||
--DEBUG("MT_TRACK_ID:", ev.value)
|
||||
--elseif ev.code == ABS_MT_POSITION_X then
|
||||
--DEBUG("MT_X:", ev.value)
|
||||
--elseif ev.code == ABS_MT_POSITION_Y then
|
||||
--DEBUG("MT_Y:", ev.value)
|
||||
--else
|
||||
--DEBUG("unknown touch event!", ev)
|
||||
--return Event:new("UnkonwnTouchEvent", ev)
|
||||
--end
|
||||
--elseif ev.type == EV_SYN then
|
||||
--if ev.code == SYN_REPORT then
|
||||
--DEBUG("SYN REPORT")
|
||||
--elseif ev.code == SYN_MT_REPORT then
|
||||
--DEBUG("SYN MT_REPORT")
|
||||
--elseif ev.code == SYN_CONFIG then
|
||||
--DEBUG("SYN CONFIG")
|
||||
--else
|
||||
--DEBUG(ev)
|
||||
--end
|
||||
else
|
||||
-- some other kind of event that we do not know yet
|
||||
return Event:new("GenericInput", ev)
|
||||
|
||||
@@ -80,6 +80,21 @@ function MenuItem:init()
|
||||
self.active_key_events = {
|
||||
Select = { {"Press"}, doc = "chose selected item" },
|
||||
}
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
--range = Geom:new{
|
||||
--x = self.dimen.x,
|
||||
--y = self.dimen.y,
|
||||
--h = self.dimen.h,
|
||||
--w = self.dimen.w,
|
||||
--},
|
||||
},
|
||||
doc = "Select Menu Item",
|
||||
},
|
||||
}
|
||||
|
||||
w = sizeUtf8Text(0, self.dimen.w, self.face, self.text, true).x
|
||||
if w >= self.content_width then
|
||||
@@ -136,6 +151,11 @@ function MenuItem:onShowItemDetail()
|
||||
return true
|
||||
end
|
||||
|
||||
function MenuItem:onTapSelect()
|
||||
self.menu:onMenuSelect(self.table)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Widget that displays menu
|
||||
@@ -265,9 +285,11 @@ function Menu:updateItems(select_number)
|
||||
local item_tmp = MenuItem:new{
|
||||
text = self.item_table[i].text,
|
||||
face = self.cface,
|
||||
dimen = self.item_dimen,
|
||||
dimen = self.item_dimen:new(),
|
||||
shortcut = item_shortcut,
|
||||
shortcut_style = shortcut_style,
|
||||
table = self.item_table[i],
|
||||
menu = self,
|
||||
}
|
||||
table.insert(self.item_group, item_tmp)
|
||||
table.insert(self.layout, {item_tmp})
|
||||
|
||||
@@ -4,6 +4,7 @@ require "ui/graphics"
|
||||
require "ui/image"
|
||||
require "ui/event"
|
||||
require "ui/inputevent"
|
||||
require "ui/gesturedetector"
|
||||
require "ui/font"
|
||||
|
||||
--[[
|
||||
@@ -60,7 +61,7 @@ function WidgetContainer:getSize()
|
||||
-- return size of first child widget
|
||||
return self[1]:getSize()
|
||||
else
|
||||
return { w = 0, h = 0 }
|
||||
return Geom:new{ w = 0, h = 0 }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -513,9 +514,18 @@ it is suggested to reference configurable sequences from another table
|
||||
and store that table as configuration setting
|
||||
]]
|
||||
InputContainer = WidgetContainer:new{
|
||||
key_events = {}
|
||||
key_events = {},
|
||||
ges_events = {},
|
||||
}
|
||||
|
||||
function InputContainer:paintTo(bb, x, y)
|
||||
self.dimen.x = x
|
||||
self.dimen.y = y
|
||||
if self[1] then
|
||||
return self[1]:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
|
||||
-- the following handler handles keypresses and checks
|
||||
-- if they lead to a command.
|
||||
-- if this is the case, we retransmit another event within
|
||||
@@ -533,3 +543,15 @@ function InputContainer:onKeyPress(key)
|
||||
end
|
||||
end
|
||||
|
||||
function InputContainer:onGesture(ev)
|
||||
for name, gsseq in pairs(self.ges_events) do
|
||||
for _, gs_range in ipairs(gsseq) do
|
||||
if gs_range:match(ev) then
|
||||
--DEBUG(gs_range)
|
||||
local eventname = gsseq.event or name
|
||||
return self:handleEvent(Event:new(eventname, gsseq.args, ev))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user