Opened 16 years ago

Closed 16 years ago

#219 closed Bug (Fixed)

Accelerator tables and multiple GUI windows

Reported by: Ultima Owned by: Jon
Milestone: Component: AutoIt
Version: Severity: None
Keywords: accelerator table child Cc:


When you set accelerators to be used in a window (using GUISetAccelerators()), other windows also end up "inheriting" the accelerator table from the first window to get accelerators set. Attempting to override accelerator tables in the subsequent windows does not work as expected either.

Checking for window focus in the callback function usually works fine in many cases, but sometimes fails. For example, if keyboard shortcuts with normally "well-defined" behaviors (like {DELETE} or {ENTER} in input/edit controls) are associated with GUI window, then such an edit control in another window would never properly receive the {DELETE} or {ENTER}.

Here's a simple(ish) test script:

#Include <GUIConstantsEx.au3>

; Dialog 1 --------------
Global $Dialog1 = GUICreate("Dialog 1", 320, 240)
Global $Dummy = GUICtrlCreateDummy()

Global $Dialog1Accelerators[1][2] = [["{ENTER}", $Dummy]]
GUISetAccelerators($Dialog1Accelerators, $Dialog1)

; Dialog 2 --------------
Global $Dialog2 = GUICreate("Dialog 2", 210, 160)
Global $Edit = GUICtrlCreateEdit("", 5, 5)

Global $Dialog2Accelerators[1][2] = [["{ENTER}", $Edit]]
GUISetAccelerators($Dialog2Accelerators, $Dialog2)

; Miscellaneous ---------
GUISetState(@SW_SHOW, $Dialog1)
GUISetState(@SW_SHOW, $Dialog2)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
        Case $Dummy
            MsgBox(0, "Dummy", "Hotkey caught by Dialog 1!")
        Case $Edit
            MsgBox(0, "Edit", "Hotkey caught by Dialog 2!")

An (interesting?) aside: depending on situation, the second dialog might actually catch a hotkey press. If you never modify the contents of the edit control, the second window never gets catches the hotkey. After you modify the edit control, though, it manages to catch the hotkey press.

Attachments (0)

Change History (7)

comment:1 Changed 16 years ago by Ultima

Uh, ignore the aside; it was just me being stupid and forgetting that the $Edit control generates its own event >_>

comment:2 Changed 16 years ago by Jon

I found out that you can only have a single accelerator table active, so being able to set them per window was a waste of time. The only "fix" I can think of is an extra parameter to indicate if an entire accelerator table should be global or just for the window it was created for. Can't think of any other options.

comment:3 Changed 16 years ago by Ultima

Well, it seemed to me like winhandle parameter was specifically made to be used in that way to begin with (to make the accelerator table per-window) :P

Adding an extra parameter (between accelerators and winhandle?) sounds like a fair workaround to me. Defaulting the "global-ness" to false and winhandle to the previously used window would keep with the consistency of other GUISet*() functions. Sure beats not being able to use standard, non-hotkey behavior at all when a registered hotkey is used somewhere else :D

A question about design (just for clarification)... if a global accelerator table is set, should per-window accelerator tables override the global accelerator table when the dialog they're set for is focused? (Or should global/local accelerator table usage not be mixed?)

comment:4 Changed 16 years ago by Jon

At the time I thought you could set accelerators on a per window basis. I found out later that windows only lets one accelerator table be active at a time which means what I did doesn't work. The change I'm proposing is that there is only one accelerator table full stop.

I could probably "switch" tables on the fly as a window becomes active...that might work. But if not it will just be the one table and an option to allow events to one work in one or all windows.

comment:5 Changed 16 years ago by Ultima

I would be surprised if switching on-the-fly didn't work, since MSDN seems to indicate that it's as simple as passing a different HACCEL to TranslateAccelerator. I guess I can't speculate, though, if I don't know the underlying aspects of it (implementation and all) :)

I suppose either solution would work fine for me, since my application expects accelerators to work only on the main parent dialog anyway (and not the children dialogs). Still it just feels like allowing one accelerator only is too limiting (but maybe it's just me :P). To a lesser degree of importance, it's also a break in consistency with the other GUISet*() functions, like GUISetHelp() (which is a less generic hotkey-setting function anyway that does work with multiple GUI windows, and happens to allow overriding of function on child dialogs).

Nevertheless, I look forward to either outcome!

comment:6 Changed 16 years ago by Jon

Unfortunately it's the call to TranslateAccelerator itself that sets the table in memory for the _next_ time that you get a message and call TranslateAccelerator again. So you may have already missed the exact message you were switching tables for.

Anyway, I've got something working with the switching and it seems to be working OK in tests so I'll release a beta in a minute. Basically each window must have its own table. If you want a certain table from the parent to work in the children then you have to also set it in the children. But you can also have a different table in the children which will override.

comment:7 Changed 16 years ago by Jon

  • Milestone set to
  • Owner set to Jon
  • Resolution set to Fixed
  • Status changed from new to closed

Fixed in version:

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

as closed The owner will remain Jon.

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.