diff --git a/frontend/ui/geometry.lua b/frontend/ui/geometry.lua index 847569aaa..1a45936a4 100644 --- a/frontend/ui/geometry.lua +++ b/frontend/ui/geometry.lua @@ -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 diff --git a/frontend/ui/gesturedetector.lua b/frontend/ui/gesturedetector.lua new file mode 100644 index 000000000..4d7eb8834 --- /dev/null +++ b/frontend/ui/gesturedetector.lua @@ -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 + + diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index 41afe6b9a..4e5cd1baa 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -1,5 +1,6 @@ require "ui/event" require "ui/device" +require "ui/gesturedetector" require "settings" -- constants from @@ -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) diff --git a/frontend/ui/menu.lua b/frontend/ui/menu.lua index 30498b9bd..93776dd0b 100644 --- a/frontend/ui/menu.lua +++ b/frontend/ui/menu.lua @@ -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}) diff --git a/frontend/ui/widget.lua b/frontend/ui/widget.lua index 630fa0589..bc23b144f 100644 --- a/frontend/ui/widget.lua +++ b/frontend/ui/widget.lua @@ -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 +