Refactoring hardware abstraction

This is a major overhaul of the hardware abstraction layer.
A few notes:

General platform distinction happens in
  frontend/device.lua
which will delegate everything else to
  frontend/device/<platform_name>/device.lua
which should extend
  frontend/device/generic/device.lua

Screen handling is implemented in
  frontend/device/screen.lua
which includes the *functionality* to support device specifics.
Actually setting up the device specific functionality, however,
is done in the device specific setup code in the relevant
device.lua file.

The same goes for input handling.
pull/1076/head
Hans-Werner Hilse 10 years ago
parent 47e65af4ed
commit 3066c86e38

@ -11,9 +11,9 @@ local ButtonDialog = require("ui/widget/buttondialog")
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Font = require("ui/font")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Device = require("device")
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")
@ -177,7 +177,7 @@ function FileManager:getDefaultDir()
return "/mnt/us/documents"
elseif Device:isKobo() then
return "/mnt/onboard"
elseif Device.isAndroid then
elseif Device.isAndroid() then
return "/sdcard"
else
return "."

@ -5,7 +5,7 @@ local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local DocSettings = require("docsettings")
local Menu = require("ui/widget/menu")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DEBUG = require("dbg")
local _ = require("gettext")

@ -4,10 +4,10 @@ local ConfirmBox = require("ui/widget/confirmbox")
local InfoMessage = require("ui/widget/infomessage")
local OTAManager = require("ui/otamanager")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Language = require("ui/language")
local DEBUG = require("dbg")
local _ = require("gettext")
@ -120,7 +120,7 @@ function FileManagerMenu:setUpdateItemTable()
table.insert(self.tab_item_table.setting, {
text = _("Screen settings"),
sub_item_table = {
Screen:getDPIMenuTable(),
require("ui/elements/screen_dpi_menu_table"),
UIManager:getRefreshMenuTable(),
},
})

@ -6,7 +6,7 @@ local InfoMessage = require("ui/widget/infomessage")
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Menu = require("ui/widget/menu")
local Screen = require("ui/screen")
local Screen = require("device").screen
local util = require("ffi/util")
local Font = require("ui/font")
local DEBUG = require("dbg")

@ -5,7 +5,7 @@ local InputDialog = require("ui/widget/inputdialog")
local MultiInputDialog = require("ui/widget/multiinputdialog")
local ConfirmBox = require("ui/widget/confirmbox")
local CenterContainer = require("ui/widget/container/centercontainer")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Menu = require("ui/widget/menu")
local Font = require("ui/font")
local util = require("ffi/util")

@ -10,7 +10,7 @@ local TextWidget = require("ui/widget/textwidget")
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Font = require("ui/font")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Event = require("ui/event")
local DEBUG = require("dbg")

@ -1,12 +1,12 @@
local EventListener = require("ui/widget/eventlistener")
local Device = require("ui/device")
local Device = require("device")
local util = require("ffi/util")
-- lipc
local ReaderActivityIndicator = EventListener:new{}
function ReaderActivityIndicator:init()
local dev_mod = Device:getModel()
local dev_mod = Device.model
if dev_mod == "KindlePaperWhite" or dev_mod == "KindlePaperWhite2" or dev_mod == "KindleTouch" then
require "liblipclua"
self.lipc_handle = lipc.init("com.github.koreader.activityindicator")

@ -1,10 +1,10 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local Menu = require("ui/widget/menu")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local UIManager = require("ui/uimanager")
local Event = require("ui/event")
local Font = require("ui/font")

@ -1,9 +1,9 @@
local ConfigDialog = require("ui/widget/configdialog")
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local UIManager = require("ui/uimanager")
local _ = require("gettext")

@ -2,7 +2,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Screen = require("ui/screen")
local Screen = require("device").screen
local LeftContainer = require("ui/widget/container/leftcontainer")
local RightContainer = require("ui/widget/container/rightcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")

@ -2,7 +2,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local DictQuickLookup = require("ui/widget/dictquicklookup")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local JSON = require("JSON")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -3,9 +3,9 @@ local RightContainer = require("ui/widget/container/rightcontainer")
local ImageWidget = require("ui/widget/imagewidget")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local ReaderDogear = InputContainer:new{}

@ -2,9 +2,9 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local ImageWidget = require("ui/widget/imagewidget")
local GestureRange = require("ui/gesturerange")
local Device = require("ui/device")
local Device = require("device")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local ReaderFlipping = InputContainer:new{

@ -3,12 +3,12 @@ local CenterContainer = require("ui/widget/container/centercontainer")
local Notification = require("ui/widget/notification")
local ConfirmBox = require("ui/widget/confirmbox")
local Menu = require("ui/widget/menu")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Input = require("ui/input")
local Device = require("device")
local Screen = require("device").screen
local Input = require("device").input
local Event = require("ui/event")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DEBUG = require("dbg")
local _ = require("gettext")

@ -8,8 +8,8 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
local TextWidget = require("ui/widget/textwidget")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Font = require("ui/font")

@ -4,8 +4,8 @@ local Notification = require("ui/widget/notification")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local DEBUG = require("dbg")
local _ = require("gettext")
@ -20,7 +20,7 @@ function ReaderFrontLight:init()
Adjust = {
GestureRange:new{
ges = "two_finger_pan",
rate = Device:getModel() ~= 'Kobo_phoenix' and 3.0 or nil,
rate = Device.model ~= 'Kobo_phoenix' and 3.0 or nil,
}
},
PanRelease= {

@ -1,7 +1,7 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -1,8 +1,8 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local Event = require("ui/event")
local UIManager = require("ui/uimanager")
local ButtonDialog = require("ui/widget/buttondialog")

@ -3,8 +3,8 @@ local GestureRange = require("ui/gesturerange")
local LinkBox = require("ui/widget/linkbox")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -6,10 +6,10 @@ local ConfirmBox = require("ui/widget/confirmbox")
local GestureRange = require("ui/gesturerange")
local OTAManager = require("ui/otamanager")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Language = require("ui/language")
local DEBUG = require("dbg")
local _ = require("gettext")
@ -93,7 +93,7 @@ function ReaderMenu:setUpdateItemTable()
table.insert(self.tab_item_table.setting, {
text = _("Screen settings"),
sub_item_table = {
Screen:getDPIMenuTable(),
require("ui/elements/screen_dpi_menu_table"),
UIManager:getRefreshMenuTable(),
},
})

@ -1,9 +1,9 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Input = require("ui/input")
local Input = require("device").input
local GestureRange = require("ui/gesturerange")
local Device = require("ui/device")
local Device = require("device")
local Event = require("ui/event")
local UIManager = require("ui/uimanager")
local Math = require("optmath")

@ -1,5 +1,5 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("ui/device")
local Device = require("device")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -1,9 +1,9 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local ReaderPanning = require("apps/reader/modules/readerpanning")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local Geom = require("ui/geometry")
local Input = require("ui/input")
local Input = require("device").input
local Event = require("ui/event")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")

@ -1,7 +1,7 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Device = require("device")
local Event = require("ui/event")
local GestureRange = require("ui/gesturerange")
local _ = require("gettext")

@ -1,6 +1,6 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local InfoMessage = require("ui/widget/infomessage")

@ -5,8 +5,8 @@ local Button = require("ui/widget/button")
local UIManager = require("ui/uimanager")
local Menu = require("ui/widget/menu")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local Event = require("ui/event")
local Font = require("ui/font")
local DEBUG = require("dbg")

@ -2,7 +2,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local ConfirmBox = require("ui/widget/confirmbox")
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -3,7 +3,7 @@ local ReaderFooter = require("apps/reader/modules/readerfooter")
local ReaderDogear = require("apps/reader/modules/readerdogear")
local OverlapGroup = require("ui/widget/overlapgroup")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Event = require("ui/event")
local DEBUG = require("dbg")

@ -5,7 +5,7 @@ local Translator = require("ui/translator")
local Wikipedia = require("ui/wikipedia")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local JSON = require("JSON")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -2,9 +2,9 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local ConfirmBox = require("ui/widget/confirmbox")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Device = require("device")
local Input = require("device").input
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Event = require("ui/event")
local DEBUG = require("dbg")

@ -6,8 +6,8 @@ local lfs = require("libs/libkoreader-lfs")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Event = require("ui/event")
local Cache = require("cache")
local DEBUG = require("dbg")

@ -0,0 +1,29 @@
local isAndroid, android = pcall(require, "android")
local util = require("ffi/util")
local function probeDevice()
if util.isEmulated() then
return require("device/emulator/device")
end
if isAndroid then
return require("device/android/device")
end
local kindle_sn = io.open("/proc/usid", "r")
if kindle_sn then
kindle_sn:close()
return require("device/kindle/device")
end
local kg_test_fd = lfs.attributes("/bin/kobo_config.sh")
if kg_test_fd then
return require("device/kobo/device")
end
error("did not find a hardware abstraction for this platform")
end
local dev = probeDevice()
dev:init()
return dev

@ -0,0 +1,43 @@
local Generic = require("device/generic/device")
local isAndroid, android = pcall(require, "android")
local ffi = require("ffi")
local function yes() return true end
local Device = Generic:new{
model = "Android",
isAndroid = yes,
firmware_rev = "none",
display_dpi = ffi.C.AConfiguration_getDensity(android.app.config),
}
function Device:init()
self.screen = require("device/screen"):new{device = self}
self.powerd = require("device/android/powerd"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/android/event_map"),
handleMiscEv = function(self, ev)
if ev.code == ffi.C.APP_CMD_SAVE_STATE then
return "SaveState"
end
end,
}
-- check if we have a keyboard
if ffi.C.AConfiguration_getKeyboard(android.app.config)
== ffi.C.ACONFIGURATION_KEYBOARD_QWERTY
then
self.hasKeyboard = yes
end
-- check if we have a touchscreen
if ffi.C.AConfiguration_getTouchscreen(android.app.config)
~= ffi.C.ACONFIGURATION_TOUCHSCREEN_NOTOUCH
then
self.isTouchDevice = yes
end
Generic:init()
end
return Device

@ -0,0 +1,33 @@
return {
[29] = "A", [30] = "B", [31] = "C", [32] = "D", [33] = "E", [34] = "F",
[35] = "G", [36] = "H", [37] = "I", [38] = "J", [39] = "K", [40] = "L",
[41] = "M", [42] = "N", [43] = "O", [44] = "P", [45] = "Q", [46] = "R",
[47] = "S", [48] = "T", [49] = "U", [50] = "V", [51] = "W", [52] = "X",
[53] = "Y", [54] = "Z", [ 7] = "0", [ 8] = "1", [ 9] = "2", [10] = "3",
[11] = "4", [12] = "5", [13] = "6", [14] = "7", [15] = "8", [16] = "9",
[4] = "Back", -- BACK
[19] = "Up", -- DPAD_UP
[20] = "Down", -- DPAD_UP
[21] = "Left", -- DPAD_LEFT
[22] = "Right", -- DPAD_RIGHT
[23] = "Press", -- DPAD_CENTER
[24] = "LPgBack", -- VOLUME_UP
[25] = "LPgFwd", -- VOLUME_DOWN
[56] = ".", -- PERIOD
[59] = "Shift", -- SHIFT_LEFT
[60] = "Shift", -- SHIFT_RIGHT
[62] = " ", -- SPACE
[63] = "Sym", -- SYM
[66] = "Enter", -- ENTER
[67] = "Del", -- DEL
[76] = "/", -- SLASH
[82] = "Menu", -- MENU
[84] = "Search",--SEARCH
[92] = "LPgBack", -- PAGE_UP
[93] = "LPgFwd", -- PAGE_DOWN
[104] = "LPgBack", -- T68 PageUp
[109] = "LPgFwd", -- T68 PageDown
[139] = "Menu", -- T68 Menu
}

@ -1,4 +1,4 @@
local BasePowerD = require("ui/device/basepowerd")
local BasePowerD = require("device/generic/powerd")
local AndroidPowerD = BasePowerD:new{
batt_capacity_file = "/sys/class/power_supply/battery/capacity",

@ -0,0 +1,29 @@
local Generic = require("device/generic/device")
local util = require("ffi/util")
local Geom = require("ui/geometry")
local function yes() return true end
local Device = Generic:new{
model = "Emulator",
isEmulator = yes,
hasKeyboard = yes,
hasKeys = yes,
hasFrontlight = yes,
isTouchDevice = yes,
viewport = Geom:new{x=40, y=40, w=550, h=650},
}
function Device:init()
self.screen = require("device/screen"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = util.haveSDL2()
and require("device/emulator/event_map_sdl2")
or require("device/emulator/event_map_sdl"),
}
Generic.init(self)
end
return Device

@ -0,0 +1,31 @@
return {
[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",
[38] = "A", [39] = "S", [40] = "D", [41] = "F", [42] = "G", [43] = "H", [44] = "J", [45] = "K", [46] = "L",
[52] = "Z", [53] = "X", [54] = "C", [55] = "V", [56] = "B", [57] = "N", [58] = "M",
[22] = "Back", -- Backspace
[36] = "Enter", -- Enter
[50] = "Shift", -- left shift
[60] = ".",
[61] = "/",
[62] = "Sym", -- right shift key
[64] = "Alt", -- left alt
[65] = " ", -- Spacebar
[67] = "Menu", -- F[1]
[68] = "Power", -- F[2]
[72] = "LPgBack", -- F[6]
[73] = "LPgFwd", -- F[7]
[95] = "VPlus", -- F[11]
[96] = "VMinus", -- F[12]
[105] = "AA", -- right alt key
[110] = "Home", -- Home
[111] = "Up", -- arrow up
[112] = "RPgBack", -- normal PageUp
[113] = "Left", -- arrow left
[114] = "Right", -- arrow right
[115] = "Press", -- End (above arrows)
[116] = "Down", -- arrow down
[117] = "RPgFwd", -- normal PageDown
[119] = "Del", -- Delete
}

@ -0,0 +1,33 @@
return {
[ 4] = "A", [ 5] = "B", [ 6] = "C", [ 7] = "D", [ 8] = "E", [ 9] = "F",
[10] = "G", [11] = "H", [12] = "I", [13] = "J", [14] = "K", [15] = "L",
[16] = "M", [17] = "N", [18] = "O", [19] = "P", [20] = "Q", [21] = "R",
[22] = "S", [23] = "T", [24] = "U", [25] = "V", [26] = "W", [27] = "X",
[28] = "Y", [29] = "Z", [30] = "1", [31] = "2", [32] = "3", [33] = "4",
[34] = "5", [35] = "6", [36] = "7", [37] = "8", [38] = "9", [39] = "0",
[42] = "Back", -- Backspace
[40] = "Enter", -- Enter
[225] = "Shift", -- left shift
[55] = ".",
[56] = "/",
[229] = "Sym", -- right shift key
[226] = "Alt", -- left alt
[44] = " ", -- Spacebar
[58] = "Menu", -- F[1]
[59] = "Power", -- F[2]
[63] = "LPgBack", -- F[6]
[64] = "LPgFwd", -- F[7]
[68] = "VPlus", -- F[11]
[69] = "VMinus", -- F[12]
[230] = "AA", -- right alt key
[74] = "Home", -- Home
[82] = "Up", -- arrow up
[75] = "RPgBack", -- normal PageUp
[80] = "Left", -- arrow left
[79] = "Right", -- arrow right
[77] = "Press", -- End (above arrows)
[81] = "Down", -- arrow down
[78] = "RPgFwd", -- normal PageDown
[76] = "Del", -- Delete
}

@ -0,0 +1,145 @@
local util = require("ffi/util")
local DEBUG = require("dbg")
local function no() return false end
local Device = {
screen_saver_mode = false,
charging_mode = false,
survive_screen_saver = false,
model = nil,
powerd = nil,
screen = nil,
input = nil,
-- hardware feature tests: (these are functions!)
hasKeyboard = no,
hasKeys = no,
isTouchDevice = no,
hasFrontlight = no,
-- use these only as a last resort. We should abstract the functionality
-- and have device dependent implementations in the corresponting
-- device/<devicetype>/device.lua file
-- (these are functions!)
isKindle = no,
isKobo = no,
isAndroid = no,
isEmulator = no,
-- some devices have part of their screen covered by the bezel
viewport = nil,
}
function Device:new(o)
local o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Device:init()
if not self.screen then
self.screen = require("device/generic/screen"):new{device = self}
end
if not self.input then
self.input = require("device/generic/input"):new{device = self}
end
if not self.powerd then
self.powerd = require("device/generic/powerd"):new{device = self}
end
if self.viewport then
self.screen:setViewport(self.viewport)
self.input:registerEventAdjustHook(
self.input.adjustTouchTranslate,
{x = 0 - self.viewport.x, y = 0 - self.viewport.y})
end
end
function Device:getPowerDevice()
return self.powerd
end
function Device:intoScreenSaver()
if self.charging_mode == false and self.screen_saver_mode == false then
self.screen:saveCurrentBB()
self.screen_saver_mode = true
end
end
function Device:outofScreenSaver()
if self.screen_saver_mode == true and self.charging_mode == false then
-- wait for native system update screen before we recover saved
-- Blitbuffer.
util.usleep(1500000)
self.screen:restoreFromSavedBB()
self.screen:refresh(0)
self.survive_screen_saver = true
end
self.screen_saver_mode = false
end
function Device:onPowerEvent(ev)
local Screensaver = require("ui/screensaver")
if (ev == "Power" or ev == "Suspend") and not self.screen_saver_mode then
local UIManager = require("ui/uimanager")
DEBUG("Suspending...")
-- always suspend in portrait mode
self.orig_rotation_mode = self.screen:getRotationMode()
self.screen:setRotationMode(0)
Screensaver:show()
self:prepareSuspend()
UIManager:scheduleIn(2, function() self:Suspend() end)
elseif (ev == "Power" or ev == "Resume") and self.screen_saver_mode then
DEBUG("Resuming...")
-- restore to previous rotation mode
self.screen:setRotationMode(self.orig_rotation_mode)
self:Resume()
Screensaver:close()
end
end
function Device:prepareSuspend()
if self.powerd and self.powerd.fl ~= nil then
-- in no case should the frontlight be turned on in suspend mode
self.powerd.fl:sleep()
end
self.screen:refresh(0)
self.screen_saver_mode = true
end
function Device:Suspend()
end
function Device:Resume()
self.screen:refresh(1)
self.screen_saver_mode = false
end
function Device:usbPlugIn()
if self.charging_mode == false and self.screen_saver_mode == false then
self.screen:saveCurrentBB()
end
self.charging_mode = true
end
function Device:usbPlugOut()
if self.charging_mode == true and self.screen_saver_mode == false then
self.screen:restoreFromSavedBB()
self.screen:refresh(0)
end
--@TODO signal filemanager for file changes 13.06 2012 (houqp)
self.charging_mode = false
end
--[[
prepare for application shutdown
--]]
function Device:exit()
require("ffi/input"):closeAll()
self.screen:close()
end
return Device

@ -3,7 +3,7 @@ local BasePowerD = {
fl_max = 10, -- max frontlight intensity
flIntensity = nil, -- frontlight intensity
battCapacity = nil, -- battery capacity
model = nil, -- device model
device = nil, -- device object
capacity_pulled_count = 0,
capacity_cached_count = 10,

@ -1,6 +1,5 @@
local Geom = require("ui/geometry")
local TimeVal = require("ui/timeval")
local Screen = require("ui/screen")
local DEBUG = require("dbg")
--[[
@ -49,10 +48,6 @@ local GestureDetector = {
TWO_FINGER_TAP_DURATION = 300 * 1000,
HOLD_INTERVAL = 500 * 1000,
SWIPE_INTERVAL = 900 * 1000,
-- distance parameters
DOUBLE_TAP_DISTANCE = 50 * Screen:getDPI() / 167,
TWO_FINGER_TAP_REGION = 20 * Screen:getDPI() / 167,
PAN_THRESHOLD = 50 * Screen:getDPI() / 167,
-- pinch/spread direction table
DIRECTION_TABLE = {
east = "horizontal",
@ -77,6 +72,21 @@ local GestureDetector = {
last_taps = {},
}
function GestureDetector:new(o)
local o = o or {}
setmetatable(o, self)
self.__index = self
if o.init then o:init() end
return o
end
function GestureDetector:init()
-- distance parameters
self.DOUBLE_TAP_DISTANCE = 50 * self.screen:getDPI() / 167
self.TWO_FINGER_TAP_REGION = 20 * self.screen:getDPI() / 167
self.PAN_THRESHOLD = 50 * self.screen:getDPI() / 167
end
function GestureDetector:feedEvent(tevs)
repeat
local tev = table.remove(tevs)
@ -584,10 +594,10 @@ end
@return adjusted gesture.
--]]
function GestureDetector:adjustGesCoordinate(ges)
if Screen.cur_rotation_mode == 1 then
if self.screen.cur_rotation_mode == 1 then
-- in landscape mode rotated 270
if ges.pos then
ges.pos.x, ges.pos.y = (Screen:getWidth() - ges.pos.y), (ges.pos.x)
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 == "two_finger_swipe"
@ -621,10 +631,10 @@ function GestureDetector:adjustGesCoordinate(ges)
ges.direction = "horizontal"
end
end
elseif Screen.cur_rotation_mode == 3 then
elseif self.screen.cur_rotation_mode == 3 then
-- in landscape mode rotated 90
if ges.pos then
ges.pos.x, ges.pos.y = (ges.pos.y), (Screen:getHeight() - ges.pos.x)
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 == "two_finger_swipe"

@ -0,0 +1,508 @@
local Event = require("ui/event")
local TimeVal = require("ui/timeval")
local input = require("ffi/input")
local util = require("ffi/util")
local Math = require("optmath")
local DEBUG = require("dbg")
local ffi = require("ffi")
local _ = require("gettext")
local Key = require("device/key")
local GestureDetector = require("device/gesturedetector")
-- constants from <linux/input.h>
local EV_SYN = 0
local EV_KEY = 1
local EV_ABS = 3
local EV_MSC = 4
-- key press event values (KEY.value)
local EVENT_VALUE_KEY_PRESS = 1
local EVENT_VALUE_KEY_REPEAT = 2
local EVENT_VALUE_KEY_RELEASE = 0
-- Synchronization events (SYN.code).
local SYN_REPORT = 0
local SYN_CONFIG = 1
local SYN_MT_REPORT = 2
-- For single-touch events (ABS.code).
local ABS_X = 00
local ABS_Y = 01
local ABS_PRESSURE = 24
-- For multi-touch events (ABS.code).
local ABS_MT_SLOT = 47
local ABS_MT_TOUCH_MAJOR = 48
local ABS_MT_WIDTH_MAJOR = 50
local ABS_MT_POSITION_X = 53
local ABS_MT_POSITION_Y = 54
local ABS_MT_TRACKING_ID = 57
local ABS_MT_PRESSURE = 58
--[[
an interface to get input events
]]
local Input = {
-- this depends on keyboard layout and should be overridden:
event_map = {},
group = {
Cursor = { "Up", "Down", "Left", "Right" },
PgFwd = { "RPgFwd", "LPgFwd" },
PgBack = { "RPgBack", "LPgBack" },
Alphabet = {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
AlphaNumeric = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
Numeric = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
},
Text = {
" ", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
Any = {
" ", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"Up", "Down", "Left", "Right", "Press",
"Back", "Enter", "Sym", "AA", "Menu", "Home", "Del",
"LPgBack", "RPgBack", "LPgFwd", "RPgFwd"
},
},
rotation_map = {
[0] = {},
[1] = { Up = "Right", Right = "Down", Down = "Left", Left = "Up" },
[2] = { Up = "Down", Right = "Left", Down = "Up", Left = "Right" },
[3] = { Up = "Left", Right = "Up", Down = "Right", Left = "Down" }
},
timer_callbacks = {},
disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP,
-- keyboard state:
modifiers = {
Alt = false,
Shift = false,
},
-- touch state:
cur_slot = 0,
MTSlots = {},
ev_slots = {
[0] = {
slot = 0,
}
},
gesture_detector = nil,
}
function Input:new(o)
local o = o or {}
setmetatable(o, self)
self.__index = self
if o.init then o:init() end
return o
end
function Input:init()
self.gesture_detector = GestureDetector:new{
screen = self.device.screen,
input = self,
}
-- 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"
end
--[[
Different device models can implement their own hooks
and register them.
--]]
function Input:registerEventAdjustHook(hook, hook_params)
local old = self.eventAdjustHook
self.eventAdjustHook = function(self, ev)
old(self, ev)
hook(self, ev, hook_params)
end
end
function Input:eventAdjustHook(ev)
-- do nothing by default
end
-- catalogue of predefined hooks:
function Input:adjustTouchSwitchXY(ev)
if ev.type == EV_ABS then
if ev.code == ABS_X then ev.code = ABS_Y end
if ev.code == ABS_Y then ev.code = ABS_X end
if ev.code == ABS_MT_POSITION_X then ev.code = ABS_MT_POSITION_Y end
if ev.code == ABS_MT_POSITION_Y then ev.code = ABS_MT_POSITION_X end
end
end
function Input:adjustTouchScale(ev, by)
if ev.type == EV_ABS then
if ev.code == ABS_X or ev.code == ABS_MT_POSITION_X then
ev.value = by.x * ev.value
end
if ev.code == ABS_Y or ev.code == ABS_MT_POSITION_Y then
ev.value = by.y * ev.value
end
end
end
function Input:adjustTouchMirrorX(ev, width)
if ev.type == EV_ABS then
if ev.code == ABS_X or ev.code == ABS_MT_POSITION_X then
ev.value = width - ev.value
end
end
end
function Input:adjustTouchMirrorY(ev, height)
if ev.type == EV_ABS then
if ev.code == ABS_Y or ev.code == ABS_MT_POSITION_Y then
ev.value = height - ev.value
end
end
end
function Input:adjustTouchTranslate(ev, by)
if ev.type == EV_ABS then
if ev.code == ABS_X or ev.code == ABS_MT_POSITION_X then
ev.value = by.x + ev.value
end
if ev.code == ABS_Y or ev.code == ABS_MT_POSITION_Y then
ev.value = by.y + ev.value
end
end
end
function Input:setTimeout(cb, tv_out)
local item = {
callback = cb,
deadline = tv_out,
}
table.insert(self.timer_callbacks, item)
table.sort(self.timer_callbacks, function(v1,v2)
return v1.deadline < v2.deadline
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.device.screen:getRotationMode()][keycode] then
keycode = self.rotation_map[self.device.screen:getRotationMode()][keycode]
end
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "Charging" or keycode == "NotCharging" then
return keycode
end
-- Kobo sleep
if keycode == "Power_SleepCover" then
if ev.value == EVENT_VALUE_KEY_PRESS then
return "Suspend"
else
return "Resume"
end
end
if ev.value == EVENT_VALUE_KEY_RELEASE
and (keycode == "Light" or keycode == "Power") 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
function Input:handleMiscEv(ev)
-- should be handled by a misc event protocol plugin
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.
From kernel document:
For type B devices, the kernel driver should associate a slot with each
identified contact, and use that slot to propagate changes for the contact.
Creation, replacement and destruction of contacts is achieved by modifying
the ABS_MT_TRACKING_ID of the associated slot. A non-negative tracking id
is interpreted as a contact, and the value -1 denotes an unused slot. A
tracking id not previously present is considered new, and a tracking id no
longer present is considered removed. Since only changes are propagated,
the full state of each initiated contact has to reside in the receiving
end. Upon receiving an MT event, one simply updates the appropriate
attribute of the current slot.
--]]
function Input:handleTouchEv(ev)
if ev.type == EV_ABS then
if #self.MTSlots == 0 then
table.insert(self.MTSlots, self:getMtSlot(self.cur_slot))
end
if ev.code == ABS_MT_SLOT then
if self.cur_slot ~= ev.value then
table.insert(self.MTSlots, self:getMtSlot(ev.value))
end
self.cur_slot = ev.value
elseif ev.code == ABS_MT_TRACKING_ID then
self:setCurrentMtSlot("id", ev.value)
elseif ev.code == ABS_MT_POSITION_X then
self:setCurrentMtSlot("x", ev.value)
elseif ev.code == ABS_MT_POSITION_Y then
self:setCurrentMtSlot("y", ev.value)
-- code to emulate mt protocol on kobos
-- we "confirm" abs_x, abs_y only when pressure ~= 0
elseif ev.code == ABS_X then
self:setCurrentMtSlot("abs_x", ev.value)
elseif ev.code == ABS_Y then
self:setCurrentMtSlot("abs_y", ev.value)
elseif ev.code == ABS_PRESSURE then
if ev.value ~= 0 then
self:setCurrentMtSlot("id", 1)
self:confirmAbsxy()
else
self:cleanAbsxy()
self:setCurrentMtSlot("id", -1)
end
end
elseif ev.type == EV_SYN then
if ev.code == SYN_REPORT then
for _, MTSlot in pairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "timev", TimeVal:new(ev.time))
end
-- feed ev in all slots to state machine
local touch_ges = self.gesture_detector:feedEvent(self.MTSlots)
self.MTSlots = {}
if touch_ges then
return Event:new("Gesture",
self.gesture_detector:adjustGesCoordinate(touch_ges)
)
end
end
end
end
function Input:handleTouchEvPhoenix(ev)
-- Hack on handleTouchEV for the Kobo Aura
-- It seems to be using a custom protocol:
-- finger 0 down:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, x1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, y1);
-- input_mt_sync (elan_touch_data.input);
-- finger 1 down:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, x2);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, y2);
-- input_mt_sync (elan_touch_data.input);
-- finger 0 up:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, last_x);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, last_y);
-- input_mt_sync (elan_touch_data.input);
-- finger 1 up:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, last_x2);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, last_y2);
-- input_mt_sync (elan_touch_data.input);
if ev.type == EV_ABS then
if #self.MTSlots == 0 then
table.insert(self.MTSlots, self:getMtSlot(self.cur_slot))
end
if ev.code == ABS_MT_TRACKING_ID then
if self.cur_slot ~= ev.value then
table.insert(self.MTSlots, self:getMtSlot(ev.value))
end
self.cur_slot = ev.value
self:setCurrentMtSlot("id", ev.value)
elseif ev.code == ABS_MT_TOUCH_MAJOR and ev.value == 0 then
self:setCurrentMtSlot("id", -1)
elseif ev.code == ABS_MT_POSITION_X then
self:setCurrentMtSlot("x", ev.value)
elseif ev.code == ABS_MT_POSITION_Y then
self:setCurrentMtSlot("y", ev.value)
end
elseif ev.type == EV_SYN then
if ev.code == SYN_REPORT then
for _, MTSlot in pairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "timev", TimeVal:new(ev.time))
end
-- feed ev in all slots to state machine
local touch_ges = self.gesture_detector:feedEvent(self.MTSlots)
self.MTSlots = {}
if touch_ges then
return Event:new("Gesture",
self.gesture_detector:adjustGesCoordinate(touch_ges)
)
end
end
end
end
-- helpers for touch event data management:
function Input:setMtSlot(slot, key, val)
if not self.ev_slots[slot] then
self.ev_slots[slot] = {
slot = slot
}
end
self.ev_slots[slot][key] = val
end
function Input:setCurrentMtSlot(key, val)
self:setMtSlot(self.cur_slot, key, val)
end
function Input:getMtSlot(slot)
return self.ev_slots[slot]
end
function Input:getCurrentMtSlot()
return self:getMtSlot(self.cur_slot)
end
function Input:confirmAbsxy()
self:setCurrentMtSlot("x", self.ev_slots[self.cur_slot]["abs_x"])
self:setCurrentMtSlot("y", self.ev_slots[self.cur_slot]["abs_y"])
end
function Input:cleanAbsxy()
self:setCurrentMtSlot("abs_x", nil)
self:setCurrentMtSlot("abs_y", nil)
end
-- main event handling:
function Input:waitEvent(timeout_us, timeout_s)
-- wrapper for input.waitForEvents that will retry for some cases
local ok, ev
local wait_deadline = TimeVal:now() + TimeVal:new{
sec = timeout_s,
usec = timeout_us
}
while true do
if #self.timer_callbacks > 0 then
-- we don't block if there is any timer, set wait to 10us
while #self.timer_callbacks > 0 do
ok, ev = pcall(input.waitForEvent, 100)
if ok then break end
local tv_now = TimeVal:now()
if ((not timeout_us and not timeout_s) or tv_now < wait_deadline) then
-- check whether timer is up
if tv_now >= self.timer_callbacks[1].deadline then
local touch_ges = self.timer_callbacks[1].callback()
table.remove(self.timer_callbacks, 1)
if touch_ges then
-- Do we really need to clear all setTimeout after
-- decided a gesture? FIXME
self.timer_callbacks = {}
return Event:new("Gesture",
self.gesture_detector:adjustGesCoordinate(touch_ges)
)
end -- EOF if touch_ges
end -- EOF if deadline reached
else
break
end -- EOF if not exceed wait timeout
end -- while #timer_callbacks > 0
else
ok, ev = pcall(input.waitForEvent, timeout_us)
end -- EOF if #timer_callbacks > 0
if ok then
break
end
-- ev does contain an error message:
if ev == "Waiting for input failed: timeout\n" then
-- don't report an error on timeout
ev = nil
break
elseif ev == "application forced to quit" then
-- TODO: return an event that can be handled
os.exit(0)
end
--DEBUG("got error waiting for events:", ev)
if ev ~= "Waiting for input failed: 4\n" then
-- we only abort if the error is not EINTR
break
end
end
if ok and ev then
if DEBUG.is_on and ev then
DEBUG:logEv(ev)
end
self:eventAdjustHook(ev)
if ev.type == EV_KEY then
DEBUG("key ev", ev)
return self:handleKeyBoardEv(ev)
elseif ev.type == EV_ABS or ev.type == EV_SYN then
return self:handleTouchEv(ev)
elseif ev.type == EV_MSC then
return self:handleMiscEv(ev)
else
-- some other kind of event that we do not know yet
return Event:new("GenericInput", ev)
end
elseif not ok and ev then
return Event:new("InputError", ev)
end
end
return Input

@ -0,0 +1,91 @@
--[[
an interface for key presses
]]
local Key = {}
function Key:new(key, modifiers)
local o = { key = key, modifiers = modifiers }
-- we're a hash map, too
o[key] = true
for mod, pressed in pairs(modifiers) do
if pressed then
o[mod] = true
end
end
setmetatable(o, self)
self.__index = self
return o
end
function Key:__tostring()
return table.concat(self:getSequence(), "-")
end
--[[
get a sequence that can be matched against later
use this to let the user press a sequence and then
store this as configuration data (configurable
shortcuts)
]]
function Key:getSequence()
local seq = {}
for mod, pressed in pairs(self.modifiers) do
if pressed then
table.insert(seq, mod)
end
end
table.insert(seq, self.key)
end
--[[
this will match a key against a sequence
the sequence should be a table of key names that
must be pressed together to match.
if an entry in this table is itself a table, at
least one key in this table must match.
E.g.:
Key:match({ "Alt", "K" }) -- match Alt-K
Key:match({ "Alt", { "K", "L" }}) -- match Alt-K _or_ Alt-L
]]
function Key:match(sequence)
local mod_keys = {} -- a hash table for checked modifiers
for _, key in ipairs(sequence) do
if type(key) == "table" then
local found = false
for _, variant in ipairs(key) do
if self[variant] then
found = true
break
end
end
if not found then
-- one of the needed keys is not pressed
return false
end
elseif not self[key] then
-- needed key not pressed
return false
elseif self.modifiers[key] ~= nil then
-- checked key is a modifier key
mod_keys[key] = true
end
end
for mod, pressed in pairs(self.modifiers) do
if pressed and not mod_keys[mod] then
-- additional modifier keys are pressed, don't match
return false
end
end
return true
end
return Key

@ -0,0 +1,245 @@
local Generic = require("device/generic/device")
local DEBUG = require("dbg")
local function yes() return true end
local Kindle = Generic:new{
model = "Kindle",
isKindle = yes,
}
local Kindle2 = Kindle:new{
model = "Kindle2",
hasKeyboard = yes,
hasKeys = yes,
}
local KindleDXG = Kindle:new{
model = "KindleDXG",
hasKeyboard = yes,
hasKeys = yes,
}
local Kindle3 = Kindle2:new{
model = "Kindle3",
hasKeyboard = yes,
hasKeys = yes,
}
local Kindle4 = Kindle:new{
model = "Kindle4",
hasKeys = yes,
}
local KindleTouch = Kindle:new{
model = "KindleTouch",
isTouchDevice = yes,
touch_dev = "/dev/input/event3",
}
local KindlePaperWhite = Kindle:new{
model = "KindlePaperWhite",
isTouchDevice = yes,
hasFrontlight = yes,
display_dpi = 212,
touch_dev = "/dev/input/event0",
}
local KindlePaperWhite2 = Kindle:new{
model = "KindlePaperWhite2",
isTouchDevice = yes,
hasFrontlight = yes,
display_dpi = 212,
touch_dev = "/dev/input/event1",
}
function Kindle2:init()
self.screen = require("device/screen"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/kindle/event_map_keyboard"),
}
self.input.open("/dev/input/event1")
Kindle.init(self)
end
function KindleDXG:init()
self.screen = require("device/screen"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/kindle/event_map_keyboard"),
}
self.input.open("/dev/input/event0")
self.input.open("/dev/input/event1")
Kindle.init(self)
end
function Kindle3:init()
self.screen = require("device/screen"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/kindle/event_map_keyboard"),
}
self.input.open("/dev/input/event1")
self.input.open("/dev/input/event2")
Kindle.init(self)
end
function Kindle4:init()
self.screen = require("device/screen"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = require("device/kindle/event_map_kindle4"),
}
self.input.event_map = require("device/kindle/event_map_kindle4")
self.input.open("/dev/input/event1")
Kindle.init(self)
end
local ABS_MT_POSITION_X = 53
local ABS_MT_POSITION_Y = 54
function KindleTouch:init()
self.screen = require("device/screen"):new{device = self}
self.powerd = require("device/kindle/powerd"):new{
device = self,
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
is_charging_file = "/sys/devices/platform/fsl-usb2-udc/charging",
}
self.input = require("device/input"):new{
device = self,
-- Kindle Touch has a single button
event_map = { [102] = "Home" },
}
-- Kindle Touch needs event modification for proper coordinates
self.input:registerEventAdjustHook(self.input.adjustTouchScale, {x=600/4095, y=800/4095})
-- event0 in KindleTouch is "WM8962 Beep Generator" (useless)
-- event1 in KindleTouch is "imx-yoshi Headset" (useless)
self.input.open("/dev/input/event2") -- Home button
self.input.open("/dev/input/event3") -- touchscreen
Kindle.init(self)
end
function KindlePaperWhite:init()
self.screen = require("device/screen"):new{device = self}
self.powerd = require("device/kindle/powerd"):new{
device = self,
fl_intensity_file = "/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity",
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
is_charging_file = "/sys/devices/platform/aplite_charger.0/charging",
}
Kindle.init(self)
self.input.open("/dev/input/event0")
end
function KindlePaperWhite2:init()
self.screen = require("device/screen"):new{device = self}
self.powerd = require("device/kindle/powerd"):new{
device = self,
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
is_charging_file = "/sys/devices/platform/aplite_charger.0/charging",
}
Kindle.init(self)
self.input.open("/dev/input/event1")
end
--[[
Test if a kindle device has Special Offers
--]]
local function isSpecialOffers()
-- Look at the current blanket modules to see if the SO screensavers are enabled...
local lipc = require("liblipclua")
if not lipc then
DEBUG("could not load liblibclua")
return false
end
local lipc_handle = lipc.init("com.github.koreader.device")
if not lipc_handle then
DEBUG("could not get lipc handle")
return false
end
local so = false
local loaded_blanket_modules = lipc_handle:get_string_property("com.lab126.blanket", "load")
if string.find(loaded_blanket_modules, "ad_screensaver") then
so = true
end
lipc_handle:close()
return so
end
function KindleTouch:exit()
if isSpecialOffers() then
-- fake a touch event
if self.touch_dev then
local width, height = Screen:getScreenWidth(), Screen:getScreenHeight()
require("ffi/input").fakeTapInput(self.touch_dev,
math.min(width, height)/2,
math.max(width, height)-30
)
end
end
Generic.exit(self)
end
KindlePaperWhite.exit = KindleTouch.exit
KindlePaperWhite2.exit = KindleTouch.exit
function Kindle3:exit()
-- send double menu key press events to trigger screen refresh
os.execute("echo 'send 139' > /proc/keypad;echo 'send 139' > /proc/keypad")
Generic.exit(self)
end
KindleDXG.exit = Kindle3.exit
----------------- device recognition: -------------------
local function Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
local kindle_sn = io.open("/proc/usid", "r")
if not kindle_sn then return end
local kindle_devcode = string.sub(kindle_sn:read(),3,4)
kindle_sn:close()
-- NOTE: Update me when new devices come out :)
local k2_set = Set { "02", "03" }
local dx_set = Set { "04", "05" }
local dxg_set = Set { "09" }
local k3_set = Set { "08", "06", "0A" }
local k4_set = Set { "0E", "23" }
local touch_set = Set { "0F", "11", "10", "12" }
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
local pw2_set = Set { "D4", "5A", "D5", "D6", "D7", "D8", "F2", "17",
"60", "F4", "F9", "62", "61", "5F" }
if k2_set[kindle_devcode] then
return Kindle2
elseif dx_set[kindle_devcode] then
return Kindle2
elseif dxg_set[kindle_devcode] then
return KindleDXG
elseif k3_set[kindle_devcode] then
return Kindle3
elseif k4_set[kindle_devcode] then
return Kindle4
elseif touch_set[kindle_devcode] then
return KindleTouch
elseif pw_set[kindle_devcode] then
return KindlePaperWhite
elseif pw2_set[kindle_devcode] then
return KindlePaperWhite2
end
error("unknown Kindle model "..kindle_devcode)

@ -0,0 +1,39 @@
--[[
event map for Kindle devices with an alphabetic and/or alphanumeric keyboard
--]]
return {
[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",
[30] = "A", [31] = "S", [32] = "D", [33] = "F", [34] = "G", [35] = "H", [36] = "J", [37] = "K", [38] = "L", [14] = "Del",
[44] = "Z", [45] = "X", [46] = "C", [47] = "V", [48] = "B", [49] = "N", [50] = "M", [52] = ".", [53] = "/", -- only KDX
[28] = "Enter",
[42] = "Shift",
[56] = "Alt",
[57] = " ",
[90] = "AA", -- KDX
[91] = "Back", -- KDX
[92] = "Press", -- KDX
[94] = "Sym", -- KDX
[98] = "Home", -- KDX
[102] = "Home", -- K[3] & k[4]
[104] = "LPgBack", -- K[3] only
[103] = "Up", -- K[3] & k[4]
[105] = "Left",
[106] = "Right",
[108] = "Down", -- K[3] & k[4]
[109] = "RPgBack",
[114] = "VMinus",
[115] = "VPlus",
[122] = "Up", -- KDX
[123] = "Down", -- KDX
[124] = "RPgFwd", -- KDX
[126] = "Sym", -- K[3]
[139] = "Menu",
[158] = "Back", -- K[3] & K[4]
[190] = "AA", -- K[3]
[191] = "RPgFwd", -- K[3] & k[4]
[193] = "LPgFwd", -- K[3] only
[194] = "Press", -- K[3] & k[4]
}

@ -0,0 +1,15 @@
--[[
event map for Kindle devices with control buttons & DPad
--]]
return {
[29] = "ScreenKB",
[102] = "Home",
[103] = "Up",
[104] = "LPgFwd",
[108] = "Down",
[158] = "Back",
[191] = "RPgFwd",
[193] = "LPgBack",
[194] = "Press",
}

@ -1,13 +1,8 @@
local BasePowerD = require("ui/device/basepowerd")
local BasePowerD = require("device/generic/powerd")
-- liblipclua, see require below
local KindlePowerD = BasePowerD:new{
fl_min = 0, fl_max = 24,
kpw1_frontlight = "/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity",
kpw2_frontlight = "/sys/class/backlight/max77696-bl/brightness",
kt_kpw_capacity = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
kpw_charging = "/sys/devices/platform/aplite_charger.0/charging",
kt_charging = "/sys/devices/platform/fsl-usb2-udc/charging",
flIntensity = nil,
battCapacity = nil,
@ -15,32 +10,11 @@ local KindlePowerD = BasePowerD:new{
lipc_handle = nil,
}
function KindlePowerD:new(o)
local o = o or {}
setmetatable(o, self)
self.__index = self
if o.init then o:init(o.model) end
return o
end
function KindlePowerD:init(model)
function KindlePowerD:init()
local lipc = require("liblipclua")
if lipc then
self.lipc_handle = lipc.init("com.github.koreader.kindlepowerd")
end
if model == "KindleTouch" then
self.batt_capacity_file = self.kt_kpw_capacity
self.is_charging_file = self.kt_charging
elseif model == "KindlePaperWhite" then
self.fl_intensity_file = self.kpw1_frontlight
self.batt_capacity_file = self.kt_kpw_capacity
self.is_charging_file = self.kpw_charging
elseif model == "KindlePaperWhite2" then
self.fl_intensity_file = self.kpw2_frontlight
self.batt_capacity_file = self.kt_kpw_capacity
self.is_charging_file = self.kpw_charging
end
if self.lipc_handle then
self.flIntensity = self.lipc_handle:get_int_property("com.lab126.powerd", "flIntensity")
else
@ -83,9 +57,10 @@ function KindlePowerD:isChargingHW()
return self.is_charging == 1
end
function KindlePowerD:coda()
function KindlePowerD:__gc()
if self.lipc_handle then
self.lipc_handle:close()
self.lipc_handle = nil
end
end

@ -0,0 +1,151 @@
local Generic = require("device/generic/device")
local lfs = require("libs/libkoreader-lfs")
local Geom = require("ui/geometry")
local function yes() return true end
local Kobo = Generic:new{
model = "Kobo",
isKobo = yes,
isTouchDevice = yes, -- all of them are
-- most Kobos have X/Y switched for the touch screen
touch_switch_xy = true,
-- most Kobos have also mirrored X coordinates
touch_mirrored_x = true,
}
-- TODO: hasKeys for some devices?
local KoboTrilogy = Kobo:new{
model = "Kobo_trilogy",
touch_switch_xy = false,
}
local KoboPixie = Kobo:new{
model = "Kobo_pixie",
display_dpi = 200,
}
local KoboDahlia = Kobo:new{
model = "Kobo_dahlia",
hasFrontlight = yes,
touch_phoenix_protocol = true,
display_dpi = 265,
-- bezel:
viewport = Geom:new{x=0, y=10, w=1080, h=1430},
}
local KoboDragon = Kobo:new{
model = "Kobo_dragon",
hasFrontlight = yes,
display_dpi = 265,
}
local KoboKraken = Kobo:new{
model = "Kobo_kraken",
hasFrontlight = yes,
display_dpi = 212,
}
local KoboPhoenix = Kobo:new{
model = "Kobo_phoenix",
hasFrontlight = yes,
touch_phoenix_protocol = true,
display_dpi = 212.8,
-- bezel:
viewport = Geom:new{x=6, y=12, w=752, h=1012},
}
function Kobo:init()
self.screen = require("device/screen"):new{device = self}
self.powerd = require("device/kobo/powerd"):new{device = self}
self.input = require("device/input"):new{
device = self,
event_map = {
[59] = "Power_SleepCover",
[90] = "Light",
[116] = "Power",
}
}
Generic.init(self)
self.input.open("/dev/input/event0") -- Light button and sleep slider
self.input.open("/dev/input/event1")
-- it's called KOBO_TOUCH_MIRRORED in defaults.lua, but what it
-- actually did in its original implementation was to switch X/Y.
if self.touch_switch_xy and not KOBO_TOUCH_MIRRORED
or not self.touch_switch_xy and KOBO_TOUCH_MIRRORED
then
self.input:registerEventAdjustHook(self.input.adjustTouchSwitchXY)
end
if self.touch_mirrored_x then
self.input:registerEventAdjustHook(
self.input.adjustTouchMirrorX,
self.screen:getScreenWidth()
)
end
if self.touch_phoenix_protocol then
self.input.handleTouchEv = self.input.handleTouchEvPhoenix
end
end
function Kobo:getCodeName()
local std_out = io.popen("/bin/kobo_config.sh 2>/dev/null", "r")
local codename = std_out:read()
std_out:close()
return codename
end
function Kobo:getFirmwareVersion()
local version_file = io.open("/mnt/onboard/.kobo/version", "r")
self.firmware_rev = string.sub(version_file:read(),24,28)
version_file:close()
end
function Kobo:Suspend()
if KOBO_LIGHT_OFF_ON_SUSPEND then
self.powerd:setIntensity(0)
end
os.execute("./suspend.sh")
end
function Kobo:Resume()
os.execute("echo 0 > /sys/power/state-extended")
if self.powerd then
if KOBO_LIGHT_ON_START and tonumber(KOBO_LIGHT_ON_START) > -1 then
self.powerd:setIntensity(math.max(math.min(KOBO_LIGHT_ON_START,100),0))
elseif powerd.fl ~= nil then
self.powerd.fl:restore()
end
end
Generic.Resume(self)
end
-------------- device probe ------------
local codename = Kobo:getCodeName()
if codename == "dahlia" then
return KoboDahlia
elseif codename == "dragon" then
return KoboDragon
elseif codename == "kraken" then
return KoboKraken
elseif codename == "phoenix" then
return KoboPhoenix
elseif codename == "trilogy" then
return KoboTrilogy
elseif codename == "pixie" then
return KoboPixie
else
error("unrecognized Kobo model "..codename)
end

@ -1,4 +1,4 @@
local BasePowerD = require("ui/device/basepowerd")
local BasePowerD = require("device/generic/powerd")
local KoboPowerD = BasePowerD:new{
fl_min = 0, fl_max = 100,

@ -0,0 +1,183 @@
local Blitbuffer = require("ffi/blitbuffer")
local einkfb = require("ffi/framebuffer")
local Geom = require("ui/geometry")
local util = require("ffi/util")
local DEBUG = require("dbg")
--[[
Codes for rotation modes:
1 for no rotation,
2 for landscape with bottom on the right side of screen, etc.
2
+--------------+
| +----------+ |
| | | |
| | Freedom! | |
| | | |
| | | |
3 | | | | 1
| | | |
| | | |
| +----------+ |
| |
| |
+--------------+
0
--]]
local Screen = {
cur_rotation_mode = 0,
native_rotation_mode = nil,
blitbuffer_rotation_mode = 0,
bb = nil,
saved_bb = nil,
screen_size = Geom:new(),
viewport = nil,
fb = einkfb.open("/dev/fb0"),
-- will be set upon loading by Device class:
device = nil,
}
function Screen:new(o)
local o = o or {}
setmetatable(o, self)
self.__index = self
if o.init then o:init() end
return o
end
function Screen:init()
self.bb = self.fb.bb
self.blitbuffer_rotation_mode = self.bb:getRotation()
-- asking the framebuffer for orientation is error prone,
-- so we do this simple heuristic (for now)
self.screen_size.w = self.bb:getWidth()
self.screen_size.h = self.bb:getHeight()
if self.screen_size.w > self.screen_size.h then
self.native_rotation_mode = 1
self.screen_size.w, self.screen_size.h = self.screen_size.h, self.screen_size.w
else
self.native_rotation_mode = 0
end
self.cur_rotation_mode = self.native_rotation_mode
end
--[[
set a rectangle that represents the area of the screen we are working on
--]]
function Screen:setViewport(viewport)
self.viewport = self.screen_size:intersect(viewport)
self.bb = self.fb.bb:viewport(
self.viewport.x, self.viewport.y,
self.viewport.w, self.viewport.h)
end
function Screen:refresh(refresh_type, waveform_mode, x, y, w, h)
if self.viewport and x and y then
-- adapt to viewport
x = x + self.viewport.x
y = y + self.viewport.y
end
self.fb:refresh(refresh_type, waveform_mode, x, y, w, h)
end
function Screen:getSize()
return Geom:new{w = self.bb:getWidth(), h = self.bb:getHeight()}
end
function Screen:getWidth()
return self.bb:getWidth()
end
function Screen:getScreenWidth()
return self.screen_size.w
end
function Screen:getScreenHeight()
return self.screen_size.h
end
function Screen:getHeight()
return self.bb:getHeight()
end
function Screen:getDPI()
if self.dpi == nil then
self.dpi = G_reader_settings:readSetting("screen_dpi")
end
if self.dpi == nil then
self.dpi = self.device.display_dpi
end
if self.dpi == nil then
self.dpi = 160
end
return self.dpi
end
function Screen:setDPI(dpi)
G_reader_settings:saveSetting("screen_dpi", dpi)
end
function Screen:scaleByDPI(px)
-- scaled positive px should also be positive
return math.ceil(px * self:getDPI()/167)
end
function Screen:getRotationMode()
return self.cur_rotation_mode
end
function Screen:getScreenMode()
if self:getWidth() > self:getHeight() then
return "landscape"
else
return "portrait"
end
end
function Screen:setRotationMode(mode)
self.fb.bb:rotateAbsolute(-90 * (mode - self.native_rotation_mode - self.blitbuffer_rotation_mode))
self.cur_rotation_mode = mode
end
function Screen:setScreenMode(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 == 0 or self.cur_rotation_mode == 2 then
self:setRotationMode(DLANDSCAPE_CLOCKWISE_ROTATION and 1 or 3)
elseif self.cur_rotation_mode == 1 or self.cur_rotation_mode == 3 then
self:setRotationMode((self.cur_rotation_mode + 2) % 4)
end
end
end
function Screen:saveCurrentBB()
if self.saved_bb then self.saved_bb:free() end
self.saved_bb = self.bb:copy()
end
function Screen:restoreFromSavedBB()
if self.saved_bb then
self.bb:blitFullFrom(self.saved_bb)
-- free data
self.saved_bb:free()
self.saved_bb = nil
end
end
function Screen:close()
DEBUG("close screen framebuffer")
self.fb:close()
end
return Screen

@ -4,8 +4,8 @@ local Configurable = require("configurable")
local Blitbuffer = require("ffi/blitbuffer")
local lfs = require("libs/libkoreader-lfs")
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Font = require("ui/font")
local DEBUG = require("dbg")
local ffi = require("ffi")

@ -2,7 +2,7 @@ local TileCacheItem = require("document/tilecacheitem")
local KOPTContext = require("ffi/koptcontext")
local Document = require("document/document")
local CacheItem = require("cacheitem")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local serial = require("serialize")
local Cache = require("cache")

@ -1,4 +1,4 @@
local Screen = require("ui/screen")
local Screen = require("device").screen
local S = require("ui/data/strings")
local _ = require("gettext")

@ -1,4 +1,4 @@
local Screen = require("ui/screen")
local Screen = require("device").screen
local S = require("ui/data/strings")
local _ = require("gettext")

@ -1,326 +0,0 @@
local isAndroid, android = pcall(require, "android")
local lfs = require("libs/libkoreader-lfs")
local Screen = require("ui/device/screen")
local util = require("ffi/util")
local DEBUG = require("dbg")
local ffi = require("ffi")
local Device = {
screen_saver_mode = false,
charging_mode = false,
survive_screen_saver = false,
is_special_offers = nil,
touch_dev = nil,
model = nil,
firmware_rev = nil,
powerd = nil,
has_no_keyboard = nil,
is_touch_device = nil,
has_front_light = nil,
screen = Screen
}
Screen.device = Device
function Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
function Device:getModel()
if self.model then return self.model end
if util.isEmulated() then
self.model = "Emulator"
return self.model
end
self.model = ""
local kindle_sn = io.open("/proc/usid", "r")
if kindle_sn then
local kindle_devcode = string.sub(kindle_sn:read(),3,4)
kindle_sn:close()
-- NOTE: Update me when new devices come out :)
local k2_set = Set { "02", "03" }
local dx_set = Set { "04", "05" }
local dxg_set = Set { "09" }
local k3_set = Set { "08", "06", "0A" }
local k4_set = Set { "0E", "23" }
local touch_set = Set { "0F", "11", "10", "12" }
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
local pw2_set = Set { "D4", "5A", "D5", "D6", "D7", "D8", "F2", "17",
"60", "F4", "F9", "62", "61", "5F" }
if k2_set[kindle_devcode] then
self.model = "Kindle2"
elseif dx_set[kindle_devcode] then
self.model = "Kindle2"
elseif dxg_set[kindle_devcode] then
self.model = "KindleDXG"
elseif k3_set[kindle_devcode] then
self.model = "Kindle3"
elseif k4_set[kindle_devcode] then
self.model = "Kindle4"
elseif touch_set[kindle_devcode] then
self.model = "KindleTouch"
elseif pw_set[kindle_devcode] then
self.model = "KindlePaperWhite"
elseif pw2_set[kindle_devcode] then
self.model = "KindlePaperWhite2"
end
else
local kg_test_fd = lfs.attributes("/bin/kobo_config.sh")
if kg_test_fd then
local std_out = io.popen("/bin/kobo_config.sh 2>/dev/null", "r")
local codename = std_out:read()
self.model = "Kobo_" .. codename
local version_file = io.open("/mnt/onboard/.kobo/version", "r")
self.firmware_rev = string.sub(version_file:read(),24,28)
version_file:close()
end
end
return self.model
end
function Device:getFirmVer()
if not self.model then self:getModel() end
return self.firmware_rev
end
function Device:isKindle4()
return (self:getModel() == "Kindle4")
end
function Device:isKindle3()
return (self:getModel() == "Kindle3")
end
function Device:isKindle2()
return (self:getModel() == "Kindle2")
end
function Device:isKindle()
local is_kindle = false
local kindle_sn = io.open("/proc/usid", "r")
if kindle_sn then
is_kindle = true
kindle_sn:close()
end
return is_kindle
end
function Device:isKobo()
return string.find(self:getModel() or "", "Kobo_") == 1
end
Device.isAndroid = util.isAndroid
-- device has qwerty keyboard
function Device:hasKeyboard()
if self.has_keyboard ~= nil then return self.has_keyboard end
if not isAndroid then
local model = self:getModel()
self.has_keyboard = (model == "Kindle2") or (model == "Kindle3")
or (model == "KindleDXG") or util.isEmulated()
else
self.has_keyboard = ffi.C.AConfiguration_getKeyboard(android.app.config)
== ffi.C.ACONFIGURATION_KEYBOARD_QWERTY
end
return self.has_keyboard
end
function Device:hasNoKeyboard()
return not self:hasKeyboard()
end
-- device has hardware keys for pagedown/pageup
function Device:hasKeys()
if self.has_keys ~= nil then return self.has_keys end
local model = self:getModel()
self.has_keys = (model ~= "KindlePaperWhite") and (model ~= "KindlePaperWhite2")
and (model ~= "KindleTouch") and not self:isKobo()
return self.has_keys
end
function Device:isTouchDevice()
if self.is_touch_device ~= nil then return self.is_touch_device end
if not isAndroid then
local model = self:getModel()
self.is_touch_device = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
or (model == "KindleTouch") or self:isKobo() or util.isEmulated()
else
self.is_touch_device = ffi.C.AConfiguration_getTouchscreen(android.app.config)
~= ffi.C.ACONFIGURATION_TOUCHSCREEN_NOTOUCH
end
return self.is_touch_device
end
function Device:hasFrontlight()
if self.has_front_light ~= nil then return self.has_front_light end
local model = self:getModel()
self.has_front_light = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
or (model == "Kobo_dahlia") or (model == "Kobo_dragon") or (model == "Kobo_kraken") or (model == "Kobo_phoenix")
or util.isEmulated()
return self.has_front_light
end
function Device:setTouchInputDev(dev)
self.touch_dev = dev
end
function Device:getTouchInputDev()
return self.touch_dev
end
function Device:intoScreenSaver()
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
if self.charging_mode == false and self.screen_saver_mode == false then
self.screen:saveCurrentBB()
--UIManager:show(InfoMessage:new{
--text = "Going into screensaver... ",
--timeout = 2,
--})
--util.sleep(1)
--os.execute("killall -cont cvm")
self.screen_saver_mode = true
end
end
function Device:outofScreenSaver()
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
if self.screen_saver_mode == true and self.charging_mode == false then
-- wait for native system update screen before we recover saved
-- Blitbuffer.
util.usleep(1500000)
--os.execute("killall -stop cvm")
self.screen:restoreFromSavedBB()
self.screen:refresh(0)
self.survive_screen_saver = true
end
self.screen_saver_mode = false
end
function Device:onPowerEvent(ev)
local Screensaver = require("ui/screensaver")
if (ev == "Power" or ev == "Suspend") and not self.screen_saver_mode then
local UIManager = require("ui/uimanager")
DEBUG("Suspending...")
-- always suspend in portrait mode
self.orig_rotation_mode = Screen:getRotationMode()
Screen:setRotationMode(0)
Screensaver:show()
self:prepareSuspend()
UIManager:scheduleIn(2, function() self:Suspend() end)
elseif (ev == "Power" or ev == "Resume") and self.screen_saver_mode then
DEBUG("Resuming...")
-- restore to previous rotation mode
Screen:setRotationMode(self.orig_rotation_mode)
self:Resume()
Screensaver:close()
end
end
function Device:prepareSuspend()
local powerd = self:getPowerDevice()
if powerd.fl ~= nil then
-- in no case should the frontlight be turned on in suspend mode
powerd.fl:sleep()
end
self.screen:refresh(0)
self.screen_saver_mode = true
end
function Device:Suspend()
if self:isKobo() then
if KOBO_LIGHT_OFF_ON_SUSPEND then self:getPowerDevice():setIntensity(0) end
os.execute("./suspend.sh")
end
end
function Device:Resume()
if self:isKobo() then
os.execute("echo 0 > /sys/power/state-extended")
local powerd = self:getPowerDevice()
if powerd then
if KOBO_LIGHT_ON_START and tonumber(KOBO_LIGHT_ON_START) > -1 then
powerd:setIntensity(math.max(math.min(KOBO_LIGHT_ON_START,100),0))
elseif powerd.fl ~= nil then
powerd.fl:restore()
end
end
end
self.screen:refresh(1)
self.screen_saver_mode = false
end
function Device:usbPlugIn()
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
if self.charging_mode == false and self.screen_saver_mode == false then
self.screen:saveCurrentBB()
--UIManager:show(InfoMessage:new{
--text = "Going into USB mode... ",
--timeout = 2,
--})
--util.sleep(1)
--os.execute("killall -cont cvm")
end
self.charging_mode = true
end
function Device:usbPlugOut()
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
if self.charging_mode == true and self.screen_saver_mode == false then
--util.usleep(1500000)
--os.execute("killall -stop cvm")
self.screen:restoreFromSavedBB()
self.screen:refresh(0)
end
--@TODO signal filemanager for file changes 13.06 2012 (houqp)
self.charging_mode = false
end
function Device:getPowerDevice()
if self.powerd ~= nil then
return self.powerd
else
local model = self:getModel()
if model == "KindleTouch" or model == "KindlePaperWhite" or model == "KindlePaperWhite2" then
local KindlePowerD = require("ui/device/kindlepowerd")
self.powerd = KindlePowerD:new{model = model}
elseif self:isKobo() then
local KoboPowerD = require("ui/device/kobopowerd")
self.powerd = KoboPowerD:new()
elseif self.isAndroid then
local AndroidPowerd = require("ui/device/androidpowerd")
self.powerd = AndroidPowerd:new()
else -- emulated FrontLight
local BasePowerD = require("ui/device/basepowerd")
self.powerd = BasePowerD:new()
end
end
return self.powerd
end
function Device:isSpecialOffers()
if self.is_special_offers ~= nil then return self.is_special_offers end
-- K5 only
if self:isTouchDevice() and self:isKindle() then
-- Look at the current blanket modules to see if the SO screensavers are enabled...
local lipc = require("liblipclua")
local lipc_handle = nil
if lipc then
lipc_handle = lipc.init("com.github.koreader.device")
end
if lipc_handle then
local loaded_blanket_modules = lipc_handle:get_string_property("com.lab126.blanket", "load")
if string.find(loaded_blanket_modules, "ad_screensaver") then
self.is_special_offers = true
end
lipc_handle:close()
else
end
end
return self.is_special_offers
end
return Device

@ -1,352 +0,0 @@
local Blitbuffer = require("ffi/blitbuffer")
local einkfb = require("ffi/framebuffer")
local Geom = require("ui/geometry")
local util = require("ffi/util")
local DEBUG = require("dbg")
local _ = require("gettext")
--[[
Codes for rotation modes:
1 for no rotation,
2 for landscape with bottom on the right side of screen, etc.
2
+--------------+
| +----------+ |
| | | |
| | Freedom! | |
| | | |
| | | |
3 | | | | 1
| | | |
| | | |
| +----------+ |
| |
| |
+--------------+
0
--]]
local Screen = {
cur_rotation_mode = 0,
native_rotation_mode = nil,
blitbuffer_rotation_mode = 0,
bb = nil,
saved_bb = nil,
fb = einkfb.open("/dev/fb0"),
-- will be set upon loading by Device class:
device = nil,
}
function Screen:init()
self.bb = self.fb.bb
if self.device:getModel() == 'Kobo_phoenix' then
function Screen:getSize()
return Screen:getSizePhoenix()
end
function Screen:getWidth()
return Screen:getWidthPhoenix()
end
function Screen:getHeight()
return Screen:getHeightPhoenix()
end
function self:offsetX()
if Screen.cur_rotation_mode == 0 then
return 6
elseif Screen.cur_rotation_mode == 1 then
return 12
elseif Screen.cur_rotation_mode == 2 then
return 12
elseif Screen.cur_rotation_mode == 3 then
return 6
end
end
function self:offsetY()
return 1
end
elseif self.device:getModel() == 'Kobo_dahlia' then
function Screen:getSize()
return Screen:getSizePhoenix()
end
function Screen:getWidth()
return Screen:getWidthDahlia()
end
function Screen:getHeight()
return Screen:getHeightDahlia()
end
function self:offsetX()
if Screen.cur_rotation_mode == 3 then
return 10
else
return 0
end
end
function self:offsetY()
if Screen.cur_rotation_mode == 0 then
return 10
else
return 0
end
end
else
function Screen:getSize()
return Screen:getSizeBB()
end
function Screen:getWidth()
return Screen:getWidthBB()
end
function Screen:getHeight()
return Screen:getHeightBB()
end
function self:offsetX() return 0 end
function self:offsetY() return 0 end
end
self.blitbuffer_rotation_mode = self.bb:getRotation()
-- asking the framebuffer for orientation is error prone,
-- so we do this simple heuristic (for now)
if self:getWidth() > self:getHeight() then
self.native_rotation_mode = 1
else
self.native_rotation_mode = 0
end
self.cur_rotation_mode = self.native_rotation_mode
end
-- For the Kobo Aura an offset is needed, because the bezel make the
-- visible screen smaller.
function Screen:PhoenixBezelCleaner()
self.bb:paintRect(0,0, Screen:getWidth(), Screen:offsetY(), Blitbuffer.COLOR_WHITE)
self.bb:paintRect(0,0, Screen:offsetX(), Screen:getHeight(), Blitbuffer.COLOR_WHITE)
self.bb:paintRect(Screen:getWidth() + Screen:offsetX(), 0,
Screen:getWidth() - Screen:getWidth() - Screen:offsetX(), Screen:getHeight(),
Blitbuffer.COLOR_WHITE)
self.bb:paintRect(0, Screen:getHeight() + Screen:offsetY(),
Screen:offsetX(), Screen:getWidth(),
Blitbuffer.COLOR_WHITE)
end
function Screen:refresh(refresh_type, waveform_mode, x, y, w, h)
self.fb:refresh(refresh_type, waveform_mode, x, y, w, h)
if self.device:getModel() == 'Kobo_phoenix' and refresh_type == 1 then
Screen:PhoenixBezelCleaner()
end
end
function Screen:getSizeBB()
return Geom:new{w = self.bb:getWidth(), h = self.bb:getHeight()}
end
function Screen:getSizePhoenix()
return Geom:new{w = self.getWidth(), h = self.getHeight()}
end
function Screen:getWidthBB()
return self.bb:getWidth()
end
function Screen:getWidthDahlia()
if self.cur_rotation_mode == 0 then return 1080
else return 1430
end
end
function Screen:getWidthPhoenix()
if self.cur_rotation_mode == 0 then return 752
else return 1012
end
end
function Screen:getHeightBB()
return self.bb:getHeight()
end
function Screen:getHeightDahlia()
if self.cur_rotation_mode == 0 then return 1430
else return 1080
end
end
function Screen:getHeightPhoenix()
if self.cur_rotation_mode == 0 then return 1012
else return 752
end
end
function Screen:getDPI()
if self.dpi == nil then
self.dpi = G_reader_settings:readSetting("screen_dpi")
end
if self.dpi ~= nil then return self.dpi end
local model = self.device:getModel()
if model == "KindlePaperWhite" or model == "KindlePaperWhite2"
or model == "Kobo_kraken" then
self.dpi = 212
elseif model == "Kobo_phoenix" then
self.dpi = 212.8
elseif model == "Kobo_dragon" or model == "Kobo_dahlia" then
self.dpi = 265
elseif model == "Kobo_pixie" then
self.dpi = 200
elseif util.isAndroid() then
local android = require("android")
local ffi = require("ffi")
self.dpi = ffi.C.AConfiguration_getDensity(android.app.config)
else
self.dpi = 160
end
return self.dpi
end
function Screen:setDPI(dpi)
G_reader_settings:saveSetting("screen_dpi", dpi)
end
function Screen:scaleByDPI(px)
-- scaled positive px should also be positive
return math.ceil(px * self:getDPI()/167)
end
function Screen:getRotationMode()
return self.cur_rotation_mode
end
function Screen:getScreenMode()
if self:getWidth() > self:getHeight() then
return "landscape"
else
return "portrait"
end
end
function Screen:setRotationMode(mode)
self.fb.bb:rotateAbsolute(-90 * (mode - self.native_rotation_mode - self.blitbuffer_rotation_mode))
self.cur_rotation_mode = mode
end
function Screen:setScreenMode(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 == 0 or self.cur_rotation_mode == 2 then
self:setRotationMode(DLANDSCAPE_CLOCKWISE_ROTATION and 1 or 3)
elseif self.cur_rotation_mode == 1 or self.cur_rotation_mode == 3 then
self:setRotationMode((self.cur_rotation_mode + 2) % 4)
end
end
end
function Screen:saveCurrentBB()
local width, height = self:getWidth(), self:getHeight()
if not self.saved_bb then
self.saved_bb = Blitbuffer.new(width, height)
end
if self.saved_bb:getWidth() ~= width then
self.saved_bb:free()
self.saved_bb = Blitbuffer.new(width, height)
end
self.saved_bb:blitFullFrom(self.bb)
end
function Screen:restoreFromSavedBB()
self:restoreFromBB(self.saved_bb)
-- free data
self.saved_bb = nil
end
function Screen:getCurrentScreenBB()
local bb = Blitbuffer.new(self:getWidth(), self:getHeight())
bb:blitFullFrom(self.bb)
return bb
end
function Screen:restoreFromBB(bb)
if bb then
self.bb:blitFullFrom(bb)
else
DEBUG("Got nil bb in restoreFromSavedBB!")
end
end
function Screen:close()
DEBUG("close screen framebuffer")
self.fb:close()
end
function Screen:getDPIMenuTable()
local function dpi() return G_reader_settings:readSetting("screen_dpi") end
local function custom() return G_reader_settings:readSetting("custom_screen_dpi") end
local function setDPI(dpi)
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
UIManager:show(InfoMessage:new{
text = _("This will take effect on next restart."),
})
Screen:setDPI(dpi)
end
return {
text = _("Screen DPI"),
sub_item_table = {
{
text = _("Auto"),
checked_func = function()
return dpi() == nil
end,
callback = function() setDPI() end
},
{
text = _("Small"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi <= 140 and dpi ~= custom
end,
callback = function() setDPI(120) end
},
{
text = _("Medium"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi > 140 and dpi <= 200 and dpi ~= custom
end,
callback = function() setDPI(160) end
},
{
text = _("Large"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi > 200 and dpi ~= custom
end,
callback = function() setDPI(240) end
},
{
text = _("Custom DPI") .. ": " .. (custom() or 160),
checked_func = function()
local dpi, custom = dpi(), custom()
return custom and dpi == custom
end,
callback = function() setDPI(custom() or 160) end,
hold_input = {
title = _("Input screen DPI"),
type = "number",
hint = "(90 - 330)",
callback = function(input)
local dpi = tonumber(input)
dpi = dpi < 90 and 90 or dpi
dpi = dpi > 330 and 330 or dpi
G_reader_settings:saveSetting("custom_screen_dpi", dpi)
setDPI(dpi)
end,
},
},
}
}
end
return Screen

@ -0,0 +1,74 @@
local _ = require("gettext")
local Screen = require("device").screen
local function dpi() return G_reader_settings:readSetting("screen_dpi") end
local function custom() return G_reader_settings:readSetting("custom_screen_dpi") end
local function setDPI(dpi)
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
UIManager:show(InfoMessage:new{
text = _("This will take effect on next restart."),
})
Screen:setDPI(dpi)
end
return {
text = _("Screen DPI"),
sub_item_table = {
{
text = _("Auto"),
checked_func = function()
return dpi() == nil
end,
callback = function() setDPI() end
},
{
text = _("Small"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi <= 140 and dpi ~= custom
end,
callback = function() setDPI(120) end
},
{
text = _("Medium"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi > 140 and dpi <= 200 and dpi ~= custom
end,
callback = function() setDPI(160) end
},
{
text = _("Large"),
checked_func = function()
local dpi, custom = dpi(), custom()
return dpi and dpi > 200 and dpi ~= custom
end,
callback = function() setDPI(240) end
},
{
text = _("Custom DPI") .. ": " .. (custom() or 160),
checked_func = function()
local dpi, custom = dpi(), custom()
return custom and dpi == custom
end,
callback = function() setDPI(custom() or 160) end,
hold_input = {
title = _("Input screen DPI"),
type = "number",
hint = "(90 - 330)",
callback = function(input)
local dpi = tonumber(input)
dpi = dpi < 90 and 90 or dpi
dpi = dpi > 330 and 330 or dpi
G_reader_settings:saveSetting("custom_screen_dpi", dpi)
setDPI(dpi)
end,
},
},
}
}

@ -1,6 +1,6 @@
local lfs = require("libs/libkoreader-lfs")
local Freetype = require("ffi/freetype")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DEBUG = require("dbg")
local Font = {

@ -1,861 +0,0 @@
local Device = require("ui/device")
local GestureDetector = require("ui/gesturedetector")
local Event = require("ui/event")
local TimeVal = require("ui/timeval")
local Screen = require("ui/screen")
local input = require("ffi/input")
local util = require("ffi/util")
local Math = require("optmath")
local DEBUG = require("dbg")
local ffi = require("ffi")
local _ = require("gettext")
-- constants from <linux/input.h>
local EV_SYN = 0
local EV_KEY = 1
local EV_ABS = 3
local EV_MSC = 4
-- key press event values (KEY.value)
local EVENT_VALUE_KEY_PRESS = 1
local EVENT_VALUE_KEY_REPEAT = 2
local EVENT_VALUE_KEY_RELEASE = 0
-- Synchronization events (SYN.code).
local SYN_REPORT = 0
local SYN_CONFIG = 1
local SYN_MT_REPORT = 2
-- For single-touch events (ABS.code).
local ABS_X = 00
local ABS_Y = 01
local ABS_PRESSURE = 24
-- For multi-touch events (ABS.code).
local ABS_MT_SLOT = 47
local ABS_MT_TOUCH_MAJOR = 48
local ABS_MT_WIDTH_MAJOR = 50
local ABS_MT_POSITION_X = 53
local ABS_MT_POSITION_Y = 54
if KOBO_TOUCH_MIRRORED then
ABS_X = 01
ABS_Y = 00
ABS_MT_POSITION_X = 54
ABS_MT_POSITION_Y = 53
end
local ABS_MT_TRACKING_ID = 57
local ABS_MT_PRESSURE = 58
--[[
an interface for key presses
]]
local Key = {}
function Key:new(key, modifiers)
local o = { key = key, modifiers = modifiers }
-- we're a hash map, too
o[key] = true
for mod, pressed in pairs(modifiers) do
if pressed then
o[mod] = true
end
end
setmetatable(o, self)
self.__index = self
return o
end
function Key:__tostring()
return table.concat(self:getSequence(), "-")
end
--[[
get a sequence that can be matched against later
use this to let the user press a sequence and then
store this as configuration data (configurable
shortcuts)
]]
function Key:getSequence()
local seq = {}
for mod, pressed in pairs(self.modifiers) do
if pressed then
table.insert(seq, mod)
end
end
table.insert(seq, self.key)
end
--[[
this will match a key against a sequence
the sequence should be a table of key names that
must be pressed together to match.
if an entry in this table is itself a table, at
least one key in this table must match.
E.g.:
Key:match({ "Alt", "K" }) -- match Alt-K
Key:match({ "Alt", { "K", "L" }}) -- match Alt-K _or_ Alt-L
]]
function Key:match(sequence)
local mod_keys = {} -- a hash table for checked modifiers
for _, key in ipairs(sequence) do
if type(key) == "table" then
local found = false
for _, variant in ipairs(key) do
if self[variant] then
found = true
break
end
end
if not found then
-- one of the needed keys is not pressed
return false
end
elseif not self[key] then
-- needed key not pressed
return false
elseif self.modifiers[key] ~= nil then
-- checked key is a modifier key
mod_keys[key] = true
end
end
for mod, pressed in pairs(self.modifiers) do
if pressed and not mod_keys[mod] then
-- additional modifier keys are pressed, don't match
return false
end
end
return true
end
--[[
an interface to get input events
]]
local Input = {
event_map = {},
modifiers = {},
rotation_map = {
[0] = {},
[1] = { Up = "Right", Right = "Down", Down = "Left", Left = "Up" },
[2] = { Up = "Down", Right = "Left", Down = "Up", Left = "Right" },
[3] = { Up = "Left", Right = "Up", Down = "Right", Left = "Down" }
},
timer_callbacks = {},
disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP,
}
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",
[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",
[44] = "Z", [45] = "X", [46] = "C", [47] = "V", [48] = "B", [49] = "N", [50] = "M", [52] = ".", [53] = "/", -- only KDX
[28] = "Enter",
[29] = "ScreenKB", -- K[4]
[42] = "Shift",
[56] = "Alt",
[57] = " ",
[90] = "AA", -- KDX
[91] = "Back", -- KDX
[92] = "Press", -- KDX
[94] = "Sym", -- KDX
[98] = "Home", -- KDX
[102] = "Home", -- K[3] & k[4]
[104] = "LPgBack", -- K[3] only
[103] = "Up", -- K[3] & k[4]
[105] = "Left",
[106] = "Right",
[108] = "Down", -- K[3] & k[4]
[109] = "RPgBack",
[114] = "VMinus",
[115] = "VPlus",
[122] = "Up", -- KDX
[123] = "Down", -- KDX
[124] = "RPgFwd", -- KDX
[126] = "Sym", -- K[3]
[139] = "Menu",
[158] = "Back", -- K[3] & K[4]
[190] = "AA", -- K[3]
[191] = "RPgFwd", -- K[3] & k[4]
[193] = "LPgFwd", -- K[3] only
[194] = "Press", -- K[3] & k[4]
}
self.sdl_event_map = {
[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",
[38] = "A", [39] = "S", [40] = "D", [41] = "F", [42] = "G", [43] = "H", [44] = "J", [45] = "K", [46] = "L",
[52] = "Z", [53] = "X", [54] = "C", [55] = "V", [56] = "B", [57] = "N", [58] = "M",
[22] = "Back", -- Backspace
[36] = "Enter", -- Enter
[50] = "Shift", -- left shift
[60] = ".",
[61] = "/",
[62] = "Sym", -- right shift key
[64] = "Alt", -- left alt
[65] = " ", -- Spacebar
[67] = "Menu", -- F[1]
[68] = "Power", -- F[2]
[72] = "LPgBack", -- F[6]
[73] = "LPgFwd", -- F[7]
[95] = "VPlus", -- F[11]
[96] = "VMinus", -- F[12]
[105] = "AA", -- right alt key
[110] = "Home", -- Home
[111] = "Up", -- arrow up
[112] = "RPgBack", -- normal PageUp
[113] = "Left", -- arrow left
[114] = "Right", -- arrow right
[115] = "Press", -- End (above arrows)
[116] = "Down", -- arrow down
[117] = "RPgFwd", -- normal PageDown
[119] = "Del", -- Delete
}
self.sdl2_event_map = {
[ 4] = "A", [ 5] = "B", [ 6] = "C", [ 7] = "D", [ 8] = "E", [ 9] = "F",
[10] = "G", [11] = "H", [12] = "I", [13] = "J", [14] = "K", [15] = "L",
[16] = "M", [17] = "N", [18] = "O", [19] = "P", [20] = "Q", [21] = "R",
[22] = "S", [23] = "T", [24] = "U", [25] = "V", [26] = "W", [27] = "X",
[28] = "Y", [29] = "Z", [30] = "1", [31] = "2", [32] = "3", [33] = "4",
[34] = "5", [35] = "6", [36] = "7", [37] = "8", [38] = "9", [39] = "0",
[42] = "Back", -- Backspace
[40] = "Enter", -- Enter
[225] = "Shift", -- left shift
[55] = ".",
[56] = "/",
[229] = "Sym", -- right shift key
[226] = "Alt", -- left alt
[44] = " ", -- Spacebar
[58] = "Menu", -- F[1]
[59] = "Power", -- F[2]
[63] = "LPgBack", -- F[6]
[64] = "LPgFwd", -- F[7]
[68] = "VPlus", -- F[11]
[69] = "VMinus", -- F[12]
[230] = "AA", -- right alt key
[74] = "Home", -- Home
[82] = "Up", -- arrow up
[75] = "RPgBack", -- normal PageUp
[80] = "Left", -- arrow left
[79] = "Right", -- arrow right
[77] = "Press", -- End (above arrows)
[81] = "Down", -- arrow down
[78] = "RPgFwd", -- normal PageDown
[76] = "Del", -- Delete
}
self.android_event_map = {
[29] = "A", [30] = "B", [31] = "C", [32] = "D", [33] = "E", [34] = "F",
[35] = "G", [36] = "H", [37] = "I", [38] = "J", [39] = "K", [40] = "L",
[41] = "M", [42] = "N", [43] = "O", [44] = "P", [45] = "Q", [46] = "R",
[47] = "S", [48] = "T", [49] = "U", [50] = "V", [51] = "W", [52] = "X",
[53] = "Y", [54] = "Z", [ 7] = "0", [ 8] = "1", [ 9] = "2", [10] = "3",
[11] = "4", [12] = "5", [13] = "6", [14] = "7", [15] = "8", [16] = "9",
[4] = "Back", -- BACK
[19] = "Up", -- DPAD_UP
[20] = "Down", -- DPAD_UP
[21] = "Left", -- DPAD_LEFT
[22] = "Right", -- DPAD_RIGHT
[23] = "Press", -- DPAD_CENTER
[24] = "LPgBack", -- VOLUME_UP
[25] = "LPgFwd", -- VOLUME_DOWN
[56] = ".", -- PERIOD
[59] = "Shift", -- SHIFT_LEFT
[60] = "Shift", -- SHIFT_RIGHT
[62] = " ", -- SPACE
[63] = "Sym", -- SYM
[66] = "Enter", -- ENTER
[67] = "Del", -- DEL
[76] = "/", -- SLASH
[82] = "Menu", -- MENU
[84] = "Search",--SEARCH
[92] = "LPgBack", -- PAGE_UP
[93] = "LPgFwd", -- PAGE_DOWN
}
self.modifiers = {
Alt = false,
Shift = false
}
-- these groups are just helpers:
self.group = {
Cursor = { "Up", "Down", "Left", "Right" },
PgFwd = { "RPgFwd", "LPgFwd" },
PgBack = { "RPgBack", "LPgBack" },
Alphabet = {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
AlphaNumeric = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
Numeric = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
},
Text = {
" ", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
},
Any = {
" ", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"Up", "Down", "Left", "Right", "Press",
"Back", "Enter", "Sym", "AA", "Menu", "Home", "Del",
"LPgBack", "RPgBack", "LPgFwd", "RPgFwd"
}
}
end
function Input:initTouchState()
self.cur_slot = 0
self.MTSlots = {}
self.ev_slots = {
[0] = {
slot = 0,
}
}
end
function Input:init()
self:initKeyMap()
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() then
-- open SDL if it's not dummy input device
if not self.dummy then input.open() end
-- SDL key codes
if not util.haveSDL2() then
self.event_map = self.sdl_event_map
else
self.event_map = self.sdl2_event_map
end
else
local dev_mod = Device:getModel()
if not Device:isKobo() then
input.open("fake_events")
end
if dev_mod == "KindlePaperWhite" then
DEBUG("Auto-detected Kindle PaperWhite")
Device:setTouchInputDev("/dev/input/event0")
input.open("/dev/input/event0")
elseif dev_mod == "KindlePaperWhite2" then
DEBUG("Auto-detected Kindle PaperWhite")
Device:setTouchInputDev("/dev/input/event1")
input.open("/dev/input/event1")
elseif dev_mod == "KindleTouch" then
-- event0 in KindleTouch is "WM8962 Beep Generator" (useless)
-- event1 in KindleTouch is "imx-yoshi Headset" (useless)
Device:setTouchInputDev("/dev/input/event3")
input.open("/dev/input/event2") -- Home button
input.open("/dev/input/event3") -- touchscreen
-- KT does have one key!
self.event_map[102] = "Home"
-- update event hook
function Input:eventAdjustHook(ev)
if ev.type == EV_ABS then
--@TODO handle coordinates properly after
--screen rotate. (houqp)
if ev.code == ABS_MT_POSITION_X then
ev.value = Math.round(ev.value * (600/4095))
elseif ev.code == ABS_MT_POSITION_Y then
ev.value = Math.round(ev.value * (800/4095))
end
end
return ev
end
DEBUG("Auto-detected Kindle Touch")
elseif Device:isKobo() then
local firm_rev = Device:getFirmVer()
input.open("/dev/input/event1")
Device:setTouchInputDev("/dev/input/event1")
input.open("/dev/input/event0") -- Light button and sleep slider
DEBUG("Auto-detected Kobo")
DEBUG("Device model=", dev_mod)
DEBUG("Firmware revision", firm_rev)
DEBUG("Screen width =", Screen:getWidth())
DEBUG("Screen height =", Screen:getHeight())
self:adjustKoboEventMap()
if dev_mod ~= 'Kobo_trilogy' then
function Input:eventAdjustHook(ev)
if ev.type == EV_ABS then
if ev.code == ABS_X then
ev.code = ABS_Y
elseif ev.code == ABS_Y then
ev.code = ABS_X
-- We always have to substract from the physical x,
-- regardless of the orientation
if (Screen:getWidth()<Screen:getHeight()) then
ev.value = Screen:getWidth() - ev.value
else
ev.value = Screen:getHeight() - ev.value
end
end
-- same thing for multitouch events (phoenix)
if ev.code == ABS_MT_POSITION_X then
ev.code = ABS_MT_POSITION_Y
elseif ev.code == ABS_MT_POSITION_Y then
ev.code = ABS_MT_POSITION_X
-- We always have to substract from the physical x,
-- regardless of the orientation
if (Screen:getWidth()<Screen:getHeight()) then
ev.value = Screen:getWidth() - ev.value
else
ev.value = Screen:getHeight() - ev.value
end
end
end
return ev
end
else -- kobo touch (trilogy)
-- FIXME some touch models should be treated as the other models,
-- depending on board revision
function Input:eventAdjustHook(ev)
if ev.code == ABS_X then
-- We always have to substract from the physical x,
-- regardless of the orientation
if (Screen:getWidth()<Screen:getHeight()) then
ev.value = Screen:getWidth() - ev.value
else
ev.value = Screen:getHeight() - ev.value
end
end
return ev
end
end
elseif dev_mod == "Kindle4" then
DEBUG("Auto-detected Kindle 4")
input.open("/dev/input/event1")
self:adjustKindle4EventMap()
elseif dev_mod == "Kindle3" then
DEBUG("Auto-detected Kindle 3")
input.open("/dev/input/event1")
input.open("/dev/input/event2")
elseif dev_mod == "KindleDXG" then
DEBUG("Auto-detected Kindle DXG")
input.open("/dev/input/event0")
input.open("/dev/input/event1")
elseif dev_mod == "Kindle2" then
DEBUG("Auto-detected Kindle 2")
input.open("/dev/input/event1")
elseif util.isAndroid() then
DEBUG("Auto-detected Android")
self.event_map = self.android_event_map
self:adjustAndroidEventMap()
function Input:handleMiscEv(ev)
return Input:handleAndroidMiscEvent(ev)
end
else
DEBUG("Not supported device model!")
end
end
if Device:getModel() == 'Kobo_phoenix' or Device:getModel() == 'Kobo_dahlia' then
function Input:handleTouchEv(ev)
return Input:handlePhoenixTouchEv(ev)
end
else
function Input:handleTouchEv(ev)
return Input:handleTypeBTouchEv(ev)
end
end
end
--[[
different device models shoudl overload this method if
necessary to make event compatible to KPV.
--]]
function Input:eventAdjustHook(ev)
-- do nothing by default
return ev
end
function Input:adjustKindle4EventMap()
self.event_map[193] = "LPgBack"
self.event_map[104] = "LPgFwd"
end
function Input:adjustKoboEventMap()
self.event_map[59] = "Power_SleepCover"
self.event_map[90] = "Light"
self.event_map[116] = "Power"
end
function Input:adjustAndroidEventMap()
self.event_map[104] = "LPgBack" -- T68 PageUp
self.event_map[109] = "LPgFwd" -- T68 PageDown
self.event_map[139] = "Menu" -- T68 Menu
end
function Input:setTimeout(cb, tv_out)
local item = {
callback = cb,
deadline = tv_out,
}
table.insert(self.timer_callbacks, item)
table.sort(self.timer_callbacks, function(v1,v2)
return v1.deadline < v2.deadline
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[Screen:getRotationMode()][keycode] then
keycode = self.rotation_map[Screen:getRotationMode()][keycode]
end
if keycode == "IntoSS" or keycode == "OutOfSS"
or keycode == "Charging" or keycode == "NotCharging" then
return keycode
end
-- Kobo sleep
if keycode == "Power_SleepCover" then
if ev.value == EVENT_VALUE_KEY_PRESS then
return "Suspend"
else
return "Resume"
end
end
if ev.value == EVENT_VALUE_KEY_RELEASE
and (keycode == "Light" or keycode == "Power") 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
function Input:handleMiscEv(ev)
end
function Input:handleAndroidMiscEvent(ev)
if ev.code == ffi.C.APP_CMD_SAVE_STATE then
return "SaveState"
end
end
function Input:setMtSlot(slot, key, val)
if not self.ev_slots[slot] then
self.ev_slots[slot] = {
slot = slot
}
end
self.ev_slots[slot][key] = val
end
function Input:setCurrentMtSlot(key, val)
self:setMtSlot(self.cur_slot, key, val)
end
function Input:getMtSlot(slot)
return self.ev_slots[slot]
end
function Input:getCurrentMtSlot()
return self:getMtSlot(self.cur_slot)
end
function Input:confirmAbsxy()
self:setCurrentMtSlot("x", self.ev_slots[self.cur_slot]["abs_x"])
self:setCurrentMtSlot("y", self.ev_slots[self.cur_slot]["abs_y"])
end
function Input:cleanAbsxy()
self:setCurrentMtSlot("abs_x", nil)
self:setCurrentMtSlot("abs_y", nil)
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.
From kernel document:
For type B devices, the kernel driver should associate a slot with each
identified contact, and use that slot to propagate changes for the contact.
Creation, replacement and destruction of contacts is achieved by modifying
the ABS_MT_TRACKING_ID of the associated slot. A non-negative tracking id
is interpreted as a contact, and the value -1 denotes an unused slot. A
tracking id not previously present is considered new, and a tracking id no
longer present is considered removed. Since only changes are propagated,
the full state of each initiated contact has to reside in the receiving
end. Upon receiving an MT event, one simply updates the appropriate
attribute of the current slot.
--]]
function Input:handleTypeBTouchEv(ev)
if ev.type == EV_ABS then
if #self.MTSlots == 0 then
table.insert(self.MTSlots, self:getMtSlot(self.cur_slot))
end
if ev.code == ABS_MT_SLOT then
if self.cur_slot ~= ev.value then
table.insert(self.MTSlots, self:getMtSlot(ev.value))
end
self.cur_slot = ev.value
elseif ev.code == ABS_MT_TRACKING_ID then
self:setCurrentMtSlot("id", ev.value)
elseif ev.code == ABS_MT_POSITION_X then
self:setCurrentMtSlot("x", ev.value)
elseif ev.code == ABS_MT_POSITION_Y then
self:setCurrentMtSlot("y", ev.value)
-- code to emulate mt protocol on kobos
-- we "confirm" abs_x, abs_y only when pressure ~= 0
elseif ev.code == ABS_X then
self:setCurrentMtSlot("abs_x", ev.value)
elseif ev.code == ABS_Y then
self:setCurrentMtSlot("abs_y", ev.value)
elseif ev.code == ABS_PRESSURE then
if ev.value ~= 0 then
self:setCurrentMtSlot("id", 1)
self:confirmAbsxy()
else
self:cleanAbsxy()
self:setCurrentMtSlot("id", -1)
end
end
elseif ev.type == EV_SYN then
if ev.code == SYN_REPORT then
for _, MTSlot in pairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "timev", TimeVal:new(ev.time))
end
-- feed ev in all slots to state machine
local touch_ges = GestureDetector:feedEvent(self.MTSlots)
self.MTSlots = {}
if touch_ges then
return Event:new("Gesture",
GestureDetector:adjustGesCoordinate(touch_ges)
)
end
end
end
end
function Input:handlePhoenixTouchEv(ev)
-- Hack on handleTouchEV for the Kobo Aura
-- It seems to be using a custom protocol:
-- finger 0 down:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, x1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, y1);
-- input_mt_sync (elan_touch_data.input);
-- finger 1 down:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, x2);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, y2);
-- input_mt_sync (elan_touch_data.input);
-- finger 0 up:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, last_x);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, last_y);
-- input_mt_sync (elan_touch_data.input);
-- finger 1 up:
-- input_report_abs(elan_touch_data.input, ABS_MT_TRACKING_ID, 1);
-- input_report_abs(elan_touch_data.input, ABS_MT_TOUCH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_WIDTH_MAJOR, 0);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_X, last_x2);
-- input_report_abs(elan_touch_data.input, ABS_MT_POSITION_Y, last_y2);
-- input_mt_sync (elan_touch_data.input);
if ev.type == EV_ABS then
if #self.MTSlots == 0 then
table.insert(self.MTSlots, self:getMtSlot(self.cur_slot))
end
if ev.code == ABS_MT_TRACKING_ID then
if self.cur_slot ~= ev.value then
table.insert(self.MTSlots, self:getMtSlot(ev.value))
end
self.cur_slot = ev.value
self:setCurrentMtSlot("id", ev.value)
elseif ev.code == ABS_MT_TOUCH_MAJOR and ev.value == 0 then
self:setCurrentMtSlot("id", -1)
elseif ev.code == ABS_MT_POSITION_X then
self:setCurrentMtSlot("x", ev.value)
elseif ev.code == ABS_MT_POSITION_Y then
self:setCurrentMtSlot("y", ev.value)
end
elseif ev.type == EV_SYN then
if ev.code == SYN_REPORT then
for _, MTSlot in pairs(self.MTSlots) do
self:setMtSlot(MTSlot.slot, "timev", TimeVal:new(ev.time))
end
-- feed ev in all slots to state machine
local touch_ges = GestureDetector:feedEvent(self.MTSlots)
self.MTSlots = {}
if touch_ges then
return Event:new("Gesture",
GestureDetector:adjustGesCoordinate(touch_ges)
)
end
end
end
end
function Input:waitEvent(timeout_us, timeout_s)
-- wrapper for input.waitForEvents that will retry for some cases
local ok, ev
local wait_deadline = TimeVal:now() + TimeVal:new{
sec = timeout_s,
usec = timeout_us
}
while true do
if #self.timer_callbacks > 0 then
-- we don't block if there is any timer, set wait to 10us
while #self.timer_callbacks > 0 do
ok, ev = pcall(input.waitForEvent, 100)
if ok then break end
local tv_now = TimeVal:now()
if ((not timeout_us and not timeout_s) or tv_now < wait_deadline) then
-- check whether timer is up
if tv_now >= self.timer_callbacks[1].deadline then
local touch_ges = self.timer_callbacks[1].callback()
table.remove(self.timer_callbacks, 1)
if touch_ges then
-- Do we really need to clear all setTimeout after
-- decided a gesture? FIXME
Input.timer_callbacks = {}
return Event:new("Gesture",
GestureDetector:adjustGesCoordinate(touch_ges)
)
end -- EOF if touch_ges
end -- EOF if deadline reached
else
break
end -- EOF if not exceed wait timeout
end -- while #timer_callbacks > 0
else
ok, ev = pcall(input.waitForEvent, timeout_us)
end -- EOF if #timer_callbacks > 0
if ok then
break
end
if ev == "Waiting for input failed: timeout\n" then
-- don't report an error on timeout
ev = nil
break
elseif ev == "application forced to quit" then
os.exit(0)
end
--DEBUG("got error waiting for events:", ev)
if ev ~= "Waiting for input failed: 4\n" then
-- we only abort if the error is not EINTR
break
end
end
if ok and ev then
if DEBUG.is_on and ev then
DEBUG:logEv(ev)
end
ev = self:eventAdjustHook(ev)
if ev.type == EV_KEY then
DEBUG("key ev", ev)
return self:handleKeyBoardEv(ev)
elseif ev.type == EV_ABS or ev.type == EV_SYN then
return self:handleTouchEv(ev)
elseif ev.type == EV_MSC then
return self:handleMiscEv(ev)
else
-- some other kind of event that we do not know yet
return Event:new("GenericInput", ev)
end
elseif not ok and ev then
return Event:new("InputError", ev)
end
end
--[[
helper function for formatting sequence definitions for output
]]
function Input:sequenceToString(sequence)
local modifiers = {}
local keystring = {"",""} -- first entries reserved for modifier specification
for _, key in ipairs(sequence) do
if type(key) == "table" then
local alternatives = {}
for _, alternative in ipairs(key) do
table.insert(alternatives, alternative)
end
table.insert(keystring, "{")
table.insert(keystring, table.concat(alternatives, "|"))
table.insert(keystring, "}")
elseif self.modifiers[key] ~= nil then
table.insert(modifiers, key)
else
table.insert(keystring, key)
end
end
if #modifiers then
keystring[1] = table.concat(modifiers, "-")
keystring[2] = "-"
end
return table.concat(keystring)
end
-- initialize the GestureDectector
-- so it can modify our (Input) state
GestureDetector.input = Input
return Input

@ -1,6 +1,6 @@
local ConfirmBox = require("ui/widget/confirmbox")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -3,7 +3,7 @@ local ConfirmBox = require("ui/widget/confirmbox")
local NetworkMgr = require("ui/networkmgr")
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -1,5 +1,5 @@
local Font = require("ui/font")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Cache = require("cache")
local CacheItem = require("cacheitem")
local BlitBuffer = require("ffi/blitbuffer")

@ -1,2 +1,2 @@
-- compatibility wrapper
return require("ui/device").screen
return require("device").screen

@ -1,6 +1,6 @@
local DocumentRegistry = require("document/documentregistry")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DocSettings = require("docsettings")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -1,16 +1,11 @@
local Device = require("ui/device")
local Screen = require("ui/screen")
local Input = require("ui/input")
local Device = require("device")
local Screen = Device.screen
local Input = require("device").input
local Event = require("ui/event")
local util = require("ffi/util")
local DEBUG = require("dbg")
local _ = require("gettext")
-- initialize output module, this must be initialized before Input
Screen:init()
-- initialize the input handling
Input:init()
-- NOTE: Those have been confirmed on Kindle devices. Might be completely different on Kobo (except for AUTO)!
local WAVEFORM_MODE_INIT = 0x0 -- Screen goes to white (clears)
local WAVEFORM_MODE_DU = 0x1 -- Grey->white/grey->black
@ -121,7 +116,7 @@ function UIManager:init()
-- We don't really have an easy way to know if we're refreshing the UI, or a page, or if said page contains an image, so go with the highest fidelity option
self.full_refresh_waveform_mode = WAVEFORM_MODE_GC16
-- We spend much more time in the reader than the UI, and our UI isn't very graphic anyway, so go with the reader behavior
if Device:getModel() == "KindlePaperWhite2" then
if Device.model == "KindlePaperWhite2" then
self.partial_refresh_waveform_mode = WAVEFORM_MODE_REAGL
else
self.partial_refresh_waveform_mode = WAVEFORM_MODE_GL16_FAST
@ -337,9 +332,8 @@ function UIManager:run()
-- paint if repaint_all is request
-- paint also if current widget or any widget underneath is dirty
if self.repaint_all or dirty or self._dirty[widget.widget] then
widget.widget:paintTo(Screen.bb,
widget.x + Screen:offsetX(),
widget.y + Screen:offsetY())
widget.widget:paintTo(Screen.bb, widget.x, widget.y)
if self._dirty[widget.widget] == "auto" then
request_full_refresh = true
end

@ -2,7 +2,7 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local Math = require("optmath")
local DEBUG = require("dbg")

@ -7,7 +7,7 @@ local GestureRange = require("ui/gesturerange")
local FrameContainer = require("ui/widget/container/framecontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local DEBUG = require("dbg")
local _ = require("gettext")
local Blitbuffer = require("ffi/blitbuffer")

@ -2,11 +2,11 @@ local ButtonTable = require("ui/widget/buttontable")
local InputContainer = require("ui/widget/container/inputcontainer")
local FrameContainer = require("ui/widget/container/framecontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local Geom = require("ui/geometry")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Input = require("device").input
local Screen = require("device").screen
local UIManager = require("ui/uimanager")
local _ = require("gettext")
local Blitbuffer = require("ffi/blitbuffer")

@ -3,7 +3,7 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local LineWidget = require("ui/widget/linewidget")
local Button = require("ui/widget/button")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Blitbuffer = require("ffi/blitbuffer")

@ -11,7 +11,7 @@ local ProgressWidget = require("ui/widget/progresswidget")
local ToggleSwitch = require("ui/widget/toggleswitch")
local ConfirmBox = require("ui/widget/confirmbox")
local Font = require("ui/font")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local RectSpan = require("ui/widget/rectspan")
@ -20,7 +20,7 @@ local HorizontalGroup = require("ui/widget/horizontalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local VerticalGroup = require("ui/widget/verticalgroup")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -9,10 +9,10 @@ local HorizontalSpan = require("ui/widget/horizontalspan")
local ButtonTable = require("ui/widget/buttontable")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Device = require("device")
local Geom = require("ui/geometry")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Input = require("device").input
local Screen = require("device").screen
local Font = require("ui/font")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -15,8 +15,8 @@ local LineWidget = require("ui/widget/linewidget")
local GestureRange = require("ui/gesturerange")
local Button = require("ui/widget/button")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local Geom = require("ui/geometry")
local Event = require("ui/event")
local Font = require("ui/font")

@ -1,8 +1,8 @@
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Menu = require("ui/widget/menu")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local util = require("ffi/util")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -1,7 +1,7 @@
local TextWidget = require("ui/widget/textwidget")
local RenderText = require("ui/rendertext")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
--[[
FixedTextWidget

@ -1,7 +1,7 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local Font = require("ui/font")
local Device = require("ui/device")
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local FrameContainer = require("ui/widget/container/framecontainer")
local HorizontalGroup = require("ui/widget/horizontalgroup")
@ -10,8 +10,8 @@ local TextBoxWidget = require("ui/widget/textboxwidget")
local HorizontalSpan = require("ui/widget/horizontalspan")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Input = require("device").input
local Screen = require("device").screen
local _ = require("gettext")
local Blitbuffer = require("ffi/blitbuffer")

@ -8,7 +8,7 @@ local LineWidget = require("ui/widget/linewidget")
local InputText = require("ui/widget/inputtext")
local RenderText = require("ui/rendertext")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Font = require("ui/font")
local Blitbuffer = require("ffi/blitbuffer")

@ -6,8 +6,8 @@ local VirtualKeyboard = require("ui/widget/virtualkeyboard")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Font = require("ui/font")
local DEBUG = require("dbg")
local util = require("ffi/util")

@ -1,9 +1,9 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Device = require("device")
local Blitbuffer = require("ffi/blitbuffer")
local LinkBox = InputContainer:new{

@ -5,7 +5,7 @@ local InputDialog = require("ui/widget/inputdialog")
local InputText = require("ui/widget/inputtext")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DEBUG = require("dbg")
local _ = require("gettext")
local Blitbuffer = require("ffi/blitbuffer")

@ -18,9 +18,9 @@ local Button = require("ui/widget/button")
local GestureRange = require("ui/gesturerange")
local Font = require("ui/font")
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Input = require("ui/input")
local Device = require("device")
local Screen = require("device").screen
local Input = require("device").input
local UIManager = require("ui/uimanager")
local RenderText = require("ui/rendertext")
local InfoMessage = require("ui/widget/infomessage")
@ -538,7 +538,7 @@ function Menu:init()
self.ges_events.Close = self.on_close_ges
end
if Device:hasNoKeyboard() then
if not Device:hasKeyboard() then
-- remove menu item shortcut for K4
self.is_enable_shortcut = false
end

@ -6,7 +6,7 @@ local InputDialog = require("ui/widget/inputdialog")
local InputText = require("ui/widget/inputtext")
local UIManager = require("ui/uimanager")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Screen = require("device").screen
local DEBUG = require("dbg")
local _ = require("gettext")
local util = require("ffi/util")

@ -4,11 +4,11 @@ local CenterContainer = require("ui/widget/container/centercontainer")
local TextWidget = require("ui/widget/textwidget")
local Font = require("ui/font")
local Geom = require("ui/geometry")
local Device = require("ui/device")
local Device = require("device")
local UIManager = require("ui/uimanager")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local Input = require("ui/input")
local Screen = require("ui/screen")
local Input = require("device").input
local Screen = require("device").screen
local Blitbuffer = require("ffi/blitbuffer")
--[[

@ -7,8 +7,8 @@ local NetworkMgr = require("ui/networkmgr")
local UIManager = require("ui/uimanager")
local CacheItem = require("cacheitem")
local Menu = require("ui/widget/menu")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local url = require('socket.url')
local util = require("ffi/util")
local Cache = require("cache")

@ -4,10 +4,10 @@ local VerticalScrollBar = require("ui/widget/verticalscrollbar")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local Device = require("ui/device")
local Device = require("device")
local Blitbuffer = require("ffi/blitbuffer")
--[[

@ -1,7 +1,7 @@
local Blitbuffer = require("ffi/blitbuffer")
local Widget = require("ui/widget/widget")
local RenderText = require("ui/rendertext")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Geom = require("ui/geometry")
-- TODO: rename string:gsplit definition

@ -1,5 +1,5 @@
local Widget = require("ui/widget/widget")
local Screen = require("ui/screen")
local Screen = require("device").screen
local RenderText = require("ui/rendertext")
local Geom = require("ui/geometry")
local Blitbuffer = require("ffi/blitbuffer")

@ -7,8 +7,8 @@ local Font = require("ui/font")
local Geom = require("ui/geometry")
local RenderText = require("ui/rendertext")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local DEBUG = require("dbg")
local Blitbuffer = require("ffi/blitbuffer")

@ -14,8 +14,8 @@ local IconButton = require("ui/widget/iconbutton")
local GestureRange = require("ui/gesturerange")
local Button = require("ui/widget/button")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Geom = require("ui/geometry")
local Font = require("ui/font")
local DEBUG = require("dbg")

@ -10,8 +10,8 @@ local ImageWidget = require("ui/widget/imagewidget")
local TextWidget = require("ui/widget/textwidget")
local Font = require("ui/font")
local Geom = require("ui/geometry")
local Screen = require("ui/screen")
local Device = require("ui/device")
local Screen = require("device").screen
local Device = require("device")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local DEBUG = require("dbg")

@ -4,7 +4,7 @@ local InfoMessage = require("ui/widget/infomessage")
local DocSettings = require("docsettings")
local NetworkMgr = require("ui/networkmgr")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local DEBUG = require("dbg")
local _ = require("gettext")

@ -10,7 +10,7 @@ local InfoMessage = require("ui/widget/infomessage")
local TextWidget = require("ui/widget/textwidget")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local Screen = require("ui/screen")
local Screen = require("device").screen
local Event = require("ui/event")
local Font = require("ui/font")
local ltn12 = require("ltn12")

@ -30,45 +30,23 @@ end
local lfs = require("libs/libkoreader-lfs")
local UIManager = require("ui/uimanager")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local input = require("ffi/input")
local DEBUG = require("dbg")
local Profiler = nil
local function exitReader()
local KindlePowerD = require("ui/device/kindlepowerd")
local ReaderActivityIndicator = require("apps/reader/modules/readeractivityindicator")
G_reader_settings:close()
-- Close lipc handles
KindlePowerD:coda()
ReaderActivityIndicator:coda()
if not util.isEmulated() then
if Device:isKindle3() or (Device:getModel() == "KindleDXG") then
-- send double menu key press events to trigger screen refresh
os.execute("echo 'send 139' > /proc/keypad;echo 'send 139' > /proc/keypad")
end
if Device:isTouchDevice() and Device.survive_screen_saver then
-- If needed, hack the swipe to unlock screen
if Device:isSpecialOffers() then
local dev = Device:getTouchInputDev()
if dev then
local width, height = Screen:getWidth(), Screen:getHeight()
input.fakeTapInput(dev,
math.min(width, height)/2,
math.max(width, height)-30
)
end
end
end
end
input.closeAll()
Screen:close()
-- shutdown hardware abstraction
Device:exit()
if Profiler then Profiler.stop() end
os.exit(0)

@ -11,11 +11,11 @@ einkfb = require("ffi/framebuffer")
einkfb.dummy = true
-- init output device
local Screen = require("ui/screen")
local Screen = require("device").screen
Screen:init()
-- init input device (do not show SDL window)
local Input = require("ui/input")
local Input = require("device").input
Input.dummy = true
-- turn on debug

@ -35,8 +35,8 @@ local InputText = require("ui/widget/inputtext")
local DocumentRegistry = require("document/documentregistry")
local ReaderUI = require("apps/reader/readerui")
local Dbg = require("dbg")
local Device = require("ui/device")
local Screen = require("ui/screen")
local Device = require("device")
local Screen = require("device").screen
local Blitbuffer = require("ffi/blitbuffer")
-----------------------------------------------------

Loading…
Cancel
Save