diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index e0dfad963..79f9a5590 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -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 "." diff --git a/frontend/apps/filemanager/filemanagerhistory.lua b/frontend/apps/filemanager/filemanagerhistory.lua index cd266a46b..27a013ddc 100644 --- a/frontend/apps/filemanager/filemanagerhistory.lua +++ b/frontend/apps/filemanager/filemanagerhistory.lua @@ -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") diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index 06f399b5d..c15893915 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -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(), }, }) diff --git a/frontend/apps/filemanager/filemanagersearch.lua b/frontend/apps/filemanager/filemanagersearch.lua index 14be06b11..5efa7c1b6 100644 --- a/frontend/apps/filemanager/filemanagersearch.lua +++ b/frontend/apps/filemanager/filemanagersearch.lua @@ -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") diff --git a/frontend/apps/filemanager/filemanagersetdefaults.lua b/frontend/apps/filemanager/filemanagersetdefaults.lua index 72968ec23..61a926739 100644 --- a/frontend/apps/filemanager/filemanagersetdefaults.lua +++ b/frontend/apps/filemanager/filemanagersetdefaults.lua @@ -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") diff --git a/frontend/apps/opdscatalog/opdscatalog.lua b/frontend/apps/opdscatalog/opdscatalog.lua index a7adf0420..d34fe04a7 100644 --- a/frontend/apps/opdscatalog/opdscatalog.lua +++ b/frontend/apps/opdscatalog/opdscatalog.lua @@ -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") diff --git a/frontend/apps/reader/modules/readeractivityindicator.lua b/frontend/apps/reader/modules/readeractivityindicator.lua index 035aacecc..f8ccdd3a8 100644 --- a/frontend/apps/reader/modules/readeractivityindicator.lua +++ b/frontend/apps/reader/modules/readeractivityindicator.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerbookmark.lua b/frontend/apps/reader/modules/readerbookmark.lua index a94326b96..fcda25500 100644 --- a/frontend/apps/reader/modules/readerbookmark.lua +++ b/frontend/apps/reader/modules/readerbookmark.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerconfig.lua b/frontend/apps/reader/modules/readerconfig.lua index feb2dc6c1..10c4c281a 100644 --- a/frontend/apps/reader/modules/readerconfig.lua +++ b/frontend/apps/reader/modules/readerconfig.lua @@ -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") diff --git a/frontend/apps/reader/modules/readercropping.lua b/frontend/apps/reader/modules/readercropping.lua index a95961d81..fa08587cd 100644 --- a/frontend/apps/reader/modules/readercropping.lua +++ b/frontend/apps/reader/modules/readercropping.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerdictionary.lua b/frontend/apps/reader/modules/readerdictionary.lua index 398df95e5..692f4e5fb 100644 --- a/frontend/apps/reader/modules/readerdictionary.lua +++ b/frontend/apps/reader/modules/readerdictionary.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerdogear.lua b/frontend/apps/reader/modules/readerdogear.lua index 616455e0d..ee42ce0b5 100644 --- a/frontend/apps/reader/modules/readerdogear.lua +++ b/frontend/apps/reader/modules/readerdogear.lua @@ -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{} diff --git a/frontend/apps/reader/modules/readerflipping.lua b/frontend/apps/reader/modules/readerflipping.lua index b2d9be9bf..f239de88f 100644 --- a/frontend/apps/reader/modules/readerflipping.lua +++ b/frontend/apps/reader/modules/readerflipping.lua @@ -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{ diff --git a/frontend/apps/reader/modules/readerfont.lua b/frontend/apps/reader/modules/readerfont.lua index 151ef8fe1..609a5bec6 100644 --- a/frontend/apps/reader/modules/readerfont.lua +++ b/frontend/apps/reader/modules/readerfont.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerfooter.lua b/frontend/apps/reader/modules/readerfooter.lua index 5de2eb6f9..f91c80abb 100644 --- a/frontend/apps/reader/modules/readerfooter.lua +++ b/frontend/apps/reader/modules/readerfooter.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerfrontlight.lua b/frontend/apps/reader/modules/readerfrontlight.lua index 0ac5fc6e2..b6bfe347b 100644 --- a/frontend/apps/reader/modules/readerfrontlight.lua +++ b/frontend/apps/reader/modules/readerfrontlight.lua @@ -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= { diff --git a/frontend/apps/reader/modules/readergoto.lua b/frontend/apps/reader/modules/readergoto.lua index 9f2a01759..9abff8f09 100644 --- a/frontend/apps/reader/modules/readergoto.lua +++ b/frontend/apps/reader/modules/readergoto.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 9c6892a24..b1b5829d0 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index 83f4fba7e..fa1d2d855 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -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") diff --git a/frontend/apps/reader/modules/readermenu.lua b/frontend/apps/reader/modules/readermenu.lua index da688f5bf..bc1e3f285 100644 --- a/frontend/apps/reader/modules/readermenu.lua +++ b/frontend/apps/reader/modules/readermenu.lua @@ -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(), }, }) diff --git a/frontend/apps/reader/modules/readerpaging.lua b/frontend/apps/reader/modules/readerpaging.lua index 7a77a7a8d..1c685af7a 100644 --- a/frontend/apps/reader/modules/readerpaging.lua +++ b/frontend/apps/reader/modules/readerpaging.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerpanning.lua b/frontend/apps/reader/modules/readerpanning.lua index d274c9849..ace5b2981 100644 --- a/frontend/apps/reader/modules/readerpanning.lua +++ b/frontend/apps/reader/modules/readerpanning.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerrolling.lua b/frontend/apps/reader/modules/readerrolling.lua index efe29bb8c..a35539c07 100644 --- a/frontend/apps/reader/modules/readerrolling.lua +++ b/frontend/apps/reader/modules/readerrolling.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerrotation.lua b/frontend/apps/reader/modules/readerrotation.lua index 356141b6b..297e48c01 100644 --- a/frontend/apps/reader/modules/readerrotation.lua +++ b/frontend/apps/reader/modules/readerrotation.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerscreenshot.lua b/frontend/apps/reader/modules/readerscreenshot.lua index 7f151a5a3..0698c468f 100644 --- a/frontend/apps/reader/modules/readerscreenshot.lua +++ b/frontend/apps/reader/modules/readerscreenshot.lua @@ -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") diff --git a/frontend/apps/reader/modules/readertoc.lua b/frontend/apps/reader/modules/readertoc.lua index a444e6686..c69b6ddd0 100644 --- a/frontend/apps/reader/modules/readertoc.lua +++ b/frontend/apps/reader/modules/readertoc.lua @@ -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") diff --git a/frontend/apps/reader/modules/readertypeset.lua b/frontend/apps/reader/modules/readertypeset.lua index 4d172eaf3..92327e054 100644 --- a/frontend/apps/reader/modules/readertypeset.lua +++ b/frontend/apps/reader/modules/readertypeset.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index cd783d159..bf1bc3632 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerwikipedia.lua b/frontend/apps/reader/modules/readerwikipedia.lua index 53bf31f8c..1533b7973 100644 --- a/frontend/apps/reader/modules/readerwikipedia.lua +++ b/frontend/apps/reader/modules/readerwikipedia.lua @@ -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") diff --git a/frontend/apps/reader/modules/readerzooming.lua b/frontend/apps/reader/modules/readerzooming.lua index 61ae2cb87..17511dd90 100644 --- a/frontend/apps/reader/modules/readerzooming.lua +++ b/frontend/apps/reader/modules/readerzooming.lua @@ -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") diff --git a/frontend/apps/reader/readerui.lua b/frontend/apps/reader/readerui.lua index 6426dc221..2cd9d5c5c 100644 --- a/frontend/apps/reader/readerui.lua +++ b/frontend/apps/reader/readerui.lua @@ -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") diff --git a/frontend/device.lua b/frontend/device.lua new file mode 100644 index 000000000..d68c5bbce --- /dev/null +++ b/frontend/device.lua @@ -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 diff --git a/frontend/device/android/device.lua b/frontend/device/android/device.lua new file mode 100644 index 000000000..a75a40f49 --- /dev/null +++ b/frontend/device/android/device.lua @@ -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 diff --git a/frontend/device/android/event_map.lua b/frontend/device/android/event_map.lua new file mode 100644 index 000000000..ddb035ddf --- /dev/null +++ b/frontend/device/android/event_map.lua @@ -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 +} diff --git a/frontend/ui/device/androidpowerd.lua b/frontend/device/android/powerd.lua similarity index 92% rename from frontend/ui/device/androidpowerd.lua rename to frontend/device/android/powerd.lua index 518ba545c..634ff87a2 100644 --- a/frontend/ui/device/androidpowerd.lua +++ b/frontend/device/android/powerd.lua @@ -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", diff --git a/frontend/device/emulator/device.lua b/frontend/device/emulator/device.lua new file mode 100644 index 000000000..711365ccc --- /dev/null +++ b/frontend/device/emulator/device.lua @@ -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 diff --git a/frontend/device/emulator/event_map_sdl.lua b/frontend/device/emulator/event_map_sdl.lua new file mode 100644 index 000000000..e102f229b --- /dev/null +++ b/frontend/device/emulator/event_map_sdl.lua @@ -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 +} diff --git a/frontend/device/emulator/event_map_sdl2.lua b/frontend/device/emulator/event_map_sdl2.lua new file mode 100644 index 000000000..8f68be4d5 --- /dev/null +++ b/frontend/device/emulator/event_map_sdl2.lua @@ -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 +} diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua new file mode 100644 index 000000000..8b3dc7f41 --- /dev/null +++ b/frontend/device/generic/device.lua @@ -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//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 diff --git a/frontend/ui/device/basepowerd.lua b/frontend/device/generic/powerd.lua similarity index 98% rename from frontend/ui/device/basepowerd.lua rename to frontend/device/generic/powerd.lua index 5c81b17ca..9463d7960 100644 --- a/frontend/ui/device/basepowerd.lua +++ b/frontend/device/generic/powerd.lua @@ -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, diff --git a/frontend/ui/gesturedetector.lua b/frontend/device/gesturedetector.lua similarity index 97% rename from frontend/ui/gesturedetector.lua rename to frontend/device/gesturedetector.lua index f19c2af10..5f6784e90 100644 --- a/frontend/ui/gesturedetector.lua +++ b/frontend/device/gesturedetector.lua @@ -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" diff --git a/frontend/device/input.lua b/frontend/device/input.lua new file mode 100644 index 000000000..a1e5d6216 --- /dev/null +++ b/frontend/device/input.lua @@ -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 +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 diff --git a/frontend/device/key.lua b/frontend/device/key.lua new file mode 100644 index 000000000..5589ac91b --- /dev/null +++ b/frontend/device/key.lua @@ -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 diff --git a/frontend/device/kindle/device.lua b/frontend/device/kindle/device.lua new file mode 100644 index 000000000..8de7d86b2 --- /dev/null +++ b/frontend/device/kindle/device.lua @@ -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) diff --git a/frontend/device/kindle/event_map_keyboard.lua b/frontend/device/kindle/event_map_keyboard.lua new file mode 100644 index 000000000..acb13e554 --- /dev/null +++ b/frontend/device/kindle/event_map_keyboard.lua @@ -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] +} diff --git a/frontend/device/kindle/event_map_kindle4.lua b/frontend/device/kindle/event_map_kindle4.lua new file mode 100644 index 000000000..8520213e0 --- /dev/null +++ b/frontend/device/kindle/event_map_kindle4.lua @@ -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", +} diff --git a/frontend/ui/device/kindlepowerd.lua b/frontend/device/kindle/powerd.lua similarity index 59% rename from frontend/ui/device/kindlepowerd.lua rename to frontend/device/kindle/powerd.lua index 18397f828..29dc80f44 100644 --- a/frontend/ui/device/kindlepowerd.lua +++ b/frontend/device/kindle/powerd.lua @@ -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 diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua new file mode 100644 index 000000000..44ef60d1e --- /dev/null +++ b/frontend/device/kobo/device.lua @@ -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 + + + diff --git a/frontend/ui/device/kobopowerd.lua b/frontend/device/kobo/powerd.lua similarity index 95% rename from frontend/ui/device/kobopowerd.lua rename to frontend/device/kobo/powerd.lua index 103ed5446..bd11c3898 100644 --- a/frontend/ui/device/kobopowerd.lua +++ b/frontend/device/kobo/powerd.lua @@ -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, diff --git a/frontend/device/screen.lua b/frontend/device/screen.lua new file mode 100644 index 000000000..81ef62f9d --- /dev/null +++ b/frontend/device/screen.lua @@ -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 diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 7cbeca101..b2795e237 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -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") diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua index 368a78e37..d3cf90d6a 100644 --- a/frontend/document/koptinterface.lua +++ b/frontend/document/koptinterface.lua @@ -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") diff --git a/frontend/ui/data/creoptions.lua b/frontend/ui/data/creoptions.lua index 3c5e254a6..a18717f4d 100644 --- a/frontend/ui/data/creoptions.lua +++ b/frontend/ui/data/creoptions.lua @@ -1,4 +1,4 @@ -local Screen = require("ui/screen") +local Screen = require("device").screen local S = require("ui/data/strings") local _ = require("gettext") diff --git a/frontend/ui/data/koptoptions.lua b/frontend/ui/data/koptoptions.lua index 685611928..89344baf0 100644 --- a/frontend/ui/data/koptoptions.lua +++ b/frontend/ui/data/koptoptions.lua @@ -1,4 +1,4 @@ -local Screen = require("ui/screen") +local Screen = require("device").screen local S = require("ui/data/strings") local _ = require("gettext") diff --git a/frontend/ui/device.lua b/frontend/ui/device.lua deleted file mode 100644 index f5c188ee3..000000000 --- a/frontend/ui/device.lua +++ /dev/null @@ -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 diff --git a/frontend/ui/device/screen.lua b/frontend/ui/device/screen.lua deleted file mode 100644 index 490b33ce1..000000000 --- a/frontend/ui/device/screen.lua +++ /dev/null @@ -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 - diff --git a/frontend/ui/elements/screen_dpi_menu_table.lua b/frontend/ui/elements/screen_dpi_menu_table.lua new file mode 100644 index 000000000..2dcbcb029 --- /dev/null +++ b/frontend/ui/elements/screen_dpi_menu_table.lua @@ -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, + }, + }, + } +} diff --git a/frontend/ui/font.lua b/frontend/ui/font.lua index 629dd8de1..249b3a34d 100644 --- a/frontend/ui/font.lua +++ b/frontend/ui/font.lua @@ -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 = { diff --git a/frontend/ui/input.lua b/frontend/ui/input.lua deleted file mode 100644 index dd2db85e7..000000000 --- a/frontend/ui/input.lua +++ /dev/null @@ -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 -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() 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 diff --git a/frontend/ui/networkmgr.lua b/frontend/ui/networkmgr.lua index 293d69a86..57a5da0fb 100644 --- a/frontend/ui/networkmgr.lua +++ b/frontend/ui/networkmgr.lua @@ -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") diff --git a/frontend/ui/otamanager.lua b/frontend/ui/otamanager.lua index 4f01f901e..571f5a5f0 100644 --- a/frontend/ui/otamanager.lua +++ b/frontend/ui/otamanager.lua @@ -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") diff --git a/frontend/ui/rendertext.lua b/frontend/ui/rendertext.lua index 1ad5886e3..7747aa043 100644 --- a/frontend/ui/rendertext.lua +++ b/frontend/ui/rendertext.lua @@ -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") diff --git a/frontend/ui/screen.lua b/frontend/ui/screen.lua index 784a9eac9..ddd310d41 100644 --- a/frontend/ui/screen.lua +++ b/frontend/ui/screen.lua @@ -1,2 +1,2 @@ -- compatibility wrapper -return require("ui/device").screen +return require("device").screen diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua index 0b79eda3b..b28d79b63 100644 --- a/frontend/ui/screensaver.lua +++ b/frontend/ui/screensaver.lua @@ -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") diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 72a5d234a..829fdcb0b 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -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 diff --git a/frontend/ui/widget/bboxwidget.lua b/frontend/ui/widget/bboxwidget.lua index b5ab79431..ff108f47d 100644 --- a/frontend/ui/widget/bboxwidget.lua +++ b/frontend/ui/widget/bboxwidget.lua @@ -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") diff --git a/frontend/ui/widget/button.lua b/frontend/ui/widget/button.lua index 297a36f9d..66f2cbb06 100644 --- a/frontend/ui/widget/button.lua +++ b/frontend/ui/widget/button.lua @@ -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") diff --git a/frontend/ui/widget/buttondialog.lua b/frontend/ui/widget/buttondialog.lua index ef355bcf5..0383c3dbd 100644 --- a/frontend/ui/widget/buttondialog.lua +++ b/frontend/ui/widget/buttondialog.lua @@ -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") diff --git a/frontend/ui/widget/buttontable.lua b/frontend/ui/widget/buttontable.lua index 9ab41ed66..fcdfadc73 100644 --- a/frontend/ui/widget/buttontable.lua +++ b/frontend/ui/widget/buttontable.lua @@ -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") diff --git a/frontend/ui/widget/configdialog.lua b/frontend/ui/widget/configdialog.lua index bc680a08c..503d1bb9b 100644 --- a/frontend/ui/widget/configdialog.lua +++ b/frontend/ui/widget/configdialog.lua @@ -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") diff --git a/frontend/ui/widget/confirmbox.lua b/frontend/ui/widget/confirmbox.lua index fd7a02427..856e62f08 100644 --- a/frontend/ui/widget/confirmbox.lua +++ b/frontend/ui/widget/confirmbox.lua @@ -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") diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 275e0089b..dd9b1d0de 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -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") diff --git a/frontend/ui/widget/filechooser.lua b/frontend/ui/widget/filechooser.lua index 6a157cfe3..386c4d2e4 100644 --- a/frontend/ui/widget/filechooser.lua +++ b/frontend/ui/widget/filechooser.lua @@ -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") diff --git a/frontend/ui/widget/fixedtextwidget.lua b/frontend/ui/widget/fixedtextwidget.lua index 8febb43b6..ad3847993 100644 --- a/frontend/ui/widget/fixedtextwidget.lua +++ b/frontend/ui/widget/fixedtextwidget.lua @@ -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 diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index adb8f4731..f91807ff3 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -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") diff --git a/frontend/ui/widget/inputdialog.lua b/frontend/ui/widget/inputdialog.lua index 6e49f7251..4eef63062 100644 --- a/frontend/ui/widget/inputdialog.lua +++ b/frontend/ui/widget/inputdialog.lua @@ -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") diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index 2c4af2c7d..ae7b6bc96 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -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") diff --git a/frontend/ui/widget/linkbox.lua b/frontend/ui/widget/linkbox.lua index 8a0173860..29f72a0e3 100644 --- a/frontend/ui/widget/linkbox.lua +++ b/frontend/ui/widget/linkbox.lua @@ -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{ diff --git a/frontend/ui/widget/logindialog.lua b/frontend/ui/widget/logindialog.lua index 88348071c..1b147be66 100644 --- a/frontend/ui/widget/logindialog.lua +++ b/frontend/ui/widget/logindialog.lua @@ -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") diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index a00ca47de..cffe46ca9 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -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 diff --git a/frontend/ui/widget/multiinputdialog.lua b/frontend/ui/widget/multiinputdialog.lua index ec81fd31c..572c0f484 100644 --- a/frontend/ui/widget/multiinputdialog.lua +++ b/frontend/ui/widget/multiinputdialog.lua @@ -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") diff --git a/frontend/ui/widget/notification.lua b/frontend/ui/widget/notification.lua index 1d28af32d..4df000238 100644 --- a/frontend/ui/widget/notification.lua +++ b/frontend/ui/widget/notification.lua @@ -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") --[[ diff --git a/frontend/ui/widget/opdsbrowser.lua b/frontend/ui/widget/opdsbrowser.lua index eba63c93e..da7d7e8af 100644 --- a/frontend/ui/widget/opdsbrowser.lua +++ b/frontend/ui/widget/opdsbrowser.lua @@ -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") diff --git a/frontend/ui/widget/scrolltextwidget.lua b/frontend/ui/widget/scrolltextwidget.lua index 3674c4f44..990dbf967 100644 --- a/frontend/ui/widget/scrolltextwidget.lua +++ b/frontend/ui/widget/scrolltextwidget.lua @@ -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") --[[ diff --git a/frontend/ui/widget/textboxwidget.lua b/frontend/ui/widget/textboxwidget.lua index 935f6b962..b7bfd251d 100644 --- a/frontend/ui/widget/textboxwidget.lua +++ b/frontend/ui/widget/textboxwidget.lua @@ -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 diff --git a/frontend/ui/widget/textwidget.lua b/frontend/ui/widget/textwidget.lua index bbe0a7cfe..3c0972408 100644 --- a/frontend/ui/widget/textwidget.lua +++ b/frontend/ui/widget/textwidget.lua @@ -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") diff --git a/frontend/ui/widget/toggleswitch.lua b/frontend/ui/widget/toggleswitch.lua index 909333573..bef4ccf19 100644 --- a/frontend/ui/widget/toggleswitch.lua +++ b/frontend/ui/widget/toggleswitch.lua @@ -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") diff --git a/frontend/ui/widget/touchmenu.lua b/frontend/ui/widget/touchmenu.lua index 080dcec8b..e68537277 100644 --- a/frontend/ui/widget/touchmenu.lua +++ b/frontend/ui/widget/touchmenu.lua @@ -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") diff --git a/frontend/ui/widget/virtualkeyboard.lua b/frontend/ui/widget/virtualkeyboard.lua index 426c2bbad..1dd73b90c 100644 --- a/frontend/ui/widget/virtualkeyboard.lua +++ b/frontend/ui/widget/virtualkeyboard.lua @@ -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") diff --git a/plugins/evernote.koplugin/main.lua b/plugins/evernote.koplugin/main.lua index 6fc6c2c2d..177360532 100644 --- a/plugins/evernote.koplugin/main.lua +++ b/plugins/evernote.koplugin/main.lua @@ -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") diff --git a/plugins/zsync.koplugin/main.lua b/plugins/zsync.koplugin/main.lua index 9310a2ac6..61f0f6eff 100644 --- a/plugins/zsync.koplugin/main.lua +++ b/plugins/zsync.koplugin/main.lua @@ -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") diff --git a/reader.lua b/reader.lua index 14b464ac7..a80218887 100755 --- a/reader.lua +++ b/reader.lua @@ -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) diff --git a/spec/unit/commonrequire.lua b/spec/unit/commonrequire.lua index 7e1637612..d961671f2 100644 --- a/spec/unit/commonrequire.lua +++ b/spec/unit/commonrequire.lua @@ -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 diff --git a/utils/wtest.lua b/utils/wtest.lua index ff097ac08..dd44ecfbd 100755 --- a/utils/wtest.lua +++ b/utils/wtest.lua @@ -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") -----------------------------------------------------