Fix jump-to-end firing on every line: debounce sustained unfocus, not recency
Debug logging disproved the previous "recent append perturbs GetFocus" theory - one spurious jump fired 7.67s after the last append. The real pattern: GetFocus() reports "not focused" for a single poll tick now and then even while the user never left the window, and that lone blip was enough for the very next tick to be read as "just switched to the window," triggering a jump on practically every incoming line. Now requires 3 consecutive unfocused poll ticks (~0.6s) before the next focused tick counts as a genuine switch, filtering out single-tick noise from MUSHclient's own UI thread. Removed the now-unused last_append_clock tracking from the previous (wrong) fix attempt.
This commit is contained in:
@@ -407,11 +407,7 @@ end
|
|||||||
-- Note: text should use "\r\n" line endings, not bare "\n" - the plain
|
-- Note: text should use "\r\n" line endings, not bare "\n" - the plain
|
||||||
-- Win32 Edit control that backs the notepad doesn't recognise bare "\n"
|
-- Win32 Edit control that backs the notepad doesn't recognise bare "\n"
|
||||||
-- as a line break for scrolling/line-count purposes.
|
-- as a line break for scrolling/line-count purposes.
|
||||||
last_append_clock = 0
|
|
||||||
|
|
||||||
function SmartAppendToNotepad(title, text)
|
function SmartAppendToNotepad(title, text)
|
||||||
last_append_clock = os.clock()
|
|
||||||
|
|
||||||
local edit = find_notepad_edit(title)
|
local edit = find_notepad_edit(title)
|
||||||
local was_at_end = true
|
local was_at_end = true
|
||||||
local sel_start, sel_end, first_visible
|
local sel_start, sel_end, first_visible
|
||||||
@@ -459,36 +455,49 @@ end
|
|||||||
-- while a separate notepad window has focus (confirmed by Nick Gammon on
|
-- while a separate notepad window has focus (confirmed by Nick Gammon on
|
||||||
-- the MUSHclient forum), so this can't be event-driven - polling every
|
-- the MUSHclient forum), so this can't be event-driven - polling every
|
||||||
-- 0.2s is the safe, non-hooking way to catch it.
|
-- 0.2s is the safe, non-hooking way to catch it.
|
||||||
|
--
|
||||||
|
-- GetFocus() genuinely reports "not focused" for a single poll tick now
|
||||||
|
-- and then, even while the user never left the window and nothing was
|
||||||
|
-- just appended (confirmed via logging - one case was 7+ seconds after
|
||||||
|
-- the last append) - just noise from MUSHclient's own UI thread being
|
||||||
|
-- momentarily busy. A single such blip was enough to make this treat
|
||||||
|
-- the very next tick as "just switched to the window" and jump, on
|
||||||
|
-- practically every incoming line. Requiring several *consecutive*
|
||||||
|
-- unfocused ticks before the next focused tick counts as a genuine
|
||||||
|
-- switch filters that out.
|
||||||
was_output_focused = false
|
was_output_focused = false
|
||||||
|
unfocused_streak = 0
|
||||||
|
FOCUS_DEBOUNCE_TICKS = 3 -- ~0.6s of sustained unfocus at the 0.2s poll rate
|
||||||
|
|
||||||
function poll_output_focus()
|
function poll_output_focus()
|
||||||
if GetVariable("jump_to_end_on_focus") == "0" then
|
if GetVariable("jump_to_end_on_focus") == "0" then
|
||||||
was_output_focused = false
|
was_output_focused = false
|
||||||
|
unfocused_streak = 0
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local edit = find_notepad_edit("output")
|
local edit = find_notepad_edit("output")
|
||||||
if not edit then
|
if not edit then
|
||||||
was_output_focused = false
|
was_output_focused = false
|
||||||
|
unfocused_streak = 0
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local focused = GetFocus()
|
local focused = GetFocus()
|
||||||
-- Compare by string representation, not raw "==": Alien's pointer
|
-- Compare by string representation, not raw "==": Alien's pointer
|
||||||
-- returns are full userdata objects, so two separate calls returning
|
-- returns are full userdata objects, so two separate calls returning
|
||||||
-- the same real HWND don't reliably compare equal with "==" (which
|
-- the same real HWND don't reliably compare equal with "==" (which
|
||||||
-- fell back to identity comparison), causing spurious "just gained
|
-- falls back to identity comparison).
|
||||||
-- focus" edges and repeated jump-to-end even while focus never moved.
|
|
||||||
local is_focused = (tostring(focused) == tostring(edit))
|
local is_focused = (tostring(focused) == tostring(edit))
|
||||||
-- Skip the jump if a SmartAppendToNotepad call happened very recently:
|
|
||||||
-- AppendToNotepad's own SetSel/ReplaceSel appears to momentarily
|
if is_focused then
|
||||||
-- perturb GetFocus() around each append, which was making this poll
|
if not was_output_focused and unfocused_streak >= FOCUS_DEBOUNCE_TICKS then
|
||||||
-- see a spurious "just gained focus" edge - and jump to the end - on
|
|
||||||
-- practically every incoming line, even though the user never left
|
|
||||||
-- the window.
|
|
||||||
local recent_append = (os.clock() - last_append_clock) < 0.5
|
|
||||||
if is_focused and not was_output_focused and not recent_append then
|
|
||||||
jump_notepad_to_end(edit)
|
jump_notepad_to_end(edit)
|
||||||
end
|
end
|
||||||
was_output_focused = is_focused
|
unfocused_streak = 0
|
||||||
|
was_output_focused = true
|
||||||
|
else
|
||||||
|
unfocused_streak = unfocused_streak + 1
|
||||||
|
was_output_focused = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------
|
------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user