• button stuck after continuous depression for a few seconds (??)

    From xol odho@21:1/5 to All on Thu Aug 25 15:35:21 2022
    Hi everyone. I'm learning some Tcl and Tk basics, enjoying what I'm
    learning it so far.

    I just found out an oddity about the classic Tk buttons: if you focus a
    button and hold down spacebar (so that it's depressed continuously) for a
    few seconds and then release spacebar, then it seems to remain stuck in
    the depressed state.

    Try it like this: open `wish`, then `pack [button .b1 -text hello]`, now
    on the toplevel with the button hit tab to focus the button, now hold down spacebar for at least four seconds, and release. Is it stuck? If so, why
    does this happen...

    This tickles my curiosity. It doesn't seem to happen with ttk::button
    (instead it hangs stuck for a while and then reverts back to normal).

    I confirm I get this behavior on the following platforms:
    Windows XP, Iron Tcl, Tk 8.6.7
    Windows 7, BAWT Tcl, Tk 8.6.11
    ArchLinux, distro's default Tcl/Tk on X11, Tk 8.6.12

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@gmail.com@21:1/5 to xol odho on Thu Aug 25 19:36:53 2022
    On 8/25/22 6:35 PM, xol odho wrote:
    Hi everyone. I'm learning some Tcl and Tk basics, enjoying what I'm
    learning it so far.

    I just found out an oddity about the classic Tk buttons: if you focus a button and hold down spacebar (so that it's depressed continuously) for a
    few seconds and then release spacebar, then it seems to remain stuck in
    the depressed state.


    It is not stuck. You can configure it with a -command option to print something to the console to confirm. As to why it appears that way,
    since no mouse movement/click was involved, it still has the focus and
    it shows this by displaying it in the "depressed" state.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Fri Aug 26 11:06:13 2022
    * Ralf Fassel <ralfixx@gmx.de>
    | * saitology9@gmail.com
    | | It is not stuck. You can configure it with a -command option to print
    | | something to the console to confirm. As to why it appears that way,
    | | since no mouse movement/click was involved, it still has the focus and
    | | it shows this by displaying it in the "depressed" state.

    | Seems like the Button-release-event which reconfigures the 'raised'
    | relief gets lost somehow. The button is fully functional, reacts to
    | mouse and keyboard, just the relief is 'sunken' instead of 'raised'.

    And looking at the code whichs gets called on pressing 'Space', it
    becomes clear:

    proc ::tk::ButtonInvoke w {
    if {[winfo exists $w] && [$w cget -state] ne "disabled"} {
    set oldRelief [$w cget -relief]
    set oldState [$w cget -state]
    $w configure -state active -relief sunken
    after 100 [list ::tk::ButtonInvokeEnd $w $oldState $oldRelief]
    }
    }

    proc ::tk::ButtonInvokeEnd {w oldState oldRelief} {
    if {[winfo exists $w]} {
    $w configure -state $oldState -relief $oldRelief
    uplevel #0 [list $w invoke]
    }
    }

    If you keep pressing Space, the next button press arrives while the
    button is still in the 'sunken' state (< 100ms), thus it will never get configured to 'raised' again.

    When selling a motocycle, this would be "technically 100%,
    optically... not so much" ;-)

    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Fri Aug 26 10:57:36 2022
    * saitology9@gmail.com
    | On 8/25/22 6:35 PM, xol odho wrote:
    | > Hi everyone. I'm learning some Tcl and Tk basics, enjoying what I'm
    | > learning it so far.
    | >
    | > I just found out an oddity about the classic Tk buttons: if you focus a
    | > button and hold down spacebar (so that it's depressed continuously) for a
    | > few seconds and then release spacebar, then it seems to remain stuck in
    | > the depressed state.

    Can confirm this in Opensuse 15.3, Tk 8.6.12.

    | It is not stuck. You can configure it with a -command option to print
    | something to the console to confirm. As to why it appears that way,
    | since no mouse movement/click was involved, it still has the focus and
    | it shows this by displaying it in the "depressed" state.

    Seems like the Button-release-event which reconfigures the 'raised'
    relief gets lost somehow. The button is fully functional, reacts to
    mouse and keyboard, just the relief is 'sunken' instead of 'raised'.

    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From xol odho@21:1/5 to All on Fri Aug 26 16:50:59 2022
    Nice catch. It's a bad interleaving of events then.

    Let me see if I get this right...

    If a second ButtonInvoke runs before the first ButtonInvokeEnd restablishes the button back to normal/raised, then the oldState/oldRelief variables get overwritten wrongly with active/sunken values, so then ButtonInvokeEnd does not reset them correctly.
    Perhaps ButtonInvoke should be stopped from touching anything (or running at all) if the button is still depressed. Then these two procs would run in strict pairs without allowing a second ButtonInvoke messing things in between...

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Erik Leunissen@21:1/5 to xol odho on Sat Sep 3 11:03:31 2022
    On 27/08/2022 01:50, xol odho wrote:
    Nice catch. It's a bad interleaving of events then.

    Let me see if I get this right...

    If a second ButtonInvoke runs before the first ButtonInvokeEnd restablishes the button back to normal/raised, then the oldState/oldRelief variables get overwritten wrongly with active/sunken values, so then ButtonInvokeEnd does not reset them correctly.
    Perhaps ButtonInvoke should be stopped from touching anything (or running at all) if the button is still depressed. Then these two procs would run in strict pairs without allowing a second ButtonInvoke messing things in between...


    I agree with your analysis of the misbehaviour, and the design foundation for a fix.

    Implementation-wise that would be something like:

    proc ::tk::ButtonInvoke w {
    if {[winfo exists $w] && ([$w cget -state] ni {disabled active})} {
    set oldRelief [$w cget -relief]
    set oldState [$w cget -state]
    $w configure -state active -relief sunken
    after 100 [list ::tk::ButtonInvokeEnd $w $oldState $oldRelief]
    }
    }

    I believe a Tk bug ticket including a fix proposal is appropriate.

    Erik.
    --
    elns@ nl | Merge the left part of these two lines into one,
    xs4all. | respecting a character's position in a line.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From xol odho@21:1/5 to All on Wed Sep 7 22:07:32 2022
    Yes, something along those lines might do it: you check whether the button
    is busy transitioning and stop right there, not more race condition.

    But perhaps this could be fixed at a lower (and more general) level,
    instead of hardcoding it using specific widget states or tracking state
    with external variables. More precisely, the button binding script could
    just ignore repeated keypresses, so tk::ButtonInvoke doesn't even get to
    run until the next physical keypress. This way you don't need to manually
    track state changes or anything because the asynchronous race would become impossible.

    For comparison, when you hold a mouseclick, it is impossible to get a "repeated" click while the mousebutton is depressed, so the bad
    interleaving is impossible for mouseclicks on Tk buttons, and so that
    obviates any need for extra ad-hoc state tracking.

    So, is it possible to (easily, reliably) detect an auto-repeated keypress
    in Tk? Perhaps `bind` could provide a percent-substitution with a boolean value? Or perhaps some trick using <Double-Keypress-*> bindings ? I'm
    really envying SDL's SDL_KeyboardEvent and Winapi's WM_KEYDOWN message,
    both carry an explicit boolean indication for repeated keypresses.

    Also, I notice the mouse-click logic and the spacebar-down logic use
    different code paths in button.tcl, perhaps they could share behavior?
    i.e., holding down click vs holding down spacebar, does the difference
    matter? In win32, a native button get depressed while click/space is down (repeats ignored) but the command fires only at last when click/space is released (both cases produce a WM_COMMAND message). I've been wondering
    about this...

    Last but not least, the <KeyRelease> event does not work properly on my
    X11 desktops with autorepeat on (Tk 8.6.12 on i3wm, xfce, etc), for
    instance with this code :

    bind . <KeyPress> {puts "%# KeyPress %K"}
    bind . <KeyRelease> {puts "%# KeyRelease %K"}

    On X11 while I hold down some key, that prints a stream of alternated
    KeyPress and KeyRelease lines, but the proper behaviour should be a unique <KeyRelease> after each <KeyPress> repeated sequence, for each physical
    key down/up pair. There was a similar bug reported for MacOSX some years
    ago. It works correctly on Win32.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From xol odho@21:1/5 to All on Wed Sep 7 22:58:52 2022
    Yes, something along those lines might do it: you check whether the button
    is busy transitioning and stop right there, not more race condition.

    But perhaps this could be fixed at a lower (and more general) level,
    instead of hardcoding it using specific widget states or tracking state
    with external variables. More precisely, the button binding script could
    just ignore repeated keypresses, so tk::ButtonInvoke doesn't even get to
    run until the next physical keypress. This way you don't need to manually
    track state changes.

    For comparison, with the mouse, it is impossible to get a "repeated" click while the mousebutton is depressed, so the bad interleaving is impossible
    for mouseclicks on Tk buttons, and so that obviates any need for extra
    ad-hoc state tracking.

    So, is it possible to (easily, reliably) detect an auto-repeated keypress
    in Tk? Perhaps `bind` could provide a percent-substitution with a boolean value? Or perhaps some trick using <Double-Keypress-*> bindings ? I'm
    really envying SDL's SDL_KeyboardEvent and Winapi's WM_KEYDOWN message,
    both carry an explicit boolean indication for repeated keypresses.

    Also, I notice the mouse-click logic and the spacebar-down logic use
    different code paths in button.tcl, perhaps they could share behavior?
    i.e., holding down click vs holding down spacebar, does the difference
    matter? In win32, a native button gets depressed while click/space is down (repeats ignored) but the command fires only at last when click/space is released (both cases produce a WM_COMMAND message). I've been wondering
    about this...

    Last but not least, the <KeyRelease> event does not work properly on my
    X11 desktops with autorepeat on (Tk 8.6.12 on i3wm, xfce, etc), for
    instance with this code :

    bind . <KeyPress> {puts "%# KeyPress %K"}
    bind . <KeyRelease> {puts "%# KeyRelease %K"}

    On X11 while I hold down some key, that prints a stream of alternated
    KeyPress and KeyRelease lines, but the proper behaviour should be a unique <KeyRelease> after each <KeyPress> repeated sequence, for each physical
    key down/up pair. There was a similar bug reported for MacOSX some years
    ago. It works correctly on Win32.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Erik Leunissen@21:1/5 to xol odho on Sun Sep 11 10:01:44 2022
    On 08/09/2022 07:58, xol odho wrote:

    But perhaps this could be fixed at a lower (and more general) level,

    I think hat your suggestions below are worth pursuing in the context of the misbehaviour that you
    reported previously. I'd be sorry if they weren't.

    I believe, now even more, that a Tk bug ticket including your suggestions (or a fix proposal) is
    appropriate. Personally, I'm not experienced enough to comment in detail on your suggestions, but Tk
    maintainers may be).

    By the way:

    https://core.tcl-lang.org/tk/ticket

    Sincerely,
    Erik Leunissen
    --

    instead of hardcoding it using specific widget states or tracking state
    with external variables. More precisely, the button binding script could
    just ignore repeated keypresses, so tk::ButtonInvoke doesn't even get to
    run until the next physical keypress. This way you don't need to manually track state changes.

    For comparison, with the mouse, it is impossible to get a "repeated" click while the mousebutton is depressed, so the bad interleaving is impossible
    for mouseclicks on Tk buttons, and so that obviates any need for extra
    ad-hoc state tracking.

    So, is it possible to (easily, reliably) detect an auto-repeated keypress
    in Tk? Perhaps `bind` could provide a percent-substitution with a boolean value? Or perhaps some trick using <Double-Keypress-*> bindings ? I'm
    really envying SDL's SDL_KeyboardEvent and Winapi's WM_KEYDOWN message,
    both carry an explicit boolean indication for repeated keypresses.

    Also, I notice the mouse-click logic and the spacebar-down logic use different code paths in button.tcl, perhaps they could share behavior?
    i.e., holding down click vs holding down spacebar, does the difference matter? In win32, a native button gets depressed while click/space is down (repeats ignored) but the command fires only at last when click/space is released (both cases produce a WM_COMMAND message). I've been wondering
    about this...

    Last but not least, the <KeyRelease> event does not work properly on my
    X11 desktops with autorepeat on (Tk 8.6.12 on i3wm, xfce, etc), for
    instance with this code :

    bind . <KeyPress> {puts "%# KeyPress %K"}
    bind . <KeyRelease> {puts "%# KeyRelease %K"}

    On X11 while I hold down some key, that prints a stream of alternated KeyPress and KeyRelease lines, but the proper behaviour should be a unique <KeyRelease> after each <KeyPress> repeated sequence, for each physical
    key down/up pair. There was a similar bug reported for MacOSX some years
    ago. It works correctly on Win32.



    --
    elns@ nl | Merge the left part of these two lines into one,
    xs4all. | respecting a character's position in a line.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)