Want AutoIt3 HotKeySet to Emulate AutoHotKey Application Filtering

433 views Asked by At

Objective

I am building a generic solution for advanced controlling of an arbitrary programs UI using AutoIt3, invoked by pressing various keys, or issuing a command.

Components

  • TargetUI - Program to be controlled by sending clicks and keys
  • MainAu3 - AutoIt program doing the sending
  • MainIni - File containing control positions and other info in a specialized notation, also contains hotkey information. All info is specific to a particular TargetUI - ie. One MainIni for each TargetUI
  • KeyHookScript - optional? Either AutoIt or AutoHotKey script

Facts

  • HotKeySet() - AutoIt function allows setting and unsetting of system-wide hotkeys
  • AutoHotKey - Scripting Language - Allows Application filtering for hotkeys via #IfWinActive
  • MainAu3 is currently designed to take a command param, provided by some KeyHookScript
  • MainAu3 is slow to invoke, due to parsing of MainIni on startup, which is necc. due to program goals

Issues

  • Since MainAu3 is slow to invoke, one option is to have it run in the background and have its own keyhooks, OR have the KeyHookScript communicate with it somehow
  • MainAu3 and MainIni will have more than one instance -- an instance for each TargetUI. This causes collision if using HotKeySet() in each MainAu3 unless you set and unset everytime TargetUIs get focus - which seems to be asking for trouble

Anticipated Approach

  • It looks like I will need a MainAu3Manager that monitors applications and ensures the proper MainAu3/MainIni are running as needed. It will also need to maintain the Singleton(?) KeyHookScript written in AutoHotKey

Questions

  • How ill-advised is it to attempt to swap out HotKeySet/Unset via each MainAu3 based on application that has focus and is a TargetUI?
  • Given that is a bad approach, which communication method is best to talk to the running MainAu3s?
  • How hard is it to create my own hooking mechanism in AutoIt via _IsPressed, and would that create a "polling problem" if it is running frequently in each MainAu3

Communication Methods

These are all the ones I can think of and I want this to be fast and reliable, and easily coded haha

  • File based - create a file(s) in some directory containing the command, let MainAu3 delete it/them
  • Registry - probably slower than files
  • Hidden window - Communicate by setting window text (I KNOW!) faster than file?
  • Hidden window - SendMessage ugh, too hard to code
  • DDE - don't get me started

Decision Point

I will need to communicate with a running MainAu3 regardless, because, reasons. The real issue is whether to embed the keyhook mechanism inside MainAu3 instances or not.

What I would like is if AutoIt had a reliable mechanism for keyhooks that were application specific like in AutoHotKeys #IfWinActive.

If I embed, I hate both options of setting and unsetting HotKeySet(), as well as polling _IsPressed(). Then again, an external keyhook via AutoHotKey is a pain too.

I think I will try embedding with HotKeySet() first, and see how that acts.

Any advice?

Note "Communication" is one-way - I just need to send commands.

1

There are 1 answers

0
Milos On BEST ANSWER

In case the GUI you are trying to control is your own GUI:

If you want hotkeys that are not system wide, you should use

GUISetAccelerators ( accelerators [, winhandle] )

GUISetAccelerators

Sets the accelerator table to be used in a GUI window.

Parameters

accelerators    A 2 dimensional array holding the accelerator table (See remarks).
winhandle   [optional] Windows handle as returned by GUICreate() (default is the previously used window).

Remarks

The array passed to this function contains the hotkey and the control ID of the accelerator. The array must be defined as Local/Global $aArray[n][2] - where n is the number of accelerator keys to set:

    $aArray[0][0] = Hotkey (in HotKeySet() format) of 1st accelerator
    $aArray[0][1] = Control ID of the 1st accelerator, as returned by GUICtrlCreate...
    $aArray[1][0] = Hotkey of 2nd accelerator
    $aArray[1][1] = Control ID of the 2nd accelerator
    ...
    $aArray[n][0] = Hotkey of nth accelerator
    $aArray[n][1] = Control ID of the nth accelerator

Passing this function a non-array will unset all accelerators for the given winhandle.

Example:

#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>

Example()

Func Example()
    GUICreate("Custom MsgBox", 225, 80)

    GUICtrlCreateLabel("Please select a button.", 10, 10)
    Local $idYes = GUICtrlCreateButton("Yes", 10, 50, 65, 25)
    Local $idNo = GUICtrlCreateButton("No", 80, 50, 65, 25)
    Local $idExit = GUICtrlCreateButton("Exit", 150, 50, 65, 25)

    ; Set GUIAccelerators for the button controlIDs, these being Ctrl + y and Ctrl + n
    Local $aAccelKeys[2][2] = [["^y", $idYes],["^n", $idNo]]
    GUISetAccelerators($aAccelKeys)

    GUISetState(@SW_SHOW) ; Display the GUI.

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                MsgBox($MB_SYSTEMMODAL, "You selected", "Close")
                ExitLoop

            Case $idYes
                MsgBox($MB_SYSTEMMODAL, "You selected", "Yes") ; Displays if the button was selected or the hotkey combination Ctrl + y was pressed.

            Case $idNo
                MsgBox($MB_SYSTEMMODAL, "You selected", "No") ; Displays if the button was selected or the hotkey combination Ctrl + n was pressed.

            Case $idExit
                MsgBox($MB_SYSTEMMODAL, "You selected", "Exit")
                ExitLoop

        EndSwitch
    WEnd
    GUIDelete() ; Delete the GUI.
EndFunc   ;==>Example

If you are controlling an external GUI then maybe try fiddling with Any GUI to make it work