From 893909146d6e406ca36c5f2d95b82526a4ed6167 Mon Sep 17 00:00:00 2001 From: ezdiy Date: Sat, 17 Oct 2020 12:59:24 +0200 Subject: [PATCH] Pocketbook: use raw input I/O (#6791) This allows for better energy efficiency (no more 50Hz tick poll), as well as lower input lag / higher precision - touch events are native linux ones. In addition, auto off/suspend plugin is used in this mode, as we need to trigger (timed) sleep / poweroff on our own, since the OS ones will no longer work whenever koreader has focus. This is for rooted devices only, and possibly somewhat FW specific, so enabled only on PB740-2 where it's reasonably tested. --- frontend/device/pocketbook/device.lua | 53 +++++++++++++++++++++++++-- frontend/device/pocketbook/powerd.lua | 1 - frontend/ui/uimanager.lua | 2 + platform/pocketbook/koreader.app | 3 ++ plugins/autosuspend.koplugin/main.lua | 29 ++++++++++++--- 5 files changed, 77 insertions(+), 11 deletions(-) diff --git a/frontend/device/pocketbook/device.lua b/frontend/device/pocketbook/device.lua index 1fcbf5b9b..9f26cfe7c 100644 --- a/frontend/device/pocketbook/device.lua +++ b/frontend/device/pocketbook/device.lua @@ -42,6 +42,19 @@ local PocketBook = Generic:new{ -- NTX chipsets *should* work (PB631), but in case it doesn't on your device, set this to "no" in here. canHWInvert = yes, + -- If we can access the necessary devices, input events can be handled directly. + -- This improves latency (~40ms), as well as power usage - we can spend more time asleep, + -- instead of busy looping at 50Hz the way inkview insists on doing. + -- In case this method fails (no root), we fallback to classic inkview api. + raw_input = nil, --[[{ + -- value or function to adjust touch matrix orientiation. + touch_rotation = -3+4, + -- Works same as input.event_map, but for raw input EV_KEY translation + keymap = { [scan] = event }, + }]] + -- Runtime state: whether raw input is actually used + is_using_raw_input = nil, + -- Private per-model kludges _fb_init = function() end, _model_init = function() end, @@ -69,6 +82,9 @@ local function isB288(fb) end function PocketBook:init() + local raw_input = self.raw_input + local touch_rotation = raw_input and raw_input.touch_rotation or 0 + self.screen = require("ffi/framebuffer_mxcfb"):new { device = self, debug = logger.dbg, @@ -87,8 +103,14 @@ function PocketBook:init() end return self._fb_init(fb, finfo, vinfo) end, + -- raw touch input orientiation is different from the screen + getTouchRotation = function(fb) + if type(touch_rotation) == "function" then + return touch_rotation(self, fb:getRotationMode()) + end + return (4 + fb:getRotationMode() + touch_rotation) % 4 + end, } - self.powerd = require("device/pocketbook/powerd"):new{device = self} -- Whenever we lose focus, but also get suspended for real (we can't reliably tell atm), -- plugins need to be notified to stop doing foreground stuff, and vice versa. To this end, @@ -98,7 +120,8 @@ function PocketBook:init() self.input = require("device/input"):new{ device = self, - event_map = { + raw_input = raw_input, + event_map = setmetatable({ [C.KEY_MENU] = "Menu", [C.KEY_PREV] = "LPgBack", [C.KEY_NEXT] = "LPgFwd", @@ -107,7 +130,7 @@ function PocketBook:init() [C.KEY_LEFT] = "Left", [C.KEY_RIGHT] = "Right", [C.KEY_OK] = "Press", - }, + }, {__index=raw_input and raw_input.keymap or {}}), handleMiscEv = function(this, ev) local ui = require("ui/uimanager") if ev.code == C.EVT_HIDE or ev.code == C.EVT_BACKGROUND then @@ -156,7 +179,17 @@ function PocketBook:init() end) self._model_init() - self.input.open() + if (not self.input.raw_input) or (not pcall(self.input.open, self.input, self.raw_input)) then + inkview.OpenScreen() + -- Raw mode open failed (no permissions?), so we'll run the usual way. + -- Disable touch coordinate translation as inkview will do that. + self.input.raw_input = nil + self.input:open() + touch_rotation = 0 + else + self.canSuspend = yes + end + self.powerd = require("device/pocketbook/powerd"):new{device = self} self:setAutoStandby(true) Generic.init(self) end @@ -238,6 +271,10 @@ function PocketBook:powerOff() inkview.PowerOff() end +function PocketBook:suspend() + inkview.SendGlobalRequest(C.REQ_KEYLOCK) +end + function PocketBook:reboot() inkview.iv_ipc_request(C.MSG_REBOOT, 1, nil, 0, 0) end @@ -464,6 +501,14 @@ local PocketBook740_2 = PocketBook:new{ isAlwaysPortrait = yes, usingForcedRotation = landscape_ccw, hasNaturalLight = yes, + raw_input = { + touch_rotation = -1, + keymap = { + [115] = "Menu", + [109] = "LPgFwd", + [104] = "LPgBack", + } + } } -- PocketBook Color Lux (801) diff --git a/frontend/device/pocketbook/powerd.lua b/frontend/device/pocketbook/powerd.lua index 8f3d3b233..171fa7abf 100644 --- a/frontend/device/pocketbook/powerd.lua +++ b/frontend/device/pocketbook/powerd.lua @@ -14,7 +14,6 @@ local PocketBookPowerD = BasePowerD:new{ function PocketBookPowerD:init() -- needed for SetFrontlightState / GetFrontlightState - inkview.OpenScreen() if self.device:hasNaturalLight() then local color = inkview.GetFrontlightColor() self.fl_warmth = color >= 0 and color or 0 diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 070a31985..409d702f7 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -1321,6 +1321,8 @@ function UIManager:suspend() self.event_handlers["Suspend"]() elseif Device:isKindle() then Device.powerd:toggleSuspend() + elseif Device.isPocketBook() and Device.canSuspend() then + Device:suspend() end end diff --git a/platform/pocketbook/koreader.app b/platform/pocketbook/koreader.app index ecc55d30b..c7dae839d 100755 --- a/platform/pocketbook/koreader.app +++ b/platform/pocketbook/koreader.app @@ -14,6 +14,9 @@ if [ "${INSTANCE_PID}" != "" ] && [ -e "/proc/${INSTANCE_PID}" ]; then exec /usr/bin/iv2sh SetActiveTask "${INSTANCE_PID}" 0 fi +# try to bring in raw device input (on rooted devices) +/mnt/secure/su /bin/chmod 644 /dev/input/* + # we're first, so publish our instance echo $$ >/tmp/koreader.pid diff --git a/plugins/autosuspend.koplugin/main.lua b/plugins/autosuspend.koplugin/main.lua index 3364b7d67..defaa8db9 100644 --- a/plugins/autosuspend.koplugin/main.lua +++ b/plugins/autosuspend.koplugin/main.lua @@ -1,6 +1,11 @@ local Device = require("device") -if not Device:isCervantes() and not Device:isKobo() and not Device:isRemarkable() and not Device:isSDL() and not Device:isSonyPRSTUX() then +if not Device:isCervantes() and + not Device:isKobo() and + not Device:isRemarkable() and + not Device:isSDL() and + not Device:isSonyPRSTUX() and + not Device:isPocketBook() then return { disabled = true, } end @@ -21,6 +26,7 @@ local AutoSuspend = WidgetContainer:new{ autoshutdown_timeout_seconds = G_reader_settings:readSetting("autoshutdown_timeout_seconds") or default_autoshutdown_timeout_seconds, settings = LuaSettings:open(DataStorage:getSettingsDir() .. "/koboautosuspend.lua"), last_action_sec = os.time(), + standby_prevented = false, } function AutoSuspend:_readTimeoutSecFrom(settings) @@ -60,7 +66,7 @@ function AutoSuspend:_schedule() local delay_suspend, delay_shutdown - if PluginShare.pause_auto_suspend then + if PluginShare.pause_auto_suspend or Device.standby_prevented or Device.powerd:isCharging() then delay_suspend = self.auto_suspend_sec delay_shutdown = self.autoshutdown_timeout_seconds else @@ -68,12 +74,13 @@ function AutoSuspend:_schedule() delay_shutdown = self.last_action_sec + self.autoshutdown_timeout_seconds - os.time() end - if delay_suspend <= 0 then - logger.dbg("AutoSuspend: will suspend the device") - UIManager:suspend() - elseif delay_shutdown <= 0 then + -- Try to shutdown first, as we may have been woken up from suspend just for the sole purpose of doing that. + if delay_shutdown <= 0 then logger.dbg("AutoSuspend: initiating shutdown") UIManager:poweroff_action() + elseif delay_suspend <= 0 then + logger.dbg("AutoSuspend: will suspend the device") + UIManager:suspend() else if self:_enabled() then logger.dbg("AutoSuspend: schedule suspend at ", os.time() + delay_suspend) @@ -100,6 +107,7 @@ function AutoSuspend:_start() end function AutoSuspend:init() + if Device:isPocketBook() and not Device:canSuspend() then return end UIManager.event_hook:registerWidget("InputEvent", self) self.auto_suspend_sec = self:_readTimeoutSec() self:_unschedule() @@ -132,6 +140,14 @@ function AutoSuspend:onResume() self:_start() end +function AutoSuspend:onAllowStandby() + self.standby_prevented = false +end + +function AutoSuspend:onPreventStandby() + self.standby_prevented = true +end + function AutoSuspend:addToMainMenu(menu_items) menu_items.autosuspend = { sorting_hint = "device", @@ -167,6 +183,7 @@ function AutoSuspend:addToMainMenu(menu_items) } if not (Device:canPowerOff() or Device:isEmulator()) then return end menu_items.autoshutdown = { + sorting_hint = "device", text = _("Autoshutdown timeout"), callback = function() local InfoMessage = require("ui/widget/infomessage")