From f4aca567efcf81ab1c40c2b08ad3ec5fee0540e5 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sat, 12 Aug 2023 00:34:29 +0200 Subject: [PATCH] Kobo: Allow disabling key repeats Re #10743 Note that this only makes faulty switches slightly less annoying: for a stuck switch, instead of a string of page turns, you'll get a single missed page turn on the tap that actually releases the stuck contact... --- frontend/device/devicelistener.lua | 11 +++++ frontend/device/generic/device.lua | 5 +- frontend/device/kobo/device.lua | 52 +++++++++++++++++++- frontend/dispatcher.lua | 6 ++- frontend/ui/elements/page_turns.lua | 2 +- frontend/ui/elements/platform_navigation.lua | 14 ++++++ reader.lua | 2 +- 7 files changed, 86 insertions(+), 6 deletions(-) diff --git a/frontend/device/devicelistener.lua b/frontend/device/devicelistener.lua index cb7b8a446..f57d7b59d 100644 --- a/frontend/device/devicelistener.lua +++ b/frontend/device/devicelistener.lua @@ -317,6 +317,17 @@ function DeviceListener:onSwapPageTurnButtons() Device:invertButtons() end +function DeviceListener:onToggleKeyRepeat(toggle) + if toggle == true then + G_reader_settings:makeFalse("input_no_key_repeats") + elseif toggle == false then + G_reader_settings:makeTrue("input_no_key_repeats") + else + G_reader_settings:flipNilOrFalse("input_no_key_repeats") + end + Device:toggleKeyRepeat(G_reader_settings:nilOrFalse("input_no_key_repeats")) +end + function DeviceListener:onRestart() self.ui.menu:exitOrRestart(function() UIManager:restartKOReader() end) end diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua index 5e010644c..37fd2de1a 100644 --- a/frontend/device/generic/device.lua +++ b/frontend/device/generic/device.lua @@ -41,6 +41,7 @@ local Device = { hasAuxBattery = no, hasKeyboard = no, hasKeys = no, + canKeyRepeat = no, hasDPad = no, hasExitOptions = yes, hasFewKeys = no, @@ -484,12 +485,14 @@ function Device:setupChargingLED() end function Device:enableCPUCores(amount) end -- NOTE: For this to work, all three must be implemented, and getKeyRepeat must be run on init (c.f., Kobo)! --- Device specific method to get the current key repeat setup +-- Device specific method to get the current key repeat setup (and is responsible for setting the canKeyRepeat cap) function Device:getKeyRepeat() end -- Device specific method to disable key repeat function Device:disableKeyRepeat() end -- Device specific method to restore key repeat function Device:restoreKeyRepeat() end +-- Device specific method to toggle key repeat (between off and a hard-coded delay/period combo) +function Device:toggleKeyRepeat(toggle) end --[[ prepare for application shutdown diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index 8ea2c6e61..1f1c04bc4 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -557,6 +557,7 @@ function Kobo:getKeyRepeat() return false else logger.dbg("Key repeat is set up to repeat every", self.key_repeat[C.REP_PERIOD], "ms after a delay of", self.key_repeat[C.REP_DELAY], "ms") + self.canKeyRepeat = yes return true end end @@ -577,6 +578,39 @@ function Kobo:restoreKeyRepeat() end end +function Kobo:toggleKeyRepeat(toggle) + local key_repeat = ffi.new("unsigned int[?]", C.REP_CNT) + if toggle == true then + -- Use the defaults from a Sage, as we can't guarantee the state of the setup on startup, so we can't just use self.key_repeat + key_repeat[C.REP_DELAY] = 400 + key_repeat[C.REP_PERIOD] = 80 + elseif toggle == false then + key_repeat[C.REP_DELAY] = 0 + key_repeat[C.REP_PERIOD] = 0 + else + -- Check the current (kernel) state to know what to do + if C.ioctl(self.ntx_fd, C.EVIOCGREP, key_repeat) < 0 then + local err = ffi.errno() + logger.warn("Device:toggleKeyRepeat: EVIOCGREP ioctl failed:", ffi.string(C.strerror(err))) + return false + else + if key_repeat[C.REP_DELAY] == 0 and key_repeat[C.REP_PERIOD] == 0 then + return self:toggleKeyRepeat(true) + else + return self:toggleKeyRepeat(false) + end + end + end + + if C.ioctl(self.ntx_fd, C.EVIOCSREP, key_repeat) < 0 then + local err = ffi.errno() + logger.warn("Device:toggleKeyRepeat: EVIOCSREP ioctl failed:", ffi.string(C.strerror(err))) + return false + end + + return true +end + function Kobo:init() -- Check if we need to disable MXCFB_WAIT_FOR_UPDATE_COMPLETE ioctls... local mxcfb_bypass_wait_for @@ -803,10 +837,14 @@ function Kobo:init() self.input.open("fake_events") -- See if the device supports key repeat - if not self:getKeyRepeat() then + -- This is *not* behind a hasKeys check, because we mainly use it to stop SleepCover chatter, + -- and sleep covers are available on a number of devices without keys ;). + self:getKeyRepeat() + if not self:canKeyRepeat() then -- NOP unsupported methods self.disableKeyRepeat = NOP self.restoreKeyRepeat = NOP + self.toggleKeyRepeat = NOP end -- Detect the NTX charging LED sysfs knob @@ -855,6 +893,18 @@ function Kobo:init() -- As found on (at least) the Glo HD (c.f., https://github.com/koreader/koreader/pull/9377#issuecomment-1213544478) self.hasIRGridSysfsKnob = "/sys/devices/platform/imx-i2c.1/i2c-1/1-0050/neocmd" end + + -- Disable key repeats if requested + if G_reader_settings:isTrue("input_no_key_repeats") then + self:toggleKeyRepeat(false) + end +end + +function Kobo:exit() + -- Re-enable key repeats on exit, that's the default state + self:toggleKeyRepeat(true) + + Generic.exit(self) end function Kobo:setDateTime(year, month, day, hour, min, sec) diff --git a/frontend/dispatcher.lua b/frontend/dispatcher.lua index 47133cdac..ddae58e00 100644 --- a/frontend/dispatcher.lua +++ b/frontend/dispatcher.lua @@ -76,6 +76,8 @@ local settingsList = { touch_input_on = {category="none", event="IgnoreTouchInput", arg=false, title=_("Enable touch input"), device=true}, touch_input_off = {category="none", event="IgnoreTouchInput", arg=true, title=_("Disable touch input"), device=true}, toggle_touch_input = {category="none", event="IgnoreTouchInput", title=_("Toggle touch input"), device=true, separator=true}, + swap_page_turn_buttons = {category="none", event="SwapPageTurnButtons", title=_("Invert page turn buttons"), device=true, condition=Device:hasKeys(), separator=true}, + toggle_key_repeat = {category="none", event="ToggleKeyRepeat", title=_("Toggle key repeat"), device=true, condition=Device:hasKeys() and Device:canKeyRepeat(), separator=true}, toggle_gsensor = {category="none", event="ToggleGSensor", title=_("Toggle accelerometer"), device=true, condition=Device:hasGSensor()}, toggle_rotation = {category="none", event="SwapRotation", title=_("Toggle orientation"), device=true}, invert_rotation = {category="none", event="InvertRotation", title=_("Invert rotation"), device=true}, @@ -174,7 +176,6 @@ local settingsList = { -- toggle_inverse_reading_order = {category="none", event="ToggleReadingOrder", title=_("Toggle page turn direction"), reader=true, separator=true}, - swap_page_turn_buttons = {category="none", event="SwapPageTurnButtons", title=_("Invert page turn buttons"), reader=true, condition=Device:hasKeys(), separator=true}, set_highlight_action = {category="string", event="SetHighlightAction", title=_("Set highlight action"), args_func=ReaderHighlight.getHighlightActions, reader=true}, cycle_highlight_action = {category="none", event="CycleHighlightAction", title=_("Cycle highlight action"), reader=true}, cycle_highlight_style = {category="none", event="CycleHighlightStyle", title=_("Cycle highlight style"), reader=true, separator=true}, @@ -270,6 +271,8 @@ local dispatcher_menu_order = { "touch_input_on", "touch_input_off", "toggle_touch_input", + "swap_page_turn_buttons", + "toggle_key_repeat", "toggle_gsensor", "rotation_mode", "toggle_rotation", @@ -368,7 +371,6 @@ local dispatcher_menu_order = { "toggle_bookmark_flipping", "toggle_reflow", "toggle_inverse_reading_order", - "swap_page_turn_buttons", "zoom", "zoom_factor_change", "set_highlight_action", diff --git a/frontend/ui/elements/page_turns.lua b/frontend/ui/elements/page_turns.lua index ff7ca49bc..d44a5014e 100644 --- a/frontend/ui/elements/page_turns.lua +++ b/frontend/ui/elements/page_turns.lua @@ -173,7 +173,7 @@ When enabled the UI direction for the Table of Contents, Book Map, and Page Brow if Device:canDoSwipeAnimation() then table.insert(PageTurns.sub_item_table, { - text =_("Page turn animations"), + text = _("Page turn animations"), checked_func = function() return G_reader_settings:isTrue("swipe_animations") end, diff --git a/frontend/ui/elements/platform_navigation.lua b/frontend/ui/elements/platform_navigation.lua index b38a52694..0d8acdc40 100644 --- a/frontend/ui/elements/platform_navigation.lua +++ b/frontend/ui/elements/platform_navigation.lua @@ -25,4 +25,18 @@ local PlatformNav = { }, } +if Device:canKeyRepeat() then + table.insert(PlatformNav.sub_item_table, { + text = _("Disable key repeats"), + help_text = _("Useful if you don't like the behavior or if your device has faulty switches"), + checked_func = function() + return G_reader_settings:isTrue("input_no_key_repeats") + end, + callback = function() + UIManager:broadcastEvent(Event:new("ToggleKeyRepeat")) + end, + separator = true, + }) +end + return PlatformNav diff --git a/reader.lua b/reader.lua index d055e0136..6347f9835 100755 --- a/reader.lua +++ b/reader.lua @@ -350,7 +350,7 @@ local function exitReader() -- Restore initial inversion state Device.screen:setHWNightmode(hw_nightmode) - -- shutdown hardware abstraction + -- Shutdown hardware abstraction Device:exit() if Profiler then Profiler.stop() end