Jump to content
AndyS19

Pass unused Accelerator keys back to the system

Recommended Posts

I have a script that traps ^A and ^C accelerator keys via the GUISetAccelerators() function, and in the key handlers, I check to see if the focus is on the control that I want the keys to operate on.

However, when I see that I'm not on that control, I want to pass the ^C and ^A back to the system so I can copy and past data on other controls.

Here is my test script.  I have it applying ^A and ^C only to the ListView control.  When I put focus on the Input control, I want to be able to copy and paste normally.

Opt("GUICloseOnESC", 1) ; ESC does not close the GUI
Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt('MustDeclareVars', 1)
OnAutoItExitRegister("ExitStageLeft")

#include <Array.au3>
#include <GuiListBox.au3>
#include <GUIConstantsEx.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

Global $hGUI, $iInput, $iList, $hInput, $hList

_Main()

Func _Main()
    Local $str, $parts

    $hGUI = GUICreate("", 250, 500)

    $iInput = GUICtrlCreateInput("2", 90, 5, 50, 20)
    $hInput = GUICtrlGetHandle($iInput)
    $iList = GUICtrlCreateListView("First Column         ", 5, 30, 240, 470, $LBS_EXTENDEDSEL)
    $hList = GUICtrlGetHandle($iList)
    For $ndx = 1 To 100
        $str = StringFormat("%s ABC", $ndx)
        Local $ret = _GUICtrlListView_AddItem($hList, $str)
    Next

    setupSpecialKeysHandlers()

    GUISetOnEvent($GUI_EVENT_CLOSE, "ExitStageLeft")

    GUISetState(@SW_SHOW)

    While (1)
        Sleep(250)
    WEnd

EndFunc   ;==>_Main

Func ExitStageLeft()
    Exit (1)
EndFunc   ;==>ExitStageLeft

Func setupSpecialKeysHandlers()
    Local $aAccelKeys[1][2]
    Local $ar, $parts, $key, $handler, $id

    ; Create a table of Special keys and their handlers
    $ar = StringSplit("", "")
    _ArrayAdd($ar, "{ENTER} - handle_ENTER_key  ")
    _ArrayAdd($ar, "^a      - handle_CTRL_A_key ")
    _ArrayAdd($ar, "^c      - handle_CTRL_C_key ")
    ReDim $aAccelKeys[UBound($ar) - 1][2]

    ; Now, create $aAccelKeys array with the table data.
    ; For each entry, create a Dummy GUI and associate its
    ; ID with the special key.
    For $ndx = 1 To UBound($ar) - 1
        $parts = StringSplit($ar[$ndx], "-", 2)
        $key = StringStripWS($parts[0], 8)
        $handler = StringStripWS($parts[1], 8)
        $id = GUICtrlCreateDummy()

        $aAccelKeys[$ndx - 1][0] = $key
        $aAccelKeys[$ndx - 1][1] = $id
        GUICtrlSetOnEvent($id, $handler)
    Next

    ; Dump the contents of the $aAccelKeys array
    For $ndx = 0 To UBound($aAccelKeys) - 1
        logMsg("$aAccelKeys" _
                 & "   [" & $ndx & "][0] = " & StringFormat("%-8s", $aAccelKeys[$ndx][0]) _
                 & "   [" & $ndx & "][1] = " & $aAccelKeys[$ndx][1])
    Next

    GUISetAccelerators($aAccelKeys) ; Setup the Special keys hooks
EndFunc   ;==>setupSpecialKeysHandlers

Func logMsg($msg, $lnum = @ScriptLineNumber)
    ConsoleWrite("+++:" & $lnum & ": " & $msg & @CRLF)
EndFunc   ;==>logMsg

Func handle_ENTER_key()
    logMsg("+++: handle_ENTER_key() entered")
EndFunc   ;==>handle_ENTER_key

Func handle_CTRL_A_key()
    logMsg("+++: handle_CTRL_A_key() entered")
    If (Not isCtrlFocused($hList)) Then Return

    selectAllGLVItems()
EndFunc   ;==>handle_CTRL_A_key

Func handle_CTRL_C_key()
    logMsg("+++: handle_CTRL_C_key() entered")
    If (isCtrlFocused($hList)) Then
    extractSelListViewGamesToClip()
    Else
    EndIf
EndFunc   ;==>handle_CTRL_C_key

Func isCtrlFocused($hWnd)
    Local $hCtrl

    $hCtrl = ControlGetHandle($hGUI, "", ControlGetFocus($hGUI))

    Return ($hWnd = $hCtrl) ? True : False
EndFunc   ;==>isCtrlFocused

Func selectAllGLVItems()
    Local $hWnd = $hList, $iIndex

    For $iIndex = 0 To _GUICtrlListView_GetItemCount($hWnd)
        _GUICtrlListView_SetItemSelected($hWnd, $iIndex)
    Next

EndFunc   ;==>selectAllGLVItems

Func extractSelListViewGamesToClip()
    Local $hWnd = $hList
    Local $iIndex,  $item, $str, $sep = ""

    $str = ""
    For $iIndex = 0 To _GUICtrlListView_GetItemCount($hWnd)
        If (_GUICtrlListView_GetItemSelected($hWnd, $iIndex)) Then
            $item = _GUICtrlListView_GetItemText($hWnd, $iIndex)
            $str &= $sep & $item
            $sep = @CRLF
        EndIf
    Next

    ClipPut($str)

    logMsg("Copied " & StringLen($str) & " bytes to the Clipboard:" & @CRLF & $str)
EndFunc   ;==>extractSelListViewGamesToClip

 

Share this post


Link to post
Share on other sites

There's probably a better way to detect the clicks but this is my attempt.

Opt("GUICloseOnESC", 1) ; ESC does not close the GUI
Opt("GUIOnEventMode", 1) ; Change to OnEvent mode
Opt('MustDeclareVars', 1)
OnAutoItExitRegister("ExitStageLeft")

#include <Array.au3>
#include <EditConstants.au3>
#include <GuiListBox.au3>
#include <GUIConstantsEx.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

Global $hGUI, $iInput, $iList, $hInput, $hList
Global $b_KeysActive = False ; initial state of the accelerators

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY') ; register for the listview clicks
GUIRegisterMsg($WM_COMMAND, "ED_WM_COMMAND") ; register for input clicks

_Main()

Func _Main()
    $hGUI = GUICreate("", 250, 500)
    $iInput = GUICtrlCreateInput("2", 90, 5, 50, 20)
    $hInput = GUICtrlGetHandle($iInput)
    $iList = GUICtrlCreateListView("First Column         ", 5, 30, 240, 470, $LBS_EXTENDEDSEL)
    $hList = GUICtrlGetHandle($iList)

    For $i = 1 To 100
        _GUICtrlListView_AddItem($hList, 'ABC ' & $i)
    Next

    GUISetOnEvent($GUI_EVENT_CLOSE, "ExitStageLeft")
    GUISetState(@SW_SHOW)

    While (1)
        Sleep(250)
    WEnd

EndFunc   ;==>_Main 

Func ExitStageLeft()
    Exit (1)
EndFunc   ;==>ExitStageLeft

Func setupSpecialKeysHandlers()
    If $b_KeysActive Then Return ; do nothing if the accelerator keys have been activated

    Local Static $i_FirstRun = 0 ; set a variable to check for array update

    Local Static $aAccelKeys[3][2] = _ ; create the initial array
            [['{ENTER}', 'handle_ENTER_key'], _
            ['^a', 'handle_CTRL_A_key'], _
            ['^c', 'handle_CTRL_C_key']]

    If Not $i_FirstRun Then ; set the accelerator keys and create the dummys
        Local $handler, $id

        ; Now, update $aAccelKeys array with the table data.
        ; For each entry, create a Dummy GUI and associate its
        ; ID with the special key.
        For $i = 0 To UBound($aAccelKeys) - 1
            $handler = $aAccelKeys[$i][1] ; set the event handler
            $id = GUICtrlCreateDummy() ; create dummy control
            $aAccelKeys[$i][1] = $id ; replace the handle with the dummy id
            GUICtrlSetOnEvent($id, $handler)

            logMsg("$aAccelKeys" _
                     & "   [" & $i & "][0] = " & StringFormat("%-8s", $aAccelKeys[$i][0]) _
                     & "   [" & $i & "][1] = " & $aAccelKeys[$i][1])
        Next

        $i_FirstRun = 1 ; update the static so the array is not created again after first run
        $b_KeysActive = True ; update global that keys are active
    EndIf

    GUISetAccelerators($aAccelKeys) ; Setup the Special keys hooks
EndFunc   ;==>setupSpecialKeysHandlers

Func logMsg($msg, $lnum = @ScriptLineNumber)
    ConsoleWrite("+++:" & $lnum & ": " & $msg & @CRLF)
EndFunc   ;==>logMsg

Func handle_ENTER_key()
    logMsg("+++: handle_ENTER_key() entered")
EndFunc   ;==>handle_ENTER_key

Func handle_CTRL_A_key()
    logMsg("+++: handle_CTRL_A_key() entered")
    If (Not isCtrlFocused($hList)) Then Return

    selectAllGLVItems()
EndFunc   ;==>handle_CTRL_A_key

Func handle_CTRL_C_key()
    logMsg("+++: handle_CTRL_C_key() entered")
    If (isCtrlFocused($hList)) Then
        extractSelListViewGamesToClip()
    Else
    EndIf
EndFunc   ;==>handle_CTRL_C_key

Func isCtrlFocused($hWnd)
    Local $hCtrl

    $hCtrl = ControlGetHandle($hGUI, "", ControlGetFocus($hGUI))

    Return ($hWnd = $hCtrl) ? True : False
EndFunc   ;==>isCtrlFocused

Func selectAllGLVItems()
    Local $hWnd = $hList, $iIndex

    For $iIndex = 0 To _GUICtrlListView_GetItemCount($hWnd)
        _GUICtrlListView_SetItemSelected($hWnd, $iIndex)
    Next

EndFunc   ;==>selectAllGLVItems

Func extractSelListViewGamesToClip()
    Local $hWnd = $hList
    Local $iIndex, $item, $str, $sep = ""

    $str = ""
    For $iIndex = 0 To _GUICtrlListView_GetItemCount($hWnd)
        If (_GUICtrlListView_GetItemSelected($hWnd, $iIndex)) Then
            $item = _GUICtrlListView_GetItemText($hWnd, $iIndex)
            $str &= $sep & $item
            $sep = @CRLF
        EndIf
    Next

    ClipPut($str)

    logMsg("Copied " & StringLen($str) & " bytes to the Clipboard:" & @CRLF & $str)
EndFunc   ;==>extractSelListViewGamesToClip

Func WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
    Local $tNMHDR, $IdFrom, $iCode

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $IdFrom = DllStructGetData($tNMHDR, 'IdFrom')
    $iCode = DllStructGetData($tNMHDR, 'Code')

    Switch $IdFrom
        Case $iList
            Switch $iCode
                Case $NM_CLICK
                    setupSpecialKeysHandlers()
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func ED_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg

    Local $iCode = BitShift($wParam, 16)

    Switch $lParam
        Case $hInput
            Switch $iCode
                Case $EN_SETFOCUS
                    GUISetAccelerators(0) ; turn off the accelerators
                    $b_KeysActive = False ; update the global that keys are inactive
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>ED_WM_COMMAND

 

Share this post


Link to post
Share on other sites

That looks like what I need, thank you.  I have to make this code expansible because in my actual script, I have more than 100 GUI controls!  I'm going to add some code to create an array of control ID/handles for only the controls that I want my special ^A and ^C keys to operate on.  If the interrupting control is not in the list, I'll turn off the accelerators, if it's in the list, I'll turn the accelerators on.   Thank you for your help.

Share this post


Link to post
Share on other sites

Actually, the form has 3 Tabs, is almost 14,000 lines and includes more than 50 UDF files .  It's for managing Timekeeper assignments and payments via CSV files.  If there's a better way, I'd be interested to try it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By Skysnake
      Hi
      I am trying to set Accelerator keys from an array.
      I select the KEY and CONTROL from a SQLite table, the Array looks like that generated for the Helpfile, but I can't get the CONTROLS to resolve...
      I though about Assign & Eval, but not sure if that's a step in the right direction. IsDeclared shows that the $var exists in Local Scope -1.  
       
      Local $Main = GUICreate("Custom MsgBox", 225, 80) GUICtrlCreateLabel("Please select a button.", 10, 10) Local $idButton_Yes = GUICtrlCreateButton("Yes", 10, 50, 65, 25) Local $idButton_No = GUICtrlCreateButton("No", 80, 50, 65, 25) Local $idButton_Exit = GUICtrlCreateButton("Exit", 150, 50, 65, 25) Local $query, $aResult, $iRows, $iColumns $query = "" ;reset $query = "Select hotkey_key, hotkey_ctrl from mytable where mykeys = 'hotkey' ; " ; ; Query $iRval = _SQLite_GetTable2d($sqliteDb, $query, $aResult, $iRows, $iColumns) If $iRval = $SQLITE_OK Then Local $sizeofHotkeys = UBound($aResult) - 1 ConsoleWrite("$sizeofHotkeys " & $sizeofHotkeys & @CRLF) If $sizeofHotkeys > 0 Then Local $main__aAccelKeys[$sizeofHotkeys][2] For $i = 0 To $sizeofHotkeys - 1 $j = $i + 1 ; replace friendly text with code -- ! alt + Shift ^ Ctrl # Windows $aResult[$j][0] = StringReplace($aResult[$j][0], "Alt", "!") $aResult[$j][0] = StringReplace($aResult[$j][0], "Shift", "+") $aResult[$j][0] = StringReplace($aResult[$j][0], "Ctrl", "^") $main__aAccelKeys[$i][0] = $aResult[$j][0] ;--- $main__aAccelKeys[$i][1] = $aResult[$j][1] ;--- Next ;~ Row|Col 0|Col 1 ;~ Row 0|F2|$idButton_Yes ;~ Row 1|F3|$idButton_No _DebugArrayDisplay($main__aAccelKeys) Local $rv = GUISetAccelerators($main__aAccelKeys, $Main) GUISetState(@SW_SHOW) ; Display the GUI.  
      Please note that this is a modified Helpfile example.
      The Helpfile specifies (a) WinHandle and (b) last Gui created.
      --> the example uses a control not a WinHandle and (b) what happens with ChildGuis? Also, the HelpFile specifies lower case, yet the examples show "{F1}" upper case?
      Also, is there a way to check the result of the GuiSetAccelerator function? 
      Note, if I add these to lines after the FOR loop, then the F1 works, and the DebugArrayDisplays shows control 4... not it's name... So I am in the right place, but my $vars names do not convert to their control numbers in the GUI
      Next $main__aAccelKeys[$sizeofHotkeys - 1][0] = "{F1}" ; -- -- use the extra row for the F1 $main__aAccelKeys[$sizeofHotkeys - 1][1] = $ChmHLP ;--- Skysnake
    • By therks
      So I'm working on an application and I've hot keyed all the numbers, and for some reason this particular combination doesn't work. All the other numbers with Ctrl+Shift work fine, and all other combinations of modifiers work with 0. Has anyone else encountered this? It's very strange. 
      Guicreate('', 300, 300) $button = GUICtrlCreateButton('Button', 0, 0) Dim $accel = [ [ '^+0', $button ] ] GUIsetaccelerators($accel) Do $gm = guigetmsg()  If $gm = $button then msgbox(0,'','test') Until $gm = - 3 Sorry for the ugly code, i typed this up on my phone. 😅
    • By John C.
      ;Adding $BS_DEFPUSHBUTTON doesn't work
              $idCopy_Data = GUICtrlCreateButton("Copy Data Only", $iButtonWidth_2, $aiGUISize[1] - $iButtonMargin, $iButtonWidth_2, 20, $BS_DEFPUSHBUTTON)
      ;Adding these two lines doesn't work either
               Local $aAccelKeys[2][2] = [["{enter}", $idCopy_Data], ["^{enter}", $idCopy_ID]]
              GUISetAccelerators($aAccelKeys)
       
    • By vindicta
      Hello everyone,
      I am trying to setup a GUI accelerator to close the utility as soon as esc is pressed.  It works fine with hotkey but I want to make sure that the utility only exits if its window was active when esc was pressed. My utility has 2 buttons, Backup and Restore.
      The exit function checks if the button clicked was Backup or Restore and then displays an error message accordingly.
      If pressed backup, $button = 1
      if pressed restore, $button = 2
      the value of $button is set inside backup() or restore() functions
      Opt("GUIOnEventMode", 1) Opt("GUICoordMode", 1) $Form1 = GUICreate("Form1", 419, 124, 238, 194, $WS_DLGFRAME) $B_backup = GUICtrlCreateButton("Backup", 48, 40, 145, 41) $B_restore = GUICtrlCreateButton("Restore", 224, 40, 145, 41) ;================ > HotKeySet('{ESC}', "terminate") GUICtrlSetOnEvent($B_backup, "Backup") GUICtrlSetOnEvent($B_restore, "Restore") GUISetState(@SW_SHOW) Dim $accelKey[1][2] = [["{ESC}", terminate()]] GUISetAccelerators($accelKey) While 1     Switch GUIGetMsg()         Case $GUI_EVENT_CLOSE             Exit     EndSwitch WEnd  
      Exit function:
      func terminate() Do     $msg = GUIGetMsg() Until $msg <> 0 While 1         If $button = 1 Then             ProcessClose("robocopy.exe")             MsgBox(16, "Abort!", "Backup Aborted!")             exit         ElseIf $button = 2 Then             ProcessClose("robocopy.exe")             MsgBox(16, "Abort!", "Restore Aborted!")             exit         Else             While 1                 For $i = 3 To 1 Step -1                     SplashTextOn("Closing Utility...", $i, 130, 54, -1, -1, 0, "Calibri", "", 900)                     Sleep(1000)                 Next                 ExitLoop             WEnd             SplashOff()             Exit Endif WEnd What am I doing wrong here? The utility closes as soon as it launches with Splash text.
×
×
  • Create New...