Jump to content
Sign in to follow this  
Jetrunner

Ctrl + A (Select all) Expected keys produce Ding sound

Recommended Posts

Jetrunner

I'm trying to modify my Edit field to accept the keys Ctrl + A to select all text, the same as right clicking and hitting select all. I managed to do it, but now every time I hit the keys, it produces an error noise. >_< I want to continuously check for these keys, so I looped them together with my GUI.

I've tried removing the registry entry for the Ding.wav sound, and then replacing it after my _IsPressed event, but it wasn't working (and editing the registry just to remove the Ding.wav sound seems messy, what if the program or OS crashed and their error noise stopped working for their entire OS?)

I did some reading on StackOverflow, and it looks like there are some solutions (albeit, not always great ones) to do this in C++ and other languages. I don't really understand them that well, but it seems like there may be a function for expected keys so you don't cause an error (or ding noise) when pressed. Is there any way to do this with AutoIt? The other threads I've found so far don't seem to have a solution that would work for me.

#include <GuiConstantsEx.au3> ;for main GUI elements
#include <GUIEdit.au3> ; for Edit controls (e.g. Select All)
#include <Constants.au3> ;for CMD related functions
#include <WindowsConstants.au3> ;for vertial-only scrolling edit box
#include <Misc.au3> ;for ispressed function (key pressed)

Global $hDLL = DllOpen("user32.dll")

GUICreate("MyProgramName", 400, 420)
$editfield = GUICtrlCreateEdit("Enter text here", 0, 0, 400, 320, $WS_VSCROLL)

Func selectAll() ;
    ; FIX POTENTIAL ERROR: ----> add code to check that edit field is the GUI item in focus! (to ensure we only select text when user expects it)
    _GUICtrlEdit_SetSel($editfield,0,-1) ;uses GUIEdit.au3
EndFunc

; >>>>> OTHER IRRELEVANT FUNCTIONS HERE <<<<

mainGUI_loop()

Func mainGUI_loop()
While 1
;       NOTE: FIX DING NOISE SOMEHOW! (following If statement produces noise...)
        If ((_IsPressed("41", $hDLL)) AND (_IsPressed("11", $hDLL))) Then ; Ctrl + A does (Select All) on text in edit box.
                selectAll()
                While ((_IsPressed("41", $hDLL)) AND (_IsPressed("11", $hDLL))) ;prevent accidental double-presses?
                    Sleep(250) ;make sure is not stalling script (modify sleep timer to check)
                WEnd
        EndIf

    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ProcessClose ( $fPID )
            Exit
        Case $exititem
            ProcessClose ( $fPID )
            Exit

        ; >>>>> OTHER IRRELEVENT GUI CODE HERE... <<<<<
    EndSwitch

WEnd
EndFunc
Edited by Jetrunner

Share this post


Link to post
Share on other sites
Jetrunner

For the record, I just tried to do it with GUISetAccelerators instead of _IsPressed, and while that removes the ding, it presents another problem: it works anywhere in the window. It also breaks an input box I've got in the GUI from accepting Ctrl+A to select all text in the input box as would be default (now it only applies to the edit box... meaning it seems accelerators "steal" or override input from other functions???).

Sorry if my Array for AccelKeys isn't right, I'm still trying to figure out arrays. [:sweating:]

 

Local $AccelKeys[2][2] = [["^a", $editfield],["^a", $editfield]]
        GUISetAccelerators($AccelKeys)

mainGUI_loop()

; ===========================
; Main GUI Loop. !!!!!  .....
; ===========================
Func mainGUI_loop()
While 1
    Switch GUIGetMsg()
        ;test of accelerator key(s)
        Case $editfield
            ;MsgBox("","title","Ctrl + A pressed - now what?","") ;debug only
            selectAll()
; >>>>> OTHER IRRELEVENT CODE HERE... <<<<<
    EndSwitch
WEnd
EndFunc

EDIT: on second thought, it appears GUISetAccelerators is only meant to be used with buttons?

I want to use Ctrl + A to select all text (in any text field that is in focus), and then Enter to submit the entered text (to a function).

Local $AccelKeys[2][2] = [["^a", $editfield],["{Enter}", $nameInput]]
        $keysPressed = GUISetAccelerators($AccelKeys)

mainGUI_loop()

Func mainGUI_loop()
While 1
    Switch GUIGetMsg()

        ;BROKEN:
        Case $keysPressed
            selectAll()
            MsgBox("","","executed");debug only
            ;^ still broken.

; <!-- ==== Other irrelevant code ==== -->

    EndSwitch
WEnd
EndFunc

I can't seem to find a way to get my Case to recognize that my cursor is in the edit field, instead of a button being pressed like the help file example. Even if I code it get get the user's focus (mouse/text cursor location and/or selected GUI tab), I still don't know if there's a way to check it with my Case switch (or case select, either), because as I said it doesn't seem to do anything like that in the example, (and all GUISetAccelerators will return is 0 or 1, which I don't seem to be able to get to work with multiple buttons).

Anyway, so far it seems I'm either stuck with these new problems, or the old problem of not having a way to take user key inputs without having Ding.wav noises flying around everywhere.
 

Share this post


Link to post
Share on other sites
NewPlaza

; >>>>> OTHER IRRELEVANT FUNCTIONS HERE <<<<

Not too irrelevant.....

>Running AU3Check (1.54.22.0)  from:C:Program Files (x86)AutoIt3

C:ScrapNew AutoIt v3 Script.au3(33,34) : WARNING: $fPID: possibly used before declaration.

            ProcessClose ( $fPID )

~~~~~~~~~~~~~~~~~~~~~~~^

C:ScrapNew AutoIt v3 Script.au3(35,23) : WARNING: $exititem: possibly used before declaration.

        Case $exititem

~~~~~~~~~~~~~~~^

C:ScrapNew AutoIt v3 Script.au3(33,34) : ERROR: $fPID: undeclared global variable.

            ProcessClose ( $fPID )

~~~~~~~~~~~~~~~~~~~~~~~^

C:ScrapNew AutoIt v3 Script.au3(35,23) : ERROR: $exititem: undeclared global variable.

        Case $exititem

~~~~~~~~~~~~~~~^

C:ScrapNew AutoIt v3 Script.au3 - 2 error(s), 2 warning(s)

 

Share this post


Link to post
Share on other sites
Jetrunner

I tried this (again?). Not sure if I used this right, but I get the same problem I got when I originally tried GUISetAccelerators, where it simultaneously disables another text field's default "Ctrl + A to select all" functionality (the latter being an input field with GUICtrlCreateInput).

So I fix one thing (edit field select all) but break another (input box select all).

Here is my re-worked code (based on AZJIO's code):

; ====================================================
; INCLUDES
; ====================================================

#include <GuiConstantsEx.au3> ;for main GUI elements
#include <GUIEdit.au3> ; for Edit controls (e.g. Select All)
#include <Constants.au3> ;for CMD related functions
#include <WindowsConstants.au3> ;for vertial-only scrolling edit box
#include <Misc.au3> ;for ispressed function
#include <File.au3> ;for writing new file
#include <GuiComboBox.au3> ;for advanced combo box features (apparently adding/removing items, in a way that you'd expect it to behave normally, is "advanced")
#include <EditConstants.au3> ; for edit & input (???) because it was included in Select all example (by AZJIO: http://pastebin.com/iasqvvsN) making sure nothing breaks.

Global $hDLL = DllOpen("user32.dll")

; ====================================================
; GUI LAYOUT
; ====================================================

; GUI
GUICreate("MyProgramName", 400, 420)
; For custom icon:
; GUISetIcon(@SystemDir & "\mspaint.exe", 0)

; >>> File menu' and sub-menus' code goes here. <<<

; EDIT FIELD
$editfield = GUICtrlCreateEdit("Enter text to speak here", 0, 0, 400, 320, $WS_VSCROLL)

; INPUT FIELD
$NameInput = GUICtrlCreateInput($myName, 131, 370, 130, 20)

; >>> Other button code goes here <<<


; ====================================================
; FUNCTIONS
; ====================================================

; >>> Other functions go here <<<

Func selectAll() ;

        global $nDummy = GUICtrlCreateDummy()
        Dim $aAccelKeys[1][2] = [["^a", $nDummy]]

        GUISetAccelerators($aAccelKeys)

EndFunc

; >>> Function calls and calls to other functions go here. <<<
; myFunction()
selectAll()
mainGUI_loop()


Func mainGUI_loop()
While 1
    Switch GUIGetMsg()
        Case $nDummy
            GUICtrlSendMsg($editfield, $EM_SETSEL, 0, -1)
        Case $GUI_EVENT_CLOSE
            ProcessClose ( $fPID )
            Exit
        Case $exititem
            ProcessClose ( $fPID )
            Exit
; >>> Other Cases go here (button presses, etc.) <<<
    EndSwitch
WEnd
EndFunc

Oh and this gem...

; >>>>> OTHER IRRELEVANT FUNCTIONS HERE <<<<

Not too irrelevant.....

 

It's largely for the sake of brevity, I have hundreds of lines of code. I could give you every piece of my code, but if you bothered to read what I already posted here, and my question, then you'd realize they really are irrelevant. So unless you were going to just rely on the SciTE debugger instead of using your eyes, or think that I should give my entire programs' source code up, for help on one single problem (after solving dozens myself and working on this for almost a week), then I see no reason why you think they are necessary for this discussion.

I've painstakingly trimmed out all most of the fat. It makes it easier to read.

Edited by Jetrunner

Share this post


Link to post
Share on other sites
AZJIO

Jetrunner

To find the error you have to prepare a special example. Perhaps in the process, you will understand a mistake.

Maybe for you it will be a novelty, but I at the time of writing the program simultaneously creating dozens of scripts to test separately any part before paste it into the script. You save your time, but you don't save time ten people who could help you.

Edited by AZJIO

Share this post


Link to post
Share on other sites
Jetrunner

Jetrunner

To find the error you have to prepare a special example. Perhaps in the process, you will understand a mistake.

Maybe for you it will be a novelty, but I at the time of writing the program simultaneously creating dozens of scripts to test separately any part before paste it into the script. You save your time, but you don't save time ten people who could help you.

I'm not sure I understand what you are saying, exactly. However, I did test my scripts before trimming them and pasting the important parts here. I got no compile errors. The only errors I found were unwanted and/or unexpected functionality in the actual program. I'm not trying to fix a syntax error here.

Edited by Jetrunner

Share this post


Link to post
Share on other sites
dragan

Here's an example:
 

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiEdit.au3>
#include <WinAPI.au3>

$Form1 = GUICreate("Form1", 600, 400)
$Edit1 = GUICtrlCreateEdit("Some text in Edit1" & @CRLF & "focus me, and press CTRL+A", 0, 0, 300, 400)
$Edit2 = GUICtrlCreateEdit("Some text in Edit2" & @CRLF & "focus me, and press CTRL+A", 300, 0, 300, 400)
GUISetState(@SW_SHOW)

Global $hSelAll = GUICtrlCreateDummy()
Dim $AccelKeys[1][2] = [["^a", $hSelAll]]
GUISetAccelerators($AccelKeys, $Form1)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $hSelAll
            _SelectAllTextInEdit()
    EndSwitch
WEnd


Func _SelectAllTextInEdit();will make select all text in eny focused edit, as long as it is edit inside $Form1 winhandle because we bound GUISetAccelerators to $Form1
    Local $theHandle = _WinAPI_GetFocus()
    Local $TheClass = _WinAPI_GetClassName($theHandle)
    If $TheClass = 'Edit' Then _GUICtrlEdit_SetSel($theHandle, 0, -1)
EndFunc
Edited by dragan
  • Like 1

Share this post


Link to post
Share on other sites
Jetrunner

 

Here's an example:

It works, tried it earlier today. But... I decided I wanted to try it without using the #include WinAPI.au3 (possibly save some overhead?). I re-worked it a bit, and here is my solution (see my selectAllgo() function):

; ====================================================
; INCLUDES (some used for functions i've trimmed out)
; ====================================================

#include <GuiConstantsEx.au3> ;for main GUI elements
;#include <WinAPI.au3> ;for finding window focus. NOT REQUIRED if using this method...
#include <GUIEdit.au3> ; for Edit controls (e.g. Select All)
#include <WindowsConstants.au3> ;for vertial-only scrolling edit box
#include <Constants.au3> ;for CMD related functions
#include <File.au3> ;for writing new file
#include <GuiComboBox.au3> ;for "advanced" combo box features

Global $hDLL = DllOpen("user32.dll")


; ====================================================
; GUI LAYOUT
; ====================================================

; GUI
$mainGUI = GUICreate("My Program Title", 400, 420)

; EDIT FIELD
$editfield = GUICtrlCreateEdit("Enter text here", 0, 0, 400, 120, $WS_VSCROLL)

; INPUT FIELD
$nameInput = GUICtrlCreateInput($myName, 0, 200, 200, 120)

; >>> Other GUI buttons and controls were here. <<<


; ====================================================
; DECLARE FUNCTIONS (all except main gui loop)
; ====================================================

; >>> Other functions were here <<<

Func selectAllsetup() ; Create dummy to use as target for select all functions & set up accelerator keys.

    Global $dummyCtrl = GUICtrlCreateDummy()
    Global $AccelKeys[1][2] = [["^a", $dummyCtrl]]
    GUISetAccelerators($AccelKeys, $mainGUI)

EndFunc

Func selectAllgo()

    ; NOTE: It appears AutoIt and/or Windows identify any field such as "input" or "edit" all as being "edit" class. (makes sense, you are editing text)

    $focusedControl = ControlGetFocus ( "My Program Title", "" ) ; find control that is in keyboard focus.
    Local $i = 1 ; edit to 0 if any "edit" field's ClassNameNN starts with 0. (check the id with AutoIt v3 Window Info)

    While $i <= 2 ; insert total number of edit fields here (or highest expected number, or variable depicting such)
            If $focusedControl == ("Edit" & $i) Then
                $theHandle = ControlGetHandle ( "", "", "Edit" & $i)
                _GUICtrlEdit_SetSel($theHandle, 0, -1)
            EndIf
        $i = $i + 1
    WEnd

EndFunc

; ====================================================
; USE FUNCTIONS
; ====================================================

; >>> Other functions were here <<<

selectAllsetup()

mainGUI_loop()
;
; =================================================
; Main GUI Loop. !!!!!  .....  !!!!!  .....  !!!!!
; =================================================
;
Func mainGUI_loop()
While 1
    Switch GUIGetMsg()
        Case $dummyCtrl
            selectAllgo() ; <----- Actually select all!
        Case $GUI_EVENT_CLOSE
            ProcessClose ( $festivalProcessID )
            Exit
        Case $exititem
            ProcessClose ( $festivalProcessID )
            Exit
; >>> Other Cases were here. <<<
    EndSwitch
WEnd
EndFunc

^This works flawlessly (and, thankfully, still without the Ding.wav sound) for programs with edit fields and input boxes. However, if you want to have selectable text in your ComboBox (i.e. drop down menu), I tried the following:

; >>> Snip snip <<<

; COMBO
$comboOptionDefault = "Select Option"
$myInputCombo = GUICtrlCreateCombo($comboOptionDefault, 131, 346, 120, 100)

; >>> Snip snip <<<

Func selectAllgo()
    Local $i = 1 ; edit to 0 if ClassNameNN starts with 0. (check the id with AutoIt v3 Window Info)
    While $i <= 2 ; insert total number of edit fields here (or highest expected number)
        ;MsgBox(0, "Value of $i is:", $i)
        If $focusedControl == ("Edit" & $i) Then
            $theHandle = ControlGetHandle ( "", "", "Edit" & $i)
            _GUICtrlEdit_SetSel($theHandle, 0, -1)
                        MsgBox("","test1","this section done1")
        EndIf
        If $focusedControl == ("ComboBox" & $i) Then
            $theHandle = ControlGetHandle ( "", "", "ComboBox" & $i)
            _GUICtrlEdit_SetSel($theHandle, 0, -1)
            MsgBox("","test2","this section done2")
        EndIf
    $i = $i + 1
    WEnd

EndFunc

; >>> Snip snip <<<

Which didn't work! While I can move my cursor around in the ComboBox, I still can't use Ctrl + A to select text (even if I remove the 1st if statement in selectAllgo() that handles Edit class controls). Of course, it still works for the edit boxes. I tested the 2nd if statement by adding a MsgBox, and it wasn't even doing it at all. (why???)

To fix it, I had to do this:

Func selectAllgo()

    $focusedControl = ControlGetFocus ( "My Program Title", "" ) ; such as "Edit1" or "Edit2" etc.

    Local $i = 1 ; edit to 0 if ClassNameNN starts with 0. (check the id with AutoIt v3 Window Info)
    While $i <= 3 ; insert total number of edit fields here (or highest expected number)
        If $focusedControl == ("Edit" & $i) Then ; "Edit" apparently can also work with ComboBox fields.
            $theHandle = ControlGetHandle ( "", "", "Edit" & $i)
            _GUICtrlEdit_SetSel($theHandle, 0, -1)
                ;MsgBox("","test1","this section done1");debug only
        EndIf
    $i = $i + 1
    WEnd

EndFunc

In otherwords, I found out, and took advantage of the fact that AutoIt (somewhat-counterintuitively) lets me select the ComboBox (the third field with text and movable cursor) with "Edit3" instead of "ComboBox1". So I changed my max number for $i.  I'm not sure if it's just a way it names things, but in this case, it appears it does not recognize "ComboBox1" as a legitimate control name/id, despite that being its name in the AutoIt Window Info tool.

In any case, the above code works. :D

I'm just not 100% sure why (because the control id/name thing doesn't make sense to me). :unsure:

Edited by Jetrunner

Share this post


Link to post
Share on other sites
dragan

I think this is much better solution (if you still wanna use it WITHOUT WinApi.au3), also CTRL+A works for combo by default:

 

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiEdit.au3>

$Form1 = GUICreate("Form1", 600, 400)
$Edit1 = GUICtrlCreateEdit("Some text in Edit1" & @CRLF & "focus me, and press CTRL+A", 0, 0, 300, 350)
$Edit2 = GUICtrlCreateEdit("Some text in Edit2" & @CRLF & "focus me, and press CTRL+A", 300, 0, 300, 350)
$Combo1 = GUICtrlCreateCombo('', 0, 360, 600);CTRL+A already works for combo, by default.
GUICtrlSetData(-1, 'Some Data 1|Some Data 2|Some Data 3|Some Data 4|Some Data 5|Some Data 6', 'Some Data 1')
GUISetState(@SW_SHOW)

Global $hSelAll = GUICtrlCreateDummy()
Dim $AccelKeys[1][2] = [["^a", $hSelAll]]
GUISetAccelerators($AccelKeys, $Form1)


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $hSelAll
            _SelectAllTextInEdit()
    EndSwitch
WEnd


Func _SelectAllTextInEdit();will make select all text in eny focused edit, as long as it is edit inside $Form1 winhandle because we bound GUISetAccelerators to $Form1
    Local $theHandle = DllCall("user32.dll", "hwnd", "GetFocus")
    If NOT @error Then
        $TheClass = DllCall("user32.dll", "int", "GetClassNameW", "hwnd", $theHandle[0], "wstr", "", "int", 4096)
        If NOT @error Then
            If $TheClass[2] = 'Edit' Then _GUICtrlEdit_SetSel($theHandle[0], 0, -1)
        EndIf
    EndIf
EndFunc
  • Like 1

Share this post


Link to post
Share on other sites
Jetrunner

That works, too. I wouldn't have thought of using DLL's. I guess I have some more reading to do. :sweating:

You've proven again that there's more than one way to code. :sorcerer:

 

And it does work by default, but if you code things a certain way, the default way will break. :oops:

Oh, also:

I'm just not 100% sure why (because the control id/name thing doesn't make sense to me). :unsure:

 

I since read this in the help file:

  • CLASSNN - The ClassnameNN value as used in previous versions of AutoIt, such as "Edit1" (emphasis/color added)

Not sure if that was my problem, but maybe knowing that will help others.

Edited by Jetrunner

Share this post


Link to post
Share on other sites
dragan

last script I posted should work for combo anyway - why? - well because combo ACTS as "Edit" while typing values. So if you use the code I posted, you should be able to mark all text even under your circumstances where you build things "a certain way".

Share this post


Link to post
Share on other sites
Jetrunner

Yeah, I've noticed through this that Edit boxes, Input boxes, and Combo boxes, are all being recognized as "Edit" class, so as long as one gets that point across properly in their code, they should all work.

I marked your >Post # 8 as best answer because it seems the easiest to understand and implement for a new user (and works on all controls... i.e. any focused text field... as it seems all your examples do).

Thanks for the help. :D

Edited by Jetrunner

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
Sign in to follow this  

×