first demo of screen rotate

pull/2/merge
Qingping Hou 11 years ago
parent 78691fd499
commit d4ff6f9291

@ -83,11 +83,14 @@ function Device:intoScreenSaver()
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt") --os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
if self.charging_mode == false and self.screen_saver_mode == false then if self.charging_mode == false and self.screen_saver_mode == false then
Screen:saveCurrentBB() Screen:saveCurrentBB()
--msg = InfoMessage:new{"Going into screensaver... "} msg = InfoMessage:new{
text = "Going into screensaver... ",
timeout = 2,
}
--UIManager:show(msg) --UIManager:show(msg)
Screen.kpv_rotation_mode = Screen.cur_rotation_mode --Screen.kpv_rotation_mode = Screen.cur_rotation_mode
Screen.fb:setOrientation(Screen.native_rotation_mode) --Screen.fb:setOrientation(Screen.native_rotation_mode)
--util.sleep(1) --util.sleep(1)
--os.execute("killall -cont cvm") --os.execute("killall -cont cvm")
self.screen_saver_mode = true self.screen_saver_mode = true
@ -99,11 +102,11 @@ end
function Device:outofScreenSaver() function Device:outofScreenSaver()
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt") --os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
if self.screen_saver_mode == true and self.charging_mode == false then if self.screen_saver_mode == true and self.charging_mode == false then
util.usleep(1500000) --util.usleep(1500000)
--os.execute("killall -stop cvm") --os.execute("killall -stop cvm")
Screen.fb:setOrientation(Screen.kpv_rotation_mode) --Screen.fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB() Screen:restoreFromSavedBB()
Screen.fb:refresh(0) Screen:refresh(0)
end end
self.screen_saver_mode = false self.screen_saver_mode = false
end end
@ -112,13 +115,14 @@ function Device:usbPlugIn()
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt") --os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
if self.charging_mode == false and self.screen_saver_mode == false then if self.charging_mode == false and self.screen_saver_mode == false then
Screen:saveCurrentBB() Screen:saveCurrentBB()
Screen.kpv_rotation_mode = Screen.cur_rotation_mode --Screen.kpv_rotation_mode = Screen.cur_rotation_mode
Screen.fb:setOrientation(Screen.native_rotation_mode) --Screen.fb:setOrientation(Screen.native_rotation_mode)
msg = InfoMessage:new{"Going into USB mode... "} msg = InfoMessage:new{
UIManager:show(msg) text = "Going into USB mode... ",
util.sleep(1) timeout = 2,
UIManager:close(msg) }
os.execute("killall -cont cvm") --util.sleep(1)
--os.execute("killall -cont cvm")
end end
self.charging_mode = true self.charging_mode = true
end end
@ -126,11 +130,11 @@ end
function Device:usbPlugOut() function Device:usbPlugOut()
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt") --os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
if self.charging_mode == true and self.screen_saver_mode == false then if self.charging_mode == true and self.screen_saver_mode == false then
util.usleep(1500000) --util.usleep(1500000)
os.execute("killall -stop cvm") --os.execute("killall -stop cvm")
Screen.fb:setOrientation(Screen.kpv_rotation_mode) --Screen.fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB() Screen:restoreFromSavedBB()
Screen.fb:refresh(0) Screen:refresh(0)
end end
--@TODO signal filemanager for file changes 13.06 2012 (houqp) --@TODO signal filemanager for file changes 13.06 2012 (houqp)

@ -33,14 +33,22 @@ Currently supported gestures:
* pan * pan
* swipe * swipe
Single tap event from kernel example: You change the state machine by feeding it touch events, i.e. calling
GestureDetector:feedEvent(tev).
MT_TRACK_ID: 0 a touch event should have following format:
MT_X: 222 tev = {
MT_Y: 207 slot = 1,
SYN REPORT id = 46,
MT_TRACK_ID: -1 x = 0,
SYN REPORT y = 1,
timev = TimeVal:new{...},
}
Don't confuse tev with raw evs from kernel, tev is build according to ev.
GestureDetector:feedEvent(tev) will return a detection result when you
feed a touch release event to it.
--]] --]]
GestureDetector = { GestureDetector = {
@ -54,41 +62,22 @@ GestureDetector = {
track_id = {}, track_id = {},
ev_stack = {}, ev_stack = {},
cur_ev = {}, -- latest feeded touch event
last_ev = {},
is_ev_start = false, is_ev_start = false,
first_ev = nil, first_ev = nil,
state = function(self, ev) state = function(self, ev)
self:switchState("initialState", ev) self:switchState("initialState", ev)
end, end,
last_ev_timev = nil,
last_tap = nil, -- for single/double tap last_tap = nil, -- for single/double tap
} }
function GestureDetector:feedEvent(ev) function GestureDetector:feedEvent(tev)
--DEBUG(ev.type, ev.code, ev.value, ev.time) if tev.id ~= -1 then
if ev.type == EV_SYN then self.last_ev = tev
if ev.code == SYN_REPORT then
self.cur_ev.timev = TimeVal:new(ev.time)
local re = self.state(self, self.cur_ev)
self.last_ev_timev = self.cur_ev.timev
if re ~= nil then
return re
end
self.cur_ev = {}
end
elseif ev.type == EV_ABS then
if ev.code == ABS_MT_SLOT then
self.cur_ev.slot = ev.value
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
return self.state(self, tev)
end end
function GestureDetector:deepCopyEv(ev) function GestureDetector:deepCopyEv(ev)
@ -120,11 +109,11 @@ end
compare last_pan with self.first_ev compare last_pan with self.first_ev
if it is a swipe, return direction of swipe gesture. if it is a swipe, return direction of swipe gesture.
--]] --]]
function GestureDetector:isSwipe(last_pan_ev) function GestureDetector:isSwipe()
local tv_diff = self.first_ev.timev - last_pan_ev.timev local tv_diff = self.first_ev.timev - self.last_ev.timev
if (tv_diff.sec == 0) and (tv_diff.usec < self.SWIPE_INTERVAL) then if (tv_diff.sec == 0) and (tv_diff.usec < self.SWIPE_INTERVAL) then
x_diff = last_pan_ev.x - self.first_ev.x x_diff = self.last_ev.x - self.first_ev.x
y_diff = last_pan_ev.y - self.first_ev.y y_diff = self.last_ev.y - self.first_ev.y
if x_diff == 0 and y_diff == 0 then if x_diff == 0 and y_diff == 0 then
return nil return nil
end end
@ -157,10 +146,8 @@ function GestureDetector:switchState(state_new, ev)
end end
function GestureDetector:clearState() function GestureDetector:clearState()
self.cur_x = nil
self.cur_y = nil
self.state = self.initialState self.state = self.initialState
self.cur_ev = {} self.last_ev = {}
self.is_ev_start = false self.is_ev_start = false
self.first_ev = nil self.first_ev = nil
end end
@ -196,15 +183,15 @@ function GestureDetector:tapState(ev)
-- default to single tap -- default to single tap
ges = "tap", ges = "tap",
pos = Geom:new{ pos = Geom:new{
x = self.cur_x, x = self.last_ev.x,
y = self.cur_y, y = self.last_ev.y,
w = 0, h = 0, w = 0, h = 0,
} }
} }
-- cur_tap is used for double tap detection -- cur_tap is used for double tap detection
local cur_tap = { local cur_tap = {
x = self.cur_x, x = self.last_ev.x,
y = self.cur_y, y = self.last_ev.y,
timev = ev.timev, timev = ev.timev,
} }
@ -221,7 +208,7 @@ function GestureDetector:tapState(ev)
self.last_tap = cur_tap self.last_tap = cur_tap
DEBUG("set up tap timer") DEBUG("set up tap timer")
local deadline = self.cur_ev.timev + TimeVal:new{ local deadline = self.last_ev.timev + TimeVal:new{
sec = 0, usec = self.DOUBLE_TAP_INTERVAL, sec = 0, usec = self.DOUBLE_TAP_INTERVAL,
} }
Input:setTimeout(function() Input:setTimeout(function()
@ -241,10 +228,8 @@ function GestureDetector:tapState(ev)
-- switched from other state, probably from initialState -- switched from other state, probably from initialState
-- we return nil in this case -- we return nil in this case
self.state = self.tapState self.state = self.tapState
self.cur_x = ev.x
self.cur_y = ev.y
DEBUG("set up hold timer") DEBUG("set up hold timer")
local deadline = self.cur_ev.timev + TimeVal:new{ local deadline = self.last_ev.timev + TimeVal:new{
sec = 0, usec = self.HOLD_INTERVAL sec = 0, usec = self.HOLD_INTERVAL
} }
Input:setTimeout(function() Input:setTimeout(function()
@ -269,16 +254,7 @@ function GestureDetector:panState(ev)
DEBUG("in pan state...") DEBUG("in pan state...")
if ev.id == -1 then if ev.id == -1 then
-- end of pan, signal swipe gesture if necessary -- end of pan, signal swipe gesture if necessary
-- we need to construct a complete_last_ev because swipe_direct = self:isSwipe()
-- the x or y of ev might be nil.
local complete_last_ev = self:deepCopyEv(ev)
if not complete_last_ev.x then
complete_last_ev.x = self.cur_x
end
if not complete_last_ev.y then
complete_last_ev.y = self.cur_y
end
swipe_direct = self:isSwipe(complete_last_ev)
if swipe_direct then if swipe_direct then
local start_pos = Geom:new{ local start_pos = Geom:new{
x = self.first_ev.x, x = self.first_ev.x,
@ -309,19 +285,14 @@ function GestureDetector:panState(ev)
}, },
pos = nil, pos = nil,
} }
if ev.x then pan_ev.relative.x = ev.x - self.last_ev.x
pan_ev.relative.x = ev.x - self.cur_x pan_ev.relative.y = ev.y - self.last_ev.y
self.cur_x = ev.x
end
if ev.y then
pan_ev.relative.y = ev.y - self.cur_y
self.cur_y = ev.y
end
pan_ev.pos = Geom:new{ pan_ev.pos = Geom:new{
x = self.cur_x, x = self.last_ev.x,
y = self.cur_y, y = self.last_ev.y,
w = 0, h = 0, w = 0, h = 0,
} }
self.last_ev = ev
return pan_ev return pan_ev
end end
end end
@ -330,13 +301,13 @@ function GestureDetector:holdState(ev)
DEBUG("in hold state...") DEBUG("in hold state...")
-- when we switch to hold state, we pass no ev -- when we switch to hold state, we pass no ev
-- so ev = nil -- so ev = nil
if not ev and self.cur_x and self.cur_y then if not ev and self.last_ev.x and self.last_ev.y then
self.state = self.holdState self.state = self.holdState
return { return {
ges = "hold", ges = "hold",
pos = Geom:new{ pos = Geom:new{
x = self.cur_x, x = self.last_ev.x,
y = self.cur_y, y = self.last_ev.y,
w = 0, h = 0, w = 0, h = 0,
} }
} }
@ -347,8 +318,8 @@ function GestureDetector:holdState(ev)
return { return {
ges = "hold_release", ges = "hold_release",
pos = Geom:new{ pos = Geom:new{
x = self.cur_x, x = self.last_ev.x,
y = self.cur_y, y = self.last_ev.y,
w = 0, h = 0, w = 0, h = 0,
} }
} }

@ -9,14 +9,15 @@ it vanishes on key press or after a given timeout
InfoMessage = InputContainer:new{ InfoMessage = InputContainer:new{
face = Font:getFace("infofont", 25), face = Font:getFace("infofont", 25),
text = "", text = "",
timeout = nil, timeout = nil, -- in seconds
key_events = {
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
}
} }
function InfoMessage:init() function InfoMessage:init()
if Device:hasKeyboard() then
key_events = {
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
}
end
-- we construct the actual content here because self.text is only available now -- we construct the actual content here because self.text is only available now
self[1] = CenterContainer:new{ self[1] = CenterContainer:new{
dimen = Screen:getSize(), dimen = Screen:getSize(),

@ -122,7 +122,13 @@ end
an interface to get input events an interface to get input events
]] ]]
Input = { Input = {
event_map = { event_map = {},
rotation = 0,
timer_callbacks = {},
}
function Input:initKeyMap()
self.event_map = {
[2] = "1", [3] = "2", [4] = "3", [5] = "4", [6] = "5", [7] = "6", [8] = "7", [9] = "8", [10] = "9", [11] = "0", [2] = "1", [3] = "2", [4] = "3", [5] = "4", [6] = "5", [7] = "6", [8] = "7", [9] = "8", [10] = "9", [11] = "0",
[16] = "Q", [17] = "W", [18] = "E", [19] = "R", [20] = "T", [21] = "Y", [22] = "U", [23] = "I", [24] = "O", [25] = "P", [16] = "Q", [17] = "W", [18] = "E", [19] = "R", [20] = "T", [21] = "Y", [22] = "U", [23] = "I", [24] = "O", [25] = "P",
[30] = "A", [31] = "S", [32] = "D", [33] = "F", [34] = "G", [35] = "H", [36] = "J", [37] = "K", [38] = "L", [14] = "Del", [30] = "A", [31] = "S", [32] = "D", [33] = "F", [34] = "G", [35] = "H", [36] = "J", [37] = "K", [38] = "L", [14] = "Del",
@ -157,13 +163,8 @@ Input = {
[191] = "RPgFwd", -- K[3] & k[4] [191] = "RPgFwd", -- K[3] & k[4]
[193] = "LPgFwd", -- K[3] only [193] = "LPgFwd", -- K[3] only
[194] = "Press", -- K[3] & k[4] [194] = "Press", -- K[3] & k[4]
}
[10000] = "IntoSS", -- go into screen saver self.sdl_event_map = {
[10001] = "OutOfSS", -- go out of screen saver
[10020] = "Charging",
[10021] = "NotCharging",
},
sdl_event_map = {
[10] = "1", [11] = "2", [12] = "3", [13] = "4", [14] = "5", [15] = "6", [16] = "7", [17] = "8", [18] = "9", [19] = "0", [10] = "1", [11] = "2", [12] = "3", [13] = "4", [14] = "5", [15] = "6", [16] = "7", [17] = "8", [18] = "9", [19] = "0",
[24] = "Q", [25] = "W", [26] = "E", [27] = "R", [28] = "T", [29] = "Y", [30] = "U", [31] = "I", [32] = "O", [33] = "P", [24] = "Q", [25] = "W", [26] = "E", [27] = "R", [28] = "T", [29] = "Y", [30] = "U", [31] = "I", [32] = "O", [33] = "P",
[38] = "A", [39] = "S", [40] = "D", [41] = "F", [42] = "G", [43] = "H", [44] = "J", [45] = "K", [46] = "L", [38] = "A", [39] = "S", [40] = "D", [41] = "F", [42] = "G", [43] = "H", [44] = "J", [45] = "K", [46] = "L",
@ -192,21 +193,19 @@ Input = {
[116] = "Down", -- arrow down [116] = "Down", -- arrow down
[117] = "RPgFwd", -- normal PageDown [117] = "RPgFwd", -- normal PageDown
[119] = "Del", -- Delete [119] = "Del", -- Delete
}, }
rotation = 0, self.rotation_map = {
rotation_map = {
[0] = {}, [0] = {},
[1] = { Up = "Right", Right = "Down", Down = "Left", Left = "Up" }, [1] = { Up = "Right", Right = "Down", Down = "Left", Left = "Up" },
[2] = { Up = "Down", Right = "Left", Down = "Up", Left = "Right" }, [2] = { Up = "Down", Right = "Left", Down = "Up", Left = "Right" },
[3] = { Up = "Left", Right = "Up", Down = "Right", Left = "Down" } [3] = { Up = "Left", Right = "Up", Down = "Right", Left = "Down" }
}, }
modifiers = { self.modifiers = {
Alt = false, Alt = false,
Shift = false Shift = false
}, }
-- these groups are just helpers: -- these groups are just helpers:
group = { self.group = {
Cursor = { "Up", "Down", "Left", "Right" }, Cursor = { "Up", "Down", "Left", "Right" },
PgFwd = { "RPgFwd", "LPgFwd" }, PgFwd = { "RPgFwd", "LPgFwd" },
PgBack = { "RPgBack", "LPgBack" }, PgBack = { "RPgBack", "LPgBack" },
@ -237,13 +236,31 @@ Input = {
"Back", "Enter", "Sym", "AA", "Menu", "Home", "Del", "Back", "Enter", "Sym", "AA", "Menu", "Home", "Del",
"LPgBack", "RPgBack", "LPgFwd", "RPgFwd" "LPgBack", "RPgBack", "LPgFwd", "RPgFwd"
} }
}, }
end
timer_callbacks = {}, function Input:initTouchState()
} self.cur_ev = {}
end
function Input:init() function Input:init()
-- Screen module must have been initilized by now.
self.rotation = Screen.fb:getOrientation()
if Device:hasKeyboard() then
self:initKeyMap()
end
if Device:isTouchDevice() then
self:initTouchState()
end
-- set up fake event map
self.event_map[10000] = "IntoSS" -- go into screen saver
self.event_map[10001] = "OutOfSS" -- go out of screen saver
self.event_map[10020] = "Charging"
self.event_map[10021] = "NotCharging"
if util.isEmulated()==1 then if util.isEmulated()==1 then
self:initKeyMap()
os.remove("emu_event") os.remove("emu_event")
os.execute("mkfifo emu_event") os.execute("mkfifo emu_event")
input.open("emu_event") input.open("emu_event")
@ -327,6 +344,86 @@ function Input:setTimeout(cb, tv_out)
end end
end end
function Input:handleKeyBoardEv(ev)
local keycode = self.event_map[ev.code]
if not keycode then
-- do not handle keypress for keys we don't know
return
end
-- take device rotation into account
if self.rotation_map[self.rotation][keycode] then
keycode = self.rotation_map[self.rotation][keycode]
end
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "Charging" or keycode == "NotCharging" then
return keycode
end
-- handle modifier keys
if self.modifiers[keycode] ~= nil then
if ev.value == EVENT_VALUE_KEY_PRESS then
self.modifiers[keycode] = true
elseif ev.value == EVENT_VALUE_KEY_RELEASE then
self.modifiers[keycode] = false
end
return
end
local key = Key:new(keycode, self.modifiers)
if ev.value == EVENT_VALUE_KEY_PRESS then
return Event:new("KeyPress", key)
elseif ev.value == EVENT_VALUE_KEY_RELEASE then
return Event:new("KeyRelease", key)
end
end
--[[
parse each touch ev from kernel and build up tev.
tev will be sent to GestureDetector:feedEvent
Events for a single tap motion from Linux kernel (MT protocol B):
MT_TRACK_ID: 0
MT_X: 222
MT_Y: 207
SYN REPORT
MT_TRACK_ID: -1
SYN REPORT
Notice that each line is a single event.
--]]
function Input:handleTouchEv(ev)
if ev.type == EV_SYN then
if ev.code == SYN_REPORT then
self.cur_ev.timev = TimeVal:new(ev.time)
--self.cur_x = self.cur_ev.x or self.cur_x
--self.cur_y = self.cur_ev.y or self.cur_y
-- send ev to state machine
local touch_ges = GestureDetector:feedEvent(self.cur_ev)
--self.last_ev_timev = self.cur_ev.timev
--self.cur_ev = {}
if touch_ges then
return Event:new("Gesture",
Screen:adjustGesCoordinate(touch_ges)
)
end
end
elseif ev.type == EV_ABS then
if ev.code == ABS_MT_SLOT then
self.cur_ev.slot = ev.value
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 Input:waitEvent(timeout_us, timeout_s) function Input:waitEvent(timeout_us, timeout_s)
-- wrapper for input.waitForEvents that will retry for some cases -- wrapper for input.waitForEvents that will retry for some cases
local ok, ev local ok, ev
@ -344,14 +441,16 @@ function Input:waitEvent(timeout_us, timeout_s)
if ((not timeout_us and not timeout_s) or tv_now < wait_deadline) then if ((not timeout_us and not timeout_s) or tv_now < wait_deadline) then
-- check whether timer is up -- check whether timer is up
if tv_now >= self.timer_callbacks[1].deadline then if tv_now >= self.timer_callbacks[1].deadline then
local ges = self.timer_callbacks[1].callback() local touch_ges = self.timer_callbacks[1].callback()
table.remove(self.timer_callbacks, 1) table.remove(self.timer_callbacks, 1)
if ges then if touch_ges then
-- Do we really need to clear all setTimeout after -- Do we really need to clear all setTimeout after
-- decided a gesture? FIXME -- decided a gesture? FIXME
Input.timer_callbacks = {} Input.timer_callbacks = {}
return Event:new("Gesture", ges) return Event:new("Gesture",
end -- EOF if ges Screen:adjustGesCoordinate(touch_ges)
)
end -- EOF if touch_ges
end -- EOF if deadline reached end -- EOF if deadline reached
else else
break break
@ -376,47 +475,13 @@ function Input:waitEvent(timeout_us, timeout_s)
break break
end end
end end
if ok and ev then if ok and ev then
ev = self:eventAdjustHook(ev) ev = self:eventAdjustHook(ev)
if ev.type == EV_KEY then if ev.type == EV_KEY then
local keycode = self.event_map[ev.code] return self:handleKeyBoardEv(ev)
if not keycode then
-- do not handle keypress for keys we don't know
return
end
-- take device rotation into account
if self.rotation_map[self.rotation][keycode] then
keycode = self.rotation_map[self.rotation][keycode]
end
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "Charging" or keycode == "NotCharging" then
return keycode
end
-- handle modifier keys
if self.modifiers[keycode] ~= nil then
if ev.value == EVENT_VALUE_KEY_PRESS then
self.modifiers[keycode] = true
elseif ev.value == EVENT_VALUE_KEY_RELEASE then
self.modifiers[keycode] = false
end
return
end
local key = Key:new(keycode, self.modifiers)
if ev.value == EVENT_VALUE_KEY_PRESS then
return Event:new("KeyPress", key)
elseif ev.value == EVENT_VALUE_KEY_RELEASE then
return Event:new("KeyRelease", key)
end
elseif ev.type == EV_ABS or ev.type == EV_SYN then elseif ev.type == EV_ABS or ev.type == EV_SYN then
local touch_ges = GestureDetector:feedEvent(ev) return self:handleTouchEv(ev)
if touch_ges then
return Event:new("Gesture", touch_ges)
end
else else
-- some other kind of event that we do not know yet -- some other kind of event that we do not know yet
return Event:new("GenericInput", ev) return Event:new("GenericInput", ev)

@ -8,13 +8,14 @@ Notification = InputContainer:new{
face = Font:getFace("infofont", 20), face = Font:getFace("infofont", 20),
text = "Null Message", text = "Null Message",
timeout = nil, timeout = nil,
key_events = {
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
}
} }
function Notification:init() function Notification:init()
if Device:hasKeyboard() then
key_events = {
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
}
end
-- we construct the actual content here because self.text is only available now -- we construct the actual content here because self.text is only available now
self[1] = CenterContainer:new{ self[1] = CenterContainer:new{
dimen = Geom:new{ dimen = Geom:new{

@ -12,23 +12,25 @@ function ReaderBookmark:init()
{ "B" }, { "B" },
doc = "show bookmarks" }, doc = "show bookmarks" },
} }
elseif Device:isTouchDevice() then
self.ges_events = {
AddBookmark = {
GestureRange:new{
ges = "double_tap",
range = Geom:new{
x = Screen:getWidth()/2, y = 0,
w = Screen:getWidth()/2,
h = Screen:getHeight()/2
}
}
},
}
end end
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
end end
function ReaderBookmark:initGesListener()
self.ges_events = {
AddBookmark = {
GestureRange:new{
ges = "double_tap",
range = Geom:new{
x = Screen:getWidth()/2, y = 0,
w = Screen:getWidth()/2,
h = Screen:getHeight()/2
}
}
},
}
end
function ReaderBookmark:onReadSettings(config) function ReaderBookmark:onReadSettings(config)
self.bookmarks = config:readSetting("bookmarks") or {} self.bookmarks = config:readSetting("bookmarks") or {}
end end
@ -38,7 +40,10 @@ function ReaderBookmark:onCloseDocument()
end end
function ReaderBookmark:onSetDimensions(dimen) function ReaderBookmark:onSetDimensions(dimen)
self.dimen = dimen -- update listening according to new screen dimen
if Device:isTouchDevice() then
self:initGesListener()
end
end end
function ReaderBookmark:onAddBookmark() function ReaderBookmark:onAddBookmark()

@ -55,20 +55,25 @@ ReaderConfig = InputContainer:new{
} }
function ReaderConfig:init() function ReaderConfig:init()
if Device:isTouchDevice() then if Device:hasKeyboard() then
self.ges_events = {
TapShowConfigMenu = {
GestureRange:new{
ges = "tap",
range = self.dimen:copy(),
}
}
}
else
self.key_events = { self.key_events = {
ShowConfigMenu = { { "AA" }, doc = "show config dialog" }, ShowConfigMenu = { { "AA" }, doc = "show config dialog" },
} }
end end
if Device:isTouchDevice() then
self:initGesListener()
end
end
function ReaderConfig:initGesListener()
self.ges_events = {
TapShowConfigMenu = {
GestureRange:new{
ges = "tap",
range = self.dimen:copy(),
}
}
}
end end
function ReaderConfig:onShowConfigMenu() function ReaderConfig:onShowConfigMenu()
@ -107,8 +112,15 @@ function ReaderConfig:onTapShowConfigMenu()
end end
function ReaderConfig:onSetDimensions(dimen) function ReaderConfig:onSetDimensions(dimen)
-- update gesture listenning range according to new screen orientation -- update listening according to new screen dimen
self:init() --@TODO do we really need to new a Geom everytime? 02.02 2013 (houqp)
self.dimen = Geom:new{
x = 0,
y = 7*Screen:getHeight()/8,
w = Screen:getWidth(),
h = Screen:getHeight()/8,
}
self:initGesListener()
end end
function ReaderConfig:onReadSettings(config) function ReaderConfig:onReadSettings(config)

@ -1,4 +1,5 @@
ReaderMenu = InputContainer:new{ ReaderMenu = InputContainer:new{
_name = "ReaderMenu",
item_table = {}, item_table = {},
registered_widgets = {}, registered_widgets = {},
} }
@ -7,42 +8,44 @@ function ReaderMenu:init()
self.item_table = {} self.item_table = {}
self.registered_widgets = {} self.registered_widgets = {}
if Device:isTouchDevice() then if Device:hasKeyboard() then
self.ges_events = {
TapShowMenu = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight()/4,
}
}
},
}
else
self.key_events = { self.key_events = {
ShowMenu = { { "Menu" }, doc = "show menu" }, ShowMenu = { { "Menu" }, doc = "show menu" },
} }
end end
end end
function ReaderMenu:initGesListener()
self.ges_events = {
TapShowMenu = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight()/4,
}
}
},
}
end
function ReaderMenu:setUpdateItemTable() function ReaderMenu:setUpdateItemTable()
table.insert(self.item_table, { table.insert(self.item_table, {
text = "Screen rotate", text = "Screen rotate",
sub_item_table = { sub_item_table = {
{ {
text = "rotate 90 degree clockwise", text = "landscape",
callback = function() callback = function()
--Screen:screenRotate("clockwise") Screen:setViewMode("landscape")
self.ui:handleEvent( self.ui:handleEvent(
Event:new("SetDimensions", Screen:getSize())) Event:new("SetDimensions", Screen:getSize()))
end end
}, },
{ {
text = "rotate 90 degree anticlockwise", text = "portrait",
callback = function() callback = function()
--Screen:screenRotate("anticlockwise") Screen:setViewMode("portrait")
self.ui:handleEvent( self.ui:handleEvent(
Event:new("SetDimensions", Screen:getSize())) Event:new("SetDimensions", Screen:getSize()))
end end
@ -101,8 +104,10 @@ function ReaderMenu:onTapShowMenu()
end end
function ReaderMenu:onSetDimensions(dimen) function ReaderMenu:onSetDimensions(dimen)
-- @TODO update gesture listenning range according to new screen -- update listening according to new screen dimen
-- orientation 15.12 2012 (houqp) if Device:isTouchDevice() then
self:initGesListener()
end
end end
function ReaderMenu:onCloseDocument() function ReaderMenu:onCloseDocument()

@ -8,32 +8,7 @@ ReaderPaging = InputContainer:new{
} }
function ReaderPaging:init() function ReaderPaging:init()
if Device:isTouchDevice() then if Device:hasKeyboard() then
self.ges_events = {
TapForward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = Screen:getWidth()/4,
y = Screen:getHeight()/4,
w = 3*Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
},
TapBackward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0,
y = Screen:getHeight()/4,
w = Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
}
}
else
self.key_events = { self.key_events = {
GotoNextPage = { GotoNextPage = {
{Input.group.PgFwd}, doc = "go to next page", {Input.group.PgFwd}, doc = "go to next page",
@ -67,6 +42,34 @@ function ReaderPaging:init()
self.number_of_pages = self.ui.document.info.number_of_pages self.number_of_pages = self.ui.document.info.number_of_pages
end end
-- This method will be called in onSetDimensions handler
function ReaderPaging:initGesListener()
self.ges_events = {
TapForward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = Screen:getWidth()/4,
y = Screen:getHeight()/4,
w = 3*Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
},
TapBackward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0,
y = Screen:getHeight()/4,
w = Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
}
}
end
function ReaderPaging:onReadSettings(config) function ReaderPaging:onReadSettings(config)
self:gotoPage(config:readSetting("last_page") or 1) self:gotoPage(config:readSetting("last_page") or 1)
local soe = config:readSetting("show_overlap_enable") local soe = config:readSetting("show_overlap_enable")
@ -90,24 +93,6 @@ function ReaderPaging:onTapBackward()
return true return true
end end
-- wrapper for bounds checking
function ReaderPaging:gotoPage(number)
if number == self.current_page then
return true
end
if number > self.number_of_pages
or number < 1 then
DEBUG("wrong page number: "..number.."!")
return false
end
DEBUG("going to page number", number)
-- this is an event to allow other controllers to be aware of this change
self.ui:handleEvent(Event:new("PageUpdate", number))
return true
end
function ReaderPaging:onZoomModeUpdate(new_mode) function ReaderPaging:onZoomModeUpdate(new_mode)
-- we need to remember zoom mode to handle page turn event -- we need to remember zoom mode to handle page turn event
self.zoom_mode = new_mode self.zoom_mode = new_mode
@ -232,3 +217,30 @@ function ReaderPaging:onRedrawCurrentPage()
self.ui:handleEvent(Event:new("PageUpdate", self.current_page)) self.ui:handleEvent(Event:new("PageUpdate", self.current_page))
return true return true
end end
function ReaderPaging:onSetDimensions()
-- update listening according to new screen dimen
if Device:isTouchDevice() then
self:initGesListener()
end
end
-- wrapper for bounds checking
function ReaderPaging:gotoPage(number)
if number == self.current_page then
return true
end
if number > self.number_of_pages
or number < 1 then
DEBUG("wrong page number: "..number.."!")
return false
end
DEBUG("going to page number", number)
-- this is an event to allow other controllers to be aware of this change
self.ui:handleEvent(Event:new("PageUpdate", number))
return true
end

@ -14,32 +14,7 @@ ReaderRolling = InputContainer:new{
} }
function ReaderRolling:init() function ReaderRolling:init()
if Device:isTouchDevice() then if Device:hasKeyboard() then
self.ges_events = {
TapForward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = Screen:getWidth()/4,
y = Screen:getHeight()/4,
w = 3*Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
},
TapBackward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0,
y = Screen:getHeight()/4,
w = Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
}
}
else
self.key_events = { self.key_events = {
GotoNextView = { GotoNextView = {
{ Input.group.PgFwd }, { Input.group.PgFwd },
@ -89,6 +64,34 @@ function ReaderRolling:init()
self.old_page = self.ui.document.info.number_of_pages self.old_page = self.ui.document.info.number_of_pages
end end
-- This method will be called in onSetDimensions handler
function ReaderRolling:initGesListener()
self.ges_events = {
TapForward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = Screen:getWidth()/4,
y = Screen:getHeight()/4,
w = 3*Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
},
TapBackward = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0,
y = Screen:getHeight()/4,
w = Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
}
}
end
function ReaderRolling:onReadSettings(config) function ReaderRolling:onReadSettings(config)
local soe = config:readSetting("show_overlap_enable") local soe = config:readSetting("show_overlap_enable")
if not soe then if not soe then
@ -223,6 +226,13 @@ function ReaderRolling:onRedrawCurrentView()
return true return true
end end
function ReaderRolling:onSetDimensions()
-- update listening according to new screen dimen
if Device:isTouchDevice() then
self:initGesListener()
end
end
--[[ --[[
PosUpdate event is used to signal other widgets that pos has been changed. PosUpdate event is used to signal other widgets that pos has been changed.
--]] --]]

@ -1,4 +1,5 @@
ReaderView = WidgetContainer:new{ ReaderView = WidgetContainer:new{
_name = "ReaderView",
document = nil, document = nil,
state = { state = {

@ -1,46 +1,4 @@
ReaderZooming = InputContainer:new{ ReaderZooming = InputContainer:new{
key_events = {
ZoomIn = {
{ "Shift", Input.group.PgFwd },
doc = "zoom in",
event = "Zoom", args = "in"
},
ZoomOut = {
{ "Shift", Input.group.PgBack },
doc = "zoom out",
event = "Zoom", args = "out"
},
ZoomToFitPage = {
{ "A" },
doc = "zoom to fit page",
event = "SetZoomMode", args = "page"
},
ZoomToFitContent = {
{ "Shift", "A" },
doc = "zoom to fit content",
event = "SetZoomMode", args = "content"
},
ZoomToFitPageWidth = {
{ "S" },
doc = "zoom to fit page width",
event = "SetZoomMode", args = "pagewidth"
},
ZoomToFitContentWidth = {
{ "Shift", "S" },
doc = "zoom to fit content width",
event = "SetZoomMode", args = "contentwidth"
},
ZoomToFitPageHeight = {
{ "D" },
doc = "zoom to fit page height",
event = "SetZoomMode", args = "pageheight"
},
ZoomToFitContentHeight = {
{ "Shift", "D" },
doc = "zoom to fit content height",
event = "SetZoomMode", args = "contentheight"
},
},
zoom = 1.0, zoom = 1.0,
-- default to nil so we can trigger ZoomModeUpdate events on start up -- default to nil so we can trigger ZoomModeUpdate events on start up
zoom_mode = nil, zoom_mode = nil,
@ -50,6 +8,50 @@ ReaderZooming = InputContainer:new{
} }
function ReaderZooming:init() function ReaderZooming:init()
if Device:hasKeyboard() then
self.key_events = {
ZoomIn = {
{ "Shift", Input.group.PgFwd },
doc = "zoom in",
event = "Zoom", args = "in"
},
ZoomOut = {
{ "Shift", Input.group.PgBack },
doc = "zoom out",
event = "Zoom", args = "out"
},
ZoomToFitPage = {
{ "A" },
doc = "zoom to fit page",
event = "SetZoomMode", args = "page"
},
ZoomToFitContent = {
{ "Shift", "A" },
doc = "zoom to fit content",
event = "SetZoomMode", args = "content"
},
ZoomToFitPageWidth = {
{ "S" },
doc = "zoom to fit page width",
event = "SetZoomMode", args = "pagewidth"
},
ZoomToFitContentWidth = {
{ "Shift", "S" },
doc = "zoom to fit content width",
event = "SetZoomMode", args = "contentwidth"
},
ZoomToFitPageHeight = {
{ "D" },
doc = "zoom to fit page height",
event = "SetZoomMode", args = "pageheight"
},
ZoomToFitContentHeight = {
{ "Shift", "D" },
doc = "zoom to fit content height",
event = "SetZoomMode", args = "contentheight"
},
}
end
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
end end

@ -40,18 +40,42 @@ Codes for rotation modes:
Screen = { Screen = {
cur_rotation_mode = 0, width = 0,
-- these two variabls are used to help switching from framework to reader height = 0,
pitch = 0,
native_rotation_mode = nil, native_rotation_mode = nil,
kpv_rotation_mode = nil, cur_rotation_mode = 0,
bb = nil,
saved_bb = nil, saved_bb = nil,
fb = einkfb.open("/dev/fb0") fb = einkfb.open("/dev/fb0"),
} }
function Screen:init()
_, self.height = self.fb:getSize()
-- for unknown strange reason, pitch*2 is less than screen width in KPW
-- so we need to calculate width by pitch here
self.width = self.fb:getPitch()*2
self.pitch = self:getPitch()
self.bb = Blitbuffer.new(self.width, self.height, self.pitch)
self.native_rotation_mode = self.fb:getOrientation()
self.cur_rotation_mode = self.native_rotation_mode
end
function Screen:refresh(refesh_type)
if self.native_rotation_mode == self.cur_rotation_mode then
self.fb.bb:blitFrom(self.bb, 0, 0, 0, 0, self.width, self.height)
elseif self.native_rotation_mode == 0 and self.cur_rotation_mode == 1 then
self.fb.bb:blitFromRotate(self.bb, 270)
end
self.fb:refresh(refesh_type)
end
-- @orien: 1 for clockwise rotate, -1 for anti-clockwise -- @orien: 1 for clockwise rotate, -1 for anti-clockwise
-- Remember to reread screen resolution after this function call -- Remember to reread screen resolution after this function call
-- WARNING: this method is deprecated!!! use setRotationMode() or
-- setViewMode() instead.
function Screen:screenRotate(orien) function Screen:screenRotate(orien)
if orien == "clockwise" then if orien == "clockwise" then
orien = -1 orien = -1
@ -70,22 +94,19 @@ function Screen:screenRotate(orien)
end end
function Screen:getSize() function Screen:getSize()
local w, h = self.fb:getSize() return Geom:new{w = self.width, h = self.height}
return Geom:new{w = w, h = h}
end end
function Screen:getWidth() function Screen:getWidth()
local w, _ = self.fb:getSize() return self.width
return w
end end
function Screen:getHeight() function Screen:getHeight()
local _, h = self.fb:getSize() return self.height
return h
end end
function Screen:getPitch() function Screen:getPitch()
return self.fb:getPitch() return self.ptich
end end
function Screen:updateRotationMode() function Screen:updateRotationMode()
@ -94,7 +115,46 @@ function Screen:updateRotationMode()
end end
function Screen:setRotationMode(mode) function Screen:setRotationMode(mode)
self.fb:setOrientation(Screen.native_rotation_mode) -- mode 0 and mode 2 has the same width and height, so do mode 1 and 3
if (self.cur_rotation_mode % 2) ~= (mode % 2) then
self.width, self.height = self.height, self.width
end
self.cur_rotation_mode = mode
self.bb:free()
self.pitch = self.width/2
self.bb = Blitbuffer.new(self.width, self.height, self.pitch)
end
function Screen:setViewMode(mode)
if mode == "portrait" then
if self.cur_rotation_mode ~= 0 then
self:setRotationMode(0)
end
elseif mode == "landscape" then
if self.cur_rotation_mode ~= 1 then
self:setRotationMode(1)
end
end
end
--[[
@brief change gesture's x and y coordinates according to screen view mode
@param ges gesture that you want to adjust
@return adjusted gesture.
--]]
function Screen:adjustGesCoordinate(ges)
-- we do nothing is screen is not rotated
if self.native_rotation_mode == self.cur_rotation_mode then
return ges
end
if self.native_rotation_mode == 0 and self.cur_rotation_mode == 1 then
ges.pos.x, ges.pos.y = (self.width - ges.pos.y), (ges.pos.x)
end
return ges
end end
function Screen:saveCurrentBB() function Screen:saveCurrentBB()

@ -5,9 +5,9 @@ require "ui/widget"
require "ui/screen" require "ui/screen"
require "settings" -- for DEBUG(), TODO: put DEBUG() somewhere else require "settings" -- for DEBUG(), TODO: put DEBUG() somewhere else
-- initialize output module, this must be initialized before Input
Screen:init()
-- initialize the input handling -- initialize the input handling
Input:init() Input:init()
@ -164,7 +164,7 @@ function UIManager:run()
local dirty = false local dirty = false
for _, widget in ipairs(self._window_stack) do for _, widget in ipairs(self._window_stack) do
if self.repaint_all or self._dirty[widget.widget] then if self.repaint_all or self._dirty[widget.widget] then
widget.widget:paintTo(Screen.fb.bb, widget.x, widget.y) widget.widget:paintTo(Screen.bb, widget.x, widget.y)
if self._dirty[widget.widget] == "full" then if self._dirty[widget.widget] == "full" then
self.refresh_type = 0 self.refresh_type = 0
end end
@ -178,7 +178,7 @@ function UIManager:run()
if dirty then if dirty then
-- refresh FB -- refresh FB
Screen.fb:refresh(self.refresh_type) -- TODO: refresh explicitly only repainted area Screen:refresh(self.refresh_type) -- TODO: refresh explicitly only repainted area
-- reset refresh_type -- reset refresh_type
self.refresh_type = 1 self.refresh_type = 1
end end
@ -204,7 +204,7 @@ function UIManager:run()
-- delegate input_event to handler -- delegate input_event to handler
if input_event then if input_event then
DEBUG(input_event) DEBUG("in ui.lua:", input_event)
if input_event == "IntoSS" then if input_event == "IntoSS" then
Device:intoScreenSaver() Device:intoScreenSaver()
elseif input_event == "OutOfSS" then elseif input_event == "OutOfSS" then

Loading…
Cancel
Save