Add key_repeat support to kindle NT#13328
Conversation
| return Event:new("KeyPress", key) | ||
| elseif ev.value == KEY_REPEAT then | ||
| -- NOTE: We only care about repeat events from the pageturn buttons... | ||
| -- NOTE: We only care about repeat events from the page-turn buttons (kobo) and cursor keys (kindle)... |
There was a problem hiding this comment.
Adding Kobo/Kindle to the comment seems more confusing than elucidating (i.e., what happens on other platforms).
There was a problem hiding this comment.
nothing since the if not rep_delay or rep_delay == 0 then return end check should kick 'em out.
There was a problem hiding this comment.
Because i can only guarantee that it works there, i can't test other platforms. To avoid potential crashes best to err on the side of caution. Furthermore if the value is zero and we don't return early... well any length of time is greater than zero
There was a problem hiding this comment.
Nothing about enabling support for Kindle implies disabling support for all other platforms. I should not have to find out about that by accident.
There was a problem hiding this comment.
So to be clear you're not changing anything other than making a comment confusing which wasn't confusing before?
There was a problem hiding this comment.
But something about all that code further down still doesn't make sense. Either they can end up here and they should be treated normally rather than blocked or they can't and there's no need to guard against anything.
There was a problem hiding this comment.
So to be clear you're not changing anything other than making a comment confusing which wasn't confusing before?
That sounds quite like what might be happening here. I was only trying to convey that only kobo supports repeats on page-turn buttons and kindle on cursor keys
On another note, it would be cool if you could test this on your kobo.
There was a problem hiding this comment.
But something about all that code further down still doesn't make sense. Either they can end up here and they should be treated normally rather than blocked or they can't and there's no need to guard against anything.
Well as i said the equal zero neutralises a user toggling it off , but what exactly doesn't make sense to you?
There was a problem hiding this comment.
It sounds like you're saying it's mostly a somewhat convoluted way of writing something like:
Device:canKeyRepeat() and G_reader_settings:isNilOrFalse("input_no_key_repeat")Which you can probably just reduce to:
elseif ev.value == KEY_REPEAT and G_reader_settings:isNilOrFalse("input_no_key_repeat") then| local rep_delay = self.device.key_repeat[C.REP_DELAY] | ||
| if not rep_delay or rep_delay == 0 then return end | ||
| local rep_period = self.device.key_repeat[C.REP_PERIOD] | ||
| if not rep_period or rep_period == 0 then return end |
There was a problem hiding this comment.
Okay, having looked at the rest of the code now this won't work quite right as written, since it'll error due to self.device.key_repeat being nil.
For the moment I suggest to change it as follows (in conjunction with the elseif ev.value == KEY_REPEAT and G_reader_settings:isNilOrFalse("input_no_key_repeat") up above).
| local rep_delay = self.device.key_repeat[C.REP_DELAY] | |
| if not rep_delay or rep_delay == 0 then return end | |
| local rep_period = self.device.key_repeat[C.REP_PERIOD] | |
| if not rep_period or rep_period == 0 then return end | |
| local rep_period = self.device.key_repeat and self.device.key_repeat[C.REP_PERIOD] or 120 | |
| if rep_period == 0 then return end |
In the Kobo implementation, it seems to be changed with ioctl, meaning with 0 there simply won't be any KEY_REPEAT events:
koreader/frontend/device/kobo/device.lua
Lines 668 to 672 in 926eb9d
I think that with this PR as written, the
self.key_repeat = ffi.new("unsigned int[?]", C.REP_CNT)
if G_reader_settings:isTrue("input_no_key_repeat") then
self.key_repeat[C.REP_DELAY] = 0
self.key_repeat[C.REP_PERIOD] = 0
else
self.key_repeat[C.REP_DELAY] = 400
self.key_repeat[C.REP_PERIOD] = 120
endShould be put in generic device.
But for the moment, let's just make the aforementioned two small changes to this PR and wait to see what @NiLuJe thinks with regard to the underlying design.
There was a problem hiding this comment.
applied your two other suggestions, but we are now letting in anyone with cursor keys...
There was a problem hiding this comment.
I am also not sure this if rep_period == 0 then return end does anything at all now. I mean the only case in which that is zero now is when the G-set is true, which is handled at the top.
There was a problem hiding this comment.
but we are now letting in anyone with cursor keys...
Exactly! Anything else is unacceptable.
|
okay sorry @Frenzie but I am bringing back the loop, although it looks needless as you said (I think), it turns out that it is not. It is in fact, the driver of quite an improvement boost. Let me rephrase that: with the previous implementation and simply adding the cursor keys to the |
|
A quick glance suggests the If there were a lot of values a table lookup might become faster eventually, if you write it like But all that I said above should be irrelevant in practice since we're only talking about one repeat every tens of milliseconds, for Kindle NT specifically every 60 ms or so according to the linked issue. I can only guess that the table definition compared with ipairs introduces a minuscule delay that has happy results in combination with the cursor's own timing on your particular device. It's potentially also worth noting that you reversed the order, but that shouldn't compensate for the ipairs overhead. local function test_if_or(iterations)
local a, b, c = false, false, true
local start = os.clock()
for i = 1, iterations do
if a or b or c then
-- do nothing
end
end
return os.clock() - start
end
local function test_ipairs(iterations)
local t = {false, false, true}
local start = os.clock()
for i = 1, iterations do
for _, v in ipairs(t) do
if v then
break
end
end
end
return os.clock() - start
end
local iterations = 1000000
local time_if_or = test_if_or(iterations)
local time_ipairs = test_ipairs(iterations)
print(string.format("Time taken (if ... or ...): %.6f seconds", time_if_or))
print(string.format("Time taken (ipairs): %.6f seconds", time_ipairs))
print(string.format("Ratio (ipairs / if or): %.2f", time_ipairs / time_if_or)) |
|
here is some empirical data running on the K4: starting from the topmost of the screen, running all the way down, and back up again (x 2, so 4 legs total) on key press self._start = time.now()
logger.dbg("Test #: xxx start")on key release local now = time.now()
logger.dbg("Test #: xxx end", time.to_s(now - self._start), "sec")so there is, empirical evidence of little to no statistical significance (within the realms of this small test, sometimes either comes on top)... what???? I swear that every time I've tried to use the loop it seems relatively slower, what's going on? and for reasons, they do take longer sometimes, but it happens to both cases... |
|
as usual, I once again just happen to bump into yet another nest of rats lurking in a dark corner. It turns out that the dicquicklookup widget does not support key repeats when doing text selection, not sure why atm. logs show that the events are being generated but it appears they are not being processed... any ideas? |
|
Does it depend on KeyRelease or something? |
what do you mean? I think that some children widgets don't have an implementation for key_repeats (that is just speculation on my part though). |
|
If it depends on InputContainer (which they basically all do?) they get their key events and key repeat events from there without distinction. I suspect this will fix your problem. ( diff --git a/base b/base
--- a/base
+++ b/base
@@ -1 +1 @@
-Subproject commit d2c1d37da563125df18efce152a0b2db9af1f7f6
+Subproject commit d2c1d37da563125df18efce152a0b2db9af1f7f6-dirty
diff --git a/frontend/ui/widget/focusmanager.lua b/frontend/ui/widget/focusmanager.lua
index 9460ef367..8b17e4938 100644
--- a/frontend/ui/widget/focusmanager.lua
+++ b/frontend/ui/widget/focusmanager.lua
@@ -526,4 +526,6 @@ function FocusManager:onKeyPress(key)
return InputContainer.onKeyPress(self, key)
end
+FocusManager.onKeyRepeat = FocusManager.onKeyPress
+
return FocusManager |
|
interesting, that indeed does the job. |
|
after A/B testing both the |
|
seeing as NiLuJe does not seem interested in joining us here (sad occasion), what direction do you reckon this should take @Frenzie ? |
| return Event:new("KeyPress", key) | ||
| elseif ev.value == KEY_REPEAT then | ||
| -- NOTE: We only care about repeat events from the pageturn buttons... | ||
| if G_reader_settings:isTrue("input_no_key_repeat") then return end |
There was a problem hiding this comment.
If the ioctl is supported, this needs to go. Ideally, even if it doesn't, this needs to go ;p.
There was a problem hiding this comment.
Say, with a device-specific event hook that swallows KEY_REPEAT events ;).
| or keycode == "RPgBack" | ||
| or keycode == "LPgFwd" | ||
| or keycode == "RPgFwd" then | ||
| local allowed_repeat_keys = { |
There was a problem hiding this comment.
Could probably be done with a key group
|
Big green GH button for reviews struck again -_-". |
|
Ah yeah, I've done that. Easy to forget. :-) |
| -- keys with key-repeat events | ||
| KeyRepeat = { | ||
| Up = true, Down = true, Left = true, Right = true, | ||
| LPgBack = true, RPgBack = true, LPgFwd = true, RPgFwd = true | ||
| }, |
There was a problem hiding this comment.
I'm not a fan of this. It dresses up something I don't think we should want as if it were a proper thing.
There was a problem hiding this comment.
I presume that means bring back the if
There was a problem hiding this comment.
I'd prefer to just blacklist sleepcover events, but the safe approach is to keep it as is in a way that signals to the reader that it's a bit hacky rather than working exactly as intended. :-)
There was a problem hiding this comment.
koreader/frontend/device/kobo/device.lua
Lines 828 to 829 in cfbb676
right so if not sleepcover it is.
| if keycode == "Up" or keycode == "Down" or keycode == "Left" or keycode == "Right" | ||
| or keycode == "RPgBack" or keycode == "RPgFwd" or keycode == "LPgBack" or keycode == "LPgFwd" then |
There was a problem hiding this comment.
| if keycode == "Up" or keycode == "Down" or keycode == "Left" or keycode == "Right" | |
| or keycode == "RPgBack" or keycode == "RPgFwd" or keycode == "LPgBack" or keycode == "LPgFwd" then | |
| if keycode ~= "SleepCover" then |
There was a problem hiding this comment.
Conceptually I think that's a significantly better approach, yes. But it requires careful thought and testing (e.g., what about power events?) while we know the current situation is fine. So if you're still aiming for the upcoming stable I wouldn't be inclined to do that yet.
There was a problem hiding this comment.
Well, what is holding back the next release? I suppose we could keep it like so for the next one and then test this approach and switch to it later, no biggie.
There was a problem hiding this comment.
Time for some testing and writing release notes (i.e., same as always). I nearly always use a recent nightly on my Kobo but my regular use doesn't touch most features.
There was a problem hiding this comment.
Are we still on for 2024.03?
There was a problem hiding this comment.
I believe @NiLuJe indicated being unhappy with this approach compared to doing something with an event hook, unless I misremember.
There was a problem hiding this comment.
Yes removing the G_sett, which was done and we are using the hook to swallow the key repeats already.
There was a problem hiding this comment.
Something about the whole affair strikes me as odd (i.e., shouldn't this manual approach only be done if it can't be set the other way), but afaict it's the better version of what's already there, so for me it's good enough. Still I'll wait to see what NiLuJe says. :-)
NiLuJe
left a comment
There was a problem hiding this comment.
Looks good beside the reset ;).
|
|
||
| -- We can't easily clear existing hooks, but we can overwrite the eventAdjustHook | ||
| -- with the default empty implementation to effectively remove previous hooks | ||
| self.input.eventAdjustHook = self.input.gestureAdjustHook |
There was a problem hiding this comment.
Should be a reset to the class Input.eventAdjustHook (c.f., frontend/device/android/device.lua which does something like this ;)).
|
Did you check that it's still working as it should? ^_^ |
Mmm, not really, no. I am blindly trusting NiLuJe here. Will do when i get home... edit: @Frenzie, it works just fine. |
|
Interesting, it looks like GH now notifies of edits. |
I believe it only does if a tag is added (double tag wouldn't), which is the case. |
I am pretty sure if the edits contain mentions, you would be notified anyway |
You beat me to it lol |
what's new
frontend/device/input.lua: Enhanced the key repeat logic to include cursor keys for Kindle devices and improved the responsiveness by using timestamps for key repeat events.frontend/device/kindle/device.lua: Added a new methodtoggleKeyRepeatto enable or disable key repeat functionality.frontend/device/kindle/device.lua: Updated theinitmethod to set up key repeat events for devices with a DPad, with configurable delay and period settings.frontend/ui/elements/physical_buttons.lua: Modified the insertion order of the key repeat disable option to ensure it appears at the top of the list.screenshots
closes #12745
This change is