Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[Function] HotkeyGUI v0.4


  • Please log in to reply
25 replies to this topic
jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005
Introduction
Let's start with a few (mostly) rhetorical questions...

What is the problem with using the keyboard to define a new hotkey?
If you are the developer (using Autohotkey of course), hopefully nothing. If you've created hotkeys so loosely that you have trouble creating new new ones, you've got other problems that we won't discuss here. :wink:

But what if you are the end-user of an application (maybe your own) and you need to dynamically create a new hotkey?
If you use a control that requires you to actually enter the entire hotkey key combination from the keyboard, it may not be as easy as it appears.

One of problems with the Hotkey Gui control, or any custom control or routine that uses the keyboard to enter or define a hotkey (see the "References" section below), is that if you are entering a hotkey that is already defined or that contains a key or combination of keys that are already defined as hotkeys, the already-defined hotkey may fire while you're trying to define a new one. If that happens, you may never be able to define the hotkey you want, at least not with that control.

As an alternative to the Hotkey Gui control, I've created a somewhat user-friendly function that will pop up a dialog that will allow the user to "select" a hotkey without using the keyboard. Of course, you still have to write the code to put the selected hotkey to work but a least you don't have to use the keyboard to select the actual keys.


Screenshot
Posted Image


The Code
The pertinent files are as follows:Source code: HotkeyGUI.ahk
Documentation: HotkeyGUI.html
Examples: HotkeyGUI -- Examples Of Use.ahk
Issues/Considerations
[*:23ilx80p]The p_Limit parameter restricts the type of keys that can be supported. For this reason, the following keys are out of scope for this project:

[*:23ilx80p]Modifier keys (as hotkeys). Example: Alt, Shift, LWin, etc.
[*:23ilx80p]Joystick keys. Example: Joy1, Joy2, etc.
[*:23ilx80p]Custom combinations. Example: Numpad0 & Numpad1.[/list][*:23ilx80p]Special keys are currently very limited. Additional keys can be added in the future.

[*:23ilx80p]Shift-only keys (characters that include "~", "!", "@", etc.) were purposely excluded for several reasons:

[*:23ilx80p]From a keyboard perspective, Shift-only keys are only available if the Shift key/modifier is pressed. Since the actual keyboard is not used to define a hotkey, including Shift-only keys doesn't make any sense (at least not to me).

[*:23ilx80p]Defining a hotkey that includes a Shift-only key is one part "illusion", one part "delusion", and one part "support headache". For example, the hotkey for Ctrl+Shift+Alt+1 can be defined as "^!+1", "^!!", or "^+!!". All three of these definitions can be defined at the same time but only one will fire. If I were to guess, AutoHotkey supports all three versions of the same hotkey for backward compatibility and/or for flexibility. If you are hard coding hotkeys in a script, this is no big deal. However, if you are dynamically defining multiple hotkeys, this might turn into a problem.[/list]References
The following include documentation and posts that I used to research this mini-project. Thank you for your contribution.
Hotkey GUI control
From the AuthoHotkey documentation
http://www.autohotke...rols.htm#Hotkey

An alternative to "Gui, Add, Hotkey"
http://www.autohotke...pic.php?t=10390

custom hotkey control
http://www.autohotke...opic.php?t=5597
Final Thoughts
I hope that someone finds this useful.

---------------------------------------------------------------------------
v0.1 (Alpha):
Original release.

v0.2:
- Removed p_Timeout parameter. Not really useful for this type of GUI.
- Removed old "Shift-only" code.
- Updated documentation.
- Updated examples.

v0.3:
Not released.

v0.4:
Important: The parameters have changed. Be sure to check the documentation before using.

Additions/Changes/Enhancements/Etc:
- Removed the p_GUI parameter. The function now takes responsibility for finding a GUI number for the HotkeyGUI window.
- Removed the p_LimitMsg parameter. This parameter was never really used.
- Renamed the p_ParentGUI parameter to p_Owner.
- Added p_Hotkey parameter. This parameter contains the default hotkey. See the documentation for more information.
- GUI redesigned to support large® system fonts sizes.
- Updated documentation.
- Updated examples.


BoBo
  • Guests
  • Last active:
  • Joined: --
I'm impressed. Additionally I like the professional way you've provided your tool. Thx for sharing it. :D

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I wish every post in the forum was presented in such a professional way. Very nice!

"Up" is not supported because I've never found a use for it

There are many uses. With mouse button hotkeys, if you want to keep using dragging or panning. At double-strike hotkeys the code is simpler. Multi-key hotkeys can check the status of other keys at key up, so you don't have to press all keys in exactly the same time, etc.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
Now we talking - self contained unit !

Superb jballi. You made good example how AHK extension scritps should be done.

Library of self contained scripts (SCS) is growing up. I urge to all forum population that release their scripts here to design them to be SCS from the start so to make their code reusable with zero-time involving (not counting documentation reading)

the originally-defined hotkey may fire while you're trying to define a new one.

This is not a problem with internal hotkey control but the design problem. Good designed application should disable all hotkies when entering hotkey setup section.
The problem with hotkey control is more that it can not define all possible hotkes (for instance only Win button). Your GUI suffers from same desase. I suggest you adding LWin, Win and RWin among "special" category in your gui, as currently it is not possible to set those hotkeys. I also think that you should redesign modifieer principle so to support hotkey variants like A+B and mentioned Up Down state. This gui, by my opinion, should be capable of doing all hotkey functions AHK can do.
Posted Image

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005

The problem with hotkey control is more that it can not define all possible hotkes (for instance only Win button). Your GUI suffers from same desase. I suggest you adding LWin, Win and RWin among "special" category in your gui, as currently it is not possible to set those hotkeys. I also think that you should redesign modifieer principle so to support hotkey variants like A+B and mentioned Up Down state. This gui, by my opinion, should be capable of doing all hotkey functions AHK can do.

This may be the "having cake" and "no cake", problem. Including "Up" is an easy addition but supporting custom combinations and adding modfiers as keys creates a function that can no longer be used as alternative to the Hotkey Gui control, at least as far the "Limit" parameter is concerned. I'll put my brain on it (we're in trouble now!). I'm sure that I/we will be able to improve on it.

Thank you for your feedback.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
Its just a matter of is it abstarct enough or not
With abstract things you get extension and that is what we all want.

I am sure you will be able to do it. I was looking at your source code and I see that you know exactly how to think about SCS scripts.
Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006
You have error in your code that can break scripts using it:
    ;[===================]
    ;[  Set GUI default  ]
    ;[===================]
    gui %l_GUI%:Default

AFAIK, three is no way you can return old Gui num back as there is nothing like A_Default in AHK.

As the user can pass "" as parentGUI you will not be able to return it back in that scenario ....

You cant do anything else now except using gui %l_GUI%: in every gui command and forget about Default, or set parentGUI to be mandatory

AHK definitely misses something to tell which gui is default.
One alternative would be setting default gui using handles.

Then on start of your function you could write
Gui, +LastFound
oldGuiHandle := WinExist()

gui, %myGui%:Deafult
...
..

Gui, ahk_id %oldGuiHandle%: Default

Posted Image

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005

You have error in your code that can break scripts using it:

    ;[===================]
    ;[  Set GUI default  ]
    ;[===================]
    gui %l_GUI%:Default

AFAIK, three is no way you can return old Gui num back as there is nothing like A_Default in AHK.

As the user can pass "" as parentGUI you will not be able to return it back in that scenario ....

You cant do anything else now except using gui %l_GUI%: in every gui command and forget about Default, or set parentGUI to be mandatory

AHK definitely misses something to tell which gui is default.
One alternative would be setting default gui using handles.

Dynamic GUIs within functions do create unique challenges.

The workaround that I use are parameters for both the dynamic GUI and the the parent GUI. Although these parameters are defined as optional, the function does not allow these parameters to contain optional or "empty" values.

If you look at the code carefully, you'll see that the program checks the integrity of these parameters and if invalid values are found, default valid values are used. Although I haven't tested every possible value, the only way to "break" the script, is to provide incorrect but valid values. For example, if you provide (or neglect to provide) the correct parent GUI, the script will not fail but the wrong GUI window might be disabled and re-enabled. I've tried to document this information in the documentation at the top of the script. The last thing the function does before returning is to reset the default GUI back to the parent GUI.

Don't get me wrong. This code is far from perfect. If you can provide a working example of how this function breaks your script, I will be happy to take a look at it.

Thank you for your feedback.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: Jul 29 2016 12:40 AM
  • Joined: 24 May 2006

For example, if you provide (or neglect to provide) the correct parent GUI, the script will not fail but the wrong GUI window might be disabled and re-enabled

This is what I had in mind... didn't look at doc though...

Also, I already informed you CHooseIconEx topic that your modality loop may break the scripts if the calller function has critical in it. You should set critical off before entering the loop and return it back to old value after.

Don't get me wrong. This code is far from perfect.

Oh, don't be so modest. Your code is not so far from perfect. I don't like "single function" approach because the code is unnatural for me, and I don't see a problem in defying several global variables which will be cleaned afterwards anyway so the only sideefect to be that you can see them in debuger hanging around. This can be ofc, solved with little effort if you provide function with bunch of static variables acting like global, and you use parameters of it to obtain or set new values. After that, even the debuger window will be clean, and code much more maintable.
Posted Image

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
This script is incompatible with Autohotkey_L.
Listview shows all keys in one line concatenated.
I will try to figure out why that happens.

Edit: Looks like an encoding issue.
When I used "Convert to UTF8" in Notepad++ it works in Autohotkey_L Rev 51 (Ascii version btw).

Another edit:

One more thing, it should be noted that the thread calling this function MUST NOT BE CRITICAL, otherwise the labels used in this dialog won't trigger. This was also mentioned in one of the referenced threads, but I think it should also be mentioned here.

And one more:
Here is a function that will check against key collisions from a list of hotkeys defined somewhere in your program. It uses temp01's Array class and requires AHK_L, but should be adaptable to vanilla AHK.
CollisionCheck(key1)
{
	global CustomHotkeys
	key1_Win := InStr(key1, "#") > 0
	key1_Alt := InStr(key1, "!") > 0
	key1_Control := InStr(key1, "^") > 0
	key1_Shift := InStr(key1, "+") > 0
	key1_Left := InStr(key1, "<") > 0 || !InStr(key1, ">")
	key1_Right := InStr(key1, ">") > 0 || !InStr(key1, "<")
	key1_WildCard := InStr(key1, "*") > 0
	key1_stripped := RegExReplace(key1, "[\*\+\^#><!~]*")
	
	Loop % CustomHotkeys.len()
	{
		key2 := CustomHotkeys[A_Index].key
		key2_Win := InStr(key2, "#") > 0
		key2_Alt := InStr(key2, "!") > 0
		key2_Control := InStr(key2, "^") > 0
		key2_Shift := InStr(key2, "+") > 0
		key2_Left := InStr(key2, "<") > 0 || !InStr(key2, ">")
		key2_Right := InStr(key2, ">") > 0 || !InStr(key2, "<")
		key2_WildCard := InStr(key2, "*") > 0
		key2_stripped := RegExReplace(key2, "[\*\+\^#><!~]*")
		DirCollision:=((key1_Left = true && key1_Left = key2_Left)||(key1_Right = true && key1_Right = key2_Right))
		KeyCollision:=(key1_stripped = key2_stripped)
		StateCollision:=((key1_Win = key2_Win && key1_Alt = key2_Alt && key1_Control = key2_Control && key1_Shift = key2_Shift) || key1_WildCard || key2_WildCard)
		if(KeyCollision && StateCollision && DirCollision)
			return true
	}
	return false
}
If editing an existing hotkey, I suggest setting its CustomHotkeys[index].key variable to "" before, and restoring it after the key has been set. This has the disadvantage that the hotkey might not work during the hotkey definition, but I think this is not much of a problem.

I suggest adding this to HotKeyGUI.ahk (line 725):
;[===================]
	;[  Collision Check  ]
	;[===================]
	if(CollisionCheck(HG_HotKey))
	{
		MsgBox  262160,%p_Title%, This hotkey is already in use.
        return 
	}
I think this should be integrated this into the function, by adding a parameter that contains a separated list of keys.
I also suggest setting the OK button as default, so you can confirm the dialog with Enter key.

Additionally, I see a problem about the shift/non-shift keys, in different keyboard language layouts, the characters are distributed differently on the keyboard, for example I have a # key which doesn't reuire shift, but don't have \ and / as non-shift keys. Maybe this can be detected somehow and dynamically shown? Would be a nice improvement.

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011

This script is incompatible with Autohotkey_L.
Listview shows all keys in one line concatenated.

It seemed a shame that this never got updated, so I decided I'd take on the job myself. I hope the OP doesn't mind.

The fix was actually quite simple, just a matter of replacing the delimiter used in the Key strings. I also corrected some minor layout issues with the GUI.
/*
 ______________________
|                      |
|    HotkeyGUI v0.3    |
|______________________|

 ____________________________________________________________________________________
|                                                                                    |
|   Change log:                                                                      |
|       v0.3 rbrtryn                                                                 |
|           Now compatable with AutoHotKey_L Unicode                                 |
|           Resolved encoding issue with ListBox by changing the Keylist delimiter   |
|           Minor changes to the GUI layout                                          |
|           Changed documentation comments to block style                            |
|____________________________________________________________________________________|
            
   Description
   ===========
   This function displays a GUI window that will allow a user to enter/select a
   hotkey without using the keyboard.  See the "Processing Notes" section for
   more information.



   Parameters
   ==========

       Name                Description
       -----               -----------
       p_GUI               The GUI window number.  [Optional]  The default
                           is 81.  Only specify a window number here if it is
                           important to know the exact window number that will
                           be used.  See the "Processing Notes" section (below)
                           for more information.


       p_ParentGUI         The GUI owner of the HotkeyGUI window.  [Optional]
                           The default is 1. 


       p_Title             Window title.  [Optional]  The default is the
                           current script name (sans the extention) plus
                           " - Select Hotkey".


       p_Limit             Hotkey limit.  [Optional]  The default is 0.  See
                           the "Hotkey Limit" section below for more
                           information.


       p_LimitMsg          Hotkey Limit message.  [Optional].  The default is
                           true.

                           If true and a hotkey limit is reached, an error
                           message is displayed and the user returned back to
                           the HotkeyGUI window.

                           If false and a hotkey limit is reached, the function
                           returns the selected hotkey and ErrorLevel (system
                           variable) is set to the Hotkey limit that was
                           reached.

                           See the "Hotkey Limit" section below for more
                           information.


       p_OptionalAttrib    Optional hotkey attributes.  [Optional].  The
                           default is true.

                           If true, all fields in the "Optional Attributes"
                           group are enabled.  If false, all of these fields
                           are disabled.



   Processing Notes
   ================
    o  This function disables the parent window and assigns ownership of the
       HotkeyGUI window to the parent window.  This makes the HotkeyGUI window
       modal which prevents the user from interacting with the parent window
       until the HotkeyGUI window is closed.  Unfortunately, it doesn't
       prevent the end user from interacting with the parent window via
       hotkeys, timers, etc.

    o  To improve usability, this function does not exit until the user closes
       the the HotkeyGUI window.  If a hotkey is used to trigger a call to this
       function, that same hotkey cannot be triggered again (if using the
       system default of #MaxThreadsPerHotkey 1) until the HotkeyGUI window is
       closed.

   o   This function uses the first GUI window that is available in the p_GUI
       (usually 81) to 99 range. If an available window cannot be found, an
       error message is displayed.

       Important:  Although this function can theoretically create up to 99
       independent windows, creating more than one HotkeyGUI window at a time
       is not recommended because the parent GUI window is automatically
       re-enabled when a HotkeyGUI window is closed.  When this occurs, any
       HotkeyGUI window still open becomes modeless (non-modal).



   Hotkey Limits
   =============
   The p_Limit parameter allows the developer to restrict the types of keys
   that are selected.  The following limit values are available:
           
       Limit   Description
       -----   -----------
       1       Prevent unmodified keys
       2       Prevent Shift-only keys 
       4       Prevent Ctrl-only keys 
       8       Prevent Alt-only keys
       16      Prevent Win-only keys
       32      Prevent Shift-Ctrl keys 
       64      Prevent Shift-Alt keys
       128     Prevent Shift-Win keys 
       256     Prevent Shift-Ctrl-Alt keys
       512     Prevent Shift-Ctrl-Win keys
       1024    Prevent Shift-Win-Alt keys

   To use a limit, enter the sum of one or more of these limit values.  For
   example, a limit value of 1 will prevent unmodified keys from being used.
   A limit value of 31 (1 + 2 + 4 + 8 + 16) will require that at least two
   modifier keys be used.



   Return Codes
   ============
   If the function ends after the user has selected a valid key and the
   "Accept" button is clicked, the function returns the selected key in the
   standard AHK hotkey format and ErrorLevel is set to 0.
   Example: Hotkey=^a  ErrorLevel=0

   If p_LimitMsg is false and a key limit test has failed, the function will
   return the selected hotkey and ErrorLevel is set to the limit value that
   failed.  Example: Hotkey=^a  ErrorLevel=4

   If the HotkeyGUI window is canceled (Cancel button, Close button, or Escape
   key), the function returns a null value and Errorlevel is set to 10003.


   Important: ErrorLevel is a system variable and is used by many commands.
   If you are unable to test ErrorLevel immediate after calling this function,
   assign the value to another variable so that the return value is retained.



   Calls To Other Functions
   ========================
   DisplayMessage
   EMessage



   Programming Notes
   =================
   No global variables are used.  However, to get around the use of global
   variables (especially when creating a GUI inside of a function), several
   changes were made:

    -  To keep the code as friendly as possible, static variables (in lieu of
       global variables) are used whenever a GUI object needs a variable.
       Object variables are defined so that a single "gui Submit" command can
       be used to collect the GUI values instead of having to execute a
       "GUIControlGet" command on every GUI control.

   -   For the few GUI objects that are programmatically updated, the ClassNN
       (class name and instance number of the object  Ex: Static4) is used.

   Important: Any changes to the GUI (additions, deletions, etc.) may change
   the ClassNN of objects that are updated.  Use Window Spy (or similar
   program) to identify any changes.


_______________________________________________________________________________
*/

HotkeyGUI(p_GUI=""
    ,p_ParentGUI=""
    ,p_Title=""
    ,p_Limit=""
    ,p_LimitMsg=""
    ,p_OptionalAttrib="")
    {
    ;[==============]
    ;[  Initialize  ]
    ;[==============]
    SplitPath A_ScriptName,,,,l_ScriptName
    l_GUIDelimiter:=|
    l_ErrorLevel=0


    ;[==================]
    ;[    Parameters    ]
    ;[  (Set defaults)  ]
    ;[==================]
    ;-- GUI
    p_GUI=%p_GUI%  ;-- AutoTrim
    if p_GUI is not Integer
        p_GUI=81
     else
        if p_GUI not between 1 and 99
            p_GUI=81


    ;-- Parent GUI
    p_ParentGUI=%p_ParentGUI%  ;-- AutoTrim
    if p_ParentGUI is not Integer
        p_ParentGUI=1
     else
        if p_ParentGUI not between 1 and 99
            p_ParentGUI=1


    ;-- Title
    p_Title=%p_Title%  ;-- AutoTrim
    if strlen(p_Title)=0
        p_Title:=l_ScriptName . " - Select Hotkey"
     else
        {
        ;-- Append to script name if p_title begins with "++"?
        if instr(p_Title,"++")=1
            {
            StringTrimLeft p_Title,p_Title,2
            p_Title:=l_ScriptName . A_Space . p_Title
            }
        }


    ;-- Limit
    p_Limit=%p_Limit%  ;-- AutoTrim
    if p_Limit is not Integer
        p_Limit=0
     else
        if p_Limit not between 0 and 2047
            p_Limit=0


    ;-- LimitMsg
    p_LimitMsg=%p_LimitMsg%  ;-- AutoTrim
    if p_LimitMsg is not Integer
        p_LimitMsg:=true
     else
        if p_LimitMsg not between 0 and 1
            p_LimitMsg:=true


    ;-- OptionalAttrib
    p_OptionalAttrib=%p_OptionalAttrib%  ;-- AutoTrim
    if p_OptionalAttrib is not Integer
        p_OptionalAttrib:=true
     else
        if p_OptionalAttrib not between 0 and 1
            p_OptionalAttrib:=true


    ;[=========================]
    ;[  Find available window  ]
    ;[  (Starting with p_GUI)  ]
    ;[=========================]
    l_GUI:=p_GUI
    loop
        {
        ;-- Window available?
        gui %l_GUI%:+LastFoundExist
        IfWinNotExist
            break

        ;-- Nothing available?
        if l_GUI=99
            {
            MsgBox 262160
                ,HotkeyGUI Error
                ,Unable to create HotkeyGUI window. GUI windows %p_GUI% to 99 are already in use.
            ErrorLevel=9999
            return ""
            }

        ;-- Increment window
        l_GUI++
        }


    ;[===================]
    ;[  Set GUI default  ]
    ;[===================]
    gui %l_GUI%:Default


    ;[=====================]
    ;[  Build/Display GUI  ]
    ;[=====================]
    ;-- Disable parent GUI
    gui %p_ParentGUI%:+Disabled

    ;-- Set ownership
    gui +Owner%p_ParentGUI%

    ;-- Set margins
    gui Margin,6,6

    ;-- GUI options
    gui -MinimizeBox +LabelHotkeyGUI +Delimiter%l_GUIDelimiter%


    ;[===============]
    ;[  GUI Objects  ]
    ;[===============]
    ;-- Modifier
    gui Add
       ,GroupBox
       ,x06 y10 w100 h110
       ,Modifier
    
    static HG_CtrlModifier
    gui Add
       ,CheckBox
       ,x16 y30 w45 h20 vHG_CtrlModifier gHotkeyGUI_UpdateHotkey
       ,Ctrl
    
    static HG_ShiftModifier
    gui Add
       ,CheckBox
       ,y+0 w45 h20 vHG_ShiftModifier gHotkeyGUI_UpdateHotkey
       ,Shift
    
    static HG_WinModifier
    gui Add
       ,CheckBox
       ,y+0 w45 h20 vHG_WinModifier gHotkeyGUI_UpdateHotkey
       ,Win
    
    static HG_AltModifier
    gui Add
       ,CheckBox
       ,y+0 w45 h20 vHG_AltModifier gHotkeyGUI_UpdateHotkey
       ,Alt
    
    
    ;-- Optional Attributes
    gui Add
       ,GroupBox
       ,x106 y10 w140 h110
       ,Optional Attributes
    
    static HG_NativeOption
    gui Add
       ,CheckBox                                                                ;-- Button7
       ,x116 y30 w120 h20 Disabled vHG_NativeOption gHotkeyGUI_UpdateHotkey
       ,~ (Native)
    
    static HG_WildcardOption
    gui Add
       ,CheckBox                                                                ;-- Button8
       ,y+0 w120 h20 Disabled vHG_WildcardOption gHotkeyGUI_UpdateHotkey 
       ,*  (Wildcard)
    
    static HG_LeftPairOption
    gui Add
       ,CheckBox                                                                ;-- Button9
       ,y+0 w120 h20 Disabled vHG_LeftPairOption gHotkeyGUI_LeftPair
       ,< (Left pair only)
    
    static HG_RightPairOption
    gui Add
       ,CheckBox                                                                ;-- Button10
       ,y+0 w120 h20 Disabled vHG_RightPairOption gHotkeyGUI_RightPair
       ,> (Right pair only)
    
    ;-- Enable "Optional Attributes"?
    if p_OptionalAttrib
        {
        GUIControl Enable,Button7
        GUIControl Enable,Button8
        GUIControl Enable,Button9
        GUIControl Enable,Button10
        }
    
    
    ;-- Keys
    gui Add
       ,GroupBox
       ,x6 y120 w240 h180
       ,Keys
    
    static HG_StandardKeysView
    gui Add
       ,Radio
       ,x16 y140 w100 h20 vHG_StandardKeysView gHotkeyGUI_UpdateKeyList Checked
       ,Standard
    
    static HG_FunctionKeysView
    gui Add
       ,Radio
       ,y+0 w100 h20 vHG_FunctionKeysView gHotkeyGUI_UpdateKeyList
       ,Function keys
    
    static HG_NumpadKeysView
    gui Add
       ,Radio
       ,y+0 w100 h20 vHG_NumpadKeysView gHotkeyGUI_UpdateKeyList
       ,Numpad
    
    static HG_MouseKeysView
    gui Add
       ,Radio
       ,y+0 w100 h20 vHG_MouseKeysView gHotkeyGUI_UpdateKeyList
       ,Mouse
    
    static HG_MultimediaKeysView
    gui Add
       ,Radio
       ,y+0 w100 h20 vHG_MultimediaKeysView gHotkeyGUI_UpdateKeyList
       ,Multimedia
    
    static HG_SpecialKeysView
    gui Add
       ,Radio
       ,y+0 w100 h20 vHG_SpecialKeysView gHotkeyGUI_UpdateKeyList
       ,Special
    
    static HG_Key
    gui Add
       ,ListBox                                                                 ; -- ListBox1
       ,x116 y140 w120 h150 vHG_Key gHotkeyGUI_UpdateHotkey
    
    gosub HotkeyGUI_UpdateKeyList
    
    
    ;-- Hotkey Display
    gui Add
       ,Text
       ,x6 y310 w40 h20
       ,Hotkey:
    
    gui Add
       ,Edit                                                                    ;-- Edit1
       ,x+5 w190 h20 +ReadOnly
    
    gui Add
       ,Text
       ,x6 y+5 w40 h20
       ,Desc:
    
    gui Add
       ,Text                                                                    ;-- Static3
       ,x+5 w190 h20 +ReadOnly
       ,None
    
    
    ;-- Buttons
    gui Add
       ,Button
       ,x6 y370 w70 h25 gHotkeyGUI_AcceptButton
       ,&Accept
    
    gui Add
       ,Button
       ,x+5 w70 h25 gHotkeyGUIClose
       ,&Cancel


    ;-- Display HotkeyGUI window
    ;     Generated using SmartGUI Creator 4.0
    gui Show,,%p_Title%


    ;[=====================]
    ;[  Collect window ID  ]
    ;[=====================]
    gui +LastFound
    WinGet HotkeyGUI_hWnd,ID


    ;[=====================]
    ;[  Loop until window  ]
    ;[      is closed      ]
    ;[=====================]
    loop
        {
        sleep 250
        IfWinNotExist ahk_id %HotkeyGUI_hWnd% 
            break
        }


    ;-- Set GUI default back to parent
    gui %p_ParentGUI%:Default


    ;[====================]
    ;[  Return to sender  ]
    ;[====================]
    ErrorLevel:=l_ErrorLevel
    return HG_HotKey  ;-- End of function





    ;*****************************
    ;*                           *
    ;*                           *
    ;*        Subroutines        *
    ;*                           *
    ;*                           *
    ;*****************************
    ;***********************
    ;*                     *
    ;*    Update Hotkey    *
    ;*                     *
    ;***********************
    HotkeyGUI_UpdateHotkey:

    ;-- Set GUI default
    gui %l_GUI%:Default

    ;-- Attach any messages to the current GUI
    gui +OwnDialogs

    ;-- Collect form values
    gui Submit,NoHide


    ;-- Substitute Pause|Break for CtrlBreak?
    if HG_Key in Pause,Break
        if HG_CtrlModifier
            HG_Key=CtrlBreak
    

    ;-- Substitute CtrlBreak for Pause (Break would work OK too)
    if HG_Key=CtrlBreak
        if not HG_CtrlModifier
            HG_Key=Pause
    
    
    ;[================]
    ;[  Build Hotkey  ]
    ;[================]
    ;-- Initialize
    HG_Hotkey=
    HG_HKDesc=
    
    
    ;-- Options
    if HG_NativeOption
        HG_Hotkey:=HG_Hotkey . "~"
    
    if HG_WildcardOption
        HG_Hotkey:=HG_Hotkey . "*"
    
    if HG_LeftPairOption
        HG_Hotkey:=HG_Hotkey . "<"
    
    if HG_RightPairOption
        HG_Hotkey:=HG_Hotkey . ">"
    
    
    ;-- Modifiers
    if HG_CtrlModifier
        {
        HG_Hotkey:=HG_Hotkey . "^"
        HG_HKDesc:=HG_HKDesc . "Ctrl + "
        }
    
    if HG_ShiftModifier
        {
        HG_Hotkey:=HG_Hotkey . "+"
        HG_HKDesc:=HG_HKDesc . "Shift + "
        }
    
    if HG_WinModifier
        {
        HG_Hotkey:=HG_Hotkey . "#"
        HG_HKDesc:=HG_HKDesc . "Win + "
        }
    
    if HG_AltModifier
        {
        HG_Hotkey:=HG_Hotkey . "!"
        HG_HKDesc:=HG_HKDesc . "Alt + "
        }
    
    HG_Hotkey:=HG_Hotkey . HG_Key
    HG_HKDesc:=HG_HKDesc . HG_Key


    ;-- Update Hotkey and HKDescr fields
    GUIControl ,,Edit1,%HG_Hotkey%
    GUIControl ,,Static3,%HG_HKDesc%

    ;-- Return to sender
    return



    ;**********************
    ;*                    *
    ;*    Pair Options    *
    ;*                    *
    ;**********************
    HotkeyGUI_LeftPair:

    ;-- Set GUI default
    gui %l_GUI%:Default


    ;-- Deselect HG_RightPairOption
    GUIControl ,,Button10,0
    gosub HotkeyGUI_UpdateHotkey
    return
    
    

    HotkeyGUI_RightPair:

    ;-- Set GUI default
    gui %l_GUI%:Default


    ;-- Deselect HG_LeftPairOption
    GUIControl ,,Button9,0
    gosub HotkeyGUI_UpdateHotkey
    return
    
    
    
    ;*************************
    ;*                       *
    ;*    Update Key List    *
    ;*                       *
    ;*************************
    HotkeyGUI_UpdateKeyList:
    
    ;-- Set GUI default
    gui %l_GUI%:Default

    ;-- Collect form values
    gui Submit,NoHide
    
    
    ;-- Standard
    if HG_StandardKeysView
        HG_KeyList=
           (ltrim join
            |A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|
            0|1|2|3|4|5|6|7|8|9|0|
            ``|-|=|[|]|`\|;|
            '|,|.|/|
            Space|Tab|Enter|Escape|Backspace|Delete|
            ScrollLock|CapsLock|NumLock|
            PrintScreen|CtrlBreak|Pause|Break|
            Insert|Home|End|PgUp|PgDn|
            Up|Down|Left|Right|
           )
    
    
    ;-- Function keys
    if HG_FunctionKeysView
        HG_KeyList=
           (ltrim join
            |F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|
            F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24
           )
    
    
    ;-- Numpad
    if HG_NumpadKeysView
        HG_KeyList=
           (ltrim join
            |NumLock|NumpadDiv|NumpadMult|NumpadAdd|NumpadSub|NumpadEnter|
            NumpadDel|NumpadIns|NumpadClear|NumpadUp|NumpadDown|NumpadLeft|
            NumpadRight|NumpadHome|NumpadEnd|NumpadPgUp|NumpadPgDn|Numpad0|
            Numpad1|Numpad2|Numpad3|Numpad4|Numpad5|Numpad6|Numpad7|Numpad8|
            Numpad9|NumpadDot
           )
    
    
    ;-- Mouse
    if HG_MouseKeysView
        HG_KeyList=|LButton|RButton|MButton|WheelDown|WheelUp|XButton1|XButton2
    
    
    ;-- Multimedia
    if HG_MultimediaKeysView  
        HG_KeyList=
           (ltrim join
            |Browser_Back|Browser_Forward|Browser_Refresh|Browser_Stop|
            Browser_Search|Browser_Favorites|Browser_Home|Volume_Mute|
            Volume_Down|Volume_Up|Media_Next|Media_Prev|Media_Stop|
            Media_Play_Pause|Launch_Mail|Launch_Media|Launch_App1|Launch_App2|
           )
    
    
    ;-- Special
    if HG_SpecialKeysView
        HG_KeyList=|Help|Sleep
    
    
    ;-- Update HG_KeyList
    GUIControl -Redraw,ListBox1
    GUIControl ,,ListBox1,%l_GUIDelimiter%%HG_KeyList%
    GUIControl +Redraw,ListBox1
    
    
    ;--- Reset HG_Hotkey and HG_HKDesc
    HG_Key=
    gosub HotkeyGUI_UpdateHotkey


    ;-- Return to sender
    return
    
    
    
    ;***********************
    ;*                     *
    ;*    Accept Button    *
    ;*                     *
    ;***********************
    HotkeyGUI_AcceptButton:

    ;-- Attach any messages to the current GUI
    gui +OwnDialogs


    ;-- Any key?
    if not HG_Key
        {
        MsgBox 262160
            ,%p_Title%
            ,A key must be selected.
        return
        }
    
    
    ;[===============]
    ;[  Limit Tests  ]
    ;[===============]
    l_ErrorLevel=0
    l_Limit:=p_Limit
    
    
    ;-- Loop until failure or until all tests have been performed
    loop
        {
        ;-- Are we done here?
        if l_limit<=0
            break
    
    
        ;-----------------
        ;-- Shift+Win+Alt 
        ;-----------------
        if l_limit>=1024
            {
            if (HG_ShiftModifier and HG_WinModifier and HG_AltModifier)
                {
                l_Message=SHIFT+WIN+ALT keys are not allowed.
                l_ErrorLevel=1024
                break
                }
    
            l_limit:=l_limit-1024
            continue
            }
    
    
        ;------------------
        ;-- Shift+Ctrl+Win 
        ;------------------
        if l_limit>=512
            {
            if (HG_ShiftModifier and HG_CtrlModifier and HG_WinModifier)
                {
                l_Message=SHIFT+CTRL+WIN keys are not allowed.
                l_ErrorLevel=512
                break
                }
    
            l_limit:=l_limit-512
            continue
            }
    
    
        ;------------------
        ;-- Shift+Ctrl+Alt 
        ;------------------
        if l_limit>=256
            {
            if (HG_ShiftModifier and HG_CtrlModifier and HG_AltModifier)
                {
                l_Message=SHIFT+CTRL+ALT keys are not allowed.
                l_ErrorLevel=256
                break
                }
    
            l_limit:=l_limit-256
            continue
            }
    
    
        ;-------------
        ;-- Shift+Win 
        ;-------------
        if l_limit>=128
            {
            if (HG_ShiftModifier and HG_WinModifier)
                {
                l_Message=SHIFT+WIN keys are not allowed.
                l_ErrorLevel=128
                break
                }
    
            l_limit:=l_limit-128
            continue
            }
    
    
        ;-------------
        ;-- Shift+Alt 
        ;-------------
        if l_limit>=64
            {
            if (HG_ShiftModifier and HG_AltModifier)
                {
                l_Message=SHIFT+ALT keys are not allowed.
                l_ErrorLevel=64
                break
                }
    
            l_limit:=l_limit-64
            continue
            }
    
    
        ;--------------
        ;-- Shift+Ctrl 
        ;--------------
        if l_limit>=32
            {
            if (HG_ShiftModifier and HG_CtrlModifier)
                {
                l_Message=SHIFT+CTRL keys are not allowed.
                l_ErrorLevel=32
                break
                }
    
            l_limit:=l_limit-32
            continue
            }
    
    
        ;------------
        ;-- Win only 
        ;------------
        if l_limit>=16
            {
            if (HG_WinModifier
            and not (HG_CtrlModifier or HG_ShiftModifier or HG_AltModifier))
                {
                l_Message=WIN-only keys are not allowed.
                l_ErrorLevel=16
                break
                }
    
            l_limit:=l_limit-16
            continue
            }
    
    
        ;------------
        ;-- Alt only 
        ;------------
        if l_limit>=8
            {
            if (HG_AltModifier
            and not (HG_CtrlModifier or HG_ShiftModifier or HG_WinModifier))
                {
                l_Message=ALT-only keys are not allowed.
                l_ErrorLevel=8
                break
                }
    
            l_limit:=l_limit-8
            continue
            }
    
    
        ;-------------
        ;-- Ctrl only 
        ;-------------
        if l_limit>=4
            {
            if (HG_CtrlModifier
            and not (HG_ShiftModifier or HG_WinModifier or HG_AltModifier))
                {
                l_Message=CTRL-only keys are not allowed.
                l_ErrorLevel=4
                break
                }
    
            l_limit:=l_limit-4
            continue
            }
    
    
        ;--------------
        ;-- Shift only 
        ;--------------
        if l_limit>=2
            {
            if (HG_ShiftModifier
            and not (HG_CtrlModifier or HG_WinModifier or HG_AltModifier))
                {
                l_Message=SHIFT-only keys are not allowed.
                l_ErrorLevel=2
                break
                }
    
            l_limit:=l_limit-2
            continue
            }
    
    
        ;--------------
        ;-- Unmodified 
        ;--------------
        if l_limit>=1
            {
            if not (HG_CtrlModifier
                or  HG_ShiftModifier
                or  HG_WinModifier
                or  HG_AltModifier)
                {
                l_Message=
                   (ltrim join`s
                    At least one modifier must be used.  Other restrictions
                    may apply.
                   )
    
                l_ErrorLevel=1
                break
                }
    
            l_limit:=l_limit-1
            continue
            }
        }
        
    
    ;[====================]
    ;[  Display message?  ]
    ;[====================]
    if l_ErrorLevel
        if p_LimitMsg
            {
            ;-- Display message
            MsgBox 262160
                ,%p_Title%
                ,%l_Message%

            ;-- Reset l_ErrorLevel
            l_ErrorLevel=0

            ;-- Send 'em back
            return
            }


    ;[==================]
    ;[  Ok, We're done  ]
    ;[   Shut it done   ]
    ;[==================]
    gosub HotkeyGUIExit

    
    ;-- Return to sender
    return



    ;***********************
    ;*                     *
    ;*    Close up shop    *
    ;*                     *
    ;***********************
    HotkeyGUIEscape:
    HotkeyGUIClose:
    HG_Hotkey:=""
    l_ErrorLevel=10003


    HotkeyGUIExit:

;;;;;    ;-- Set GUI default (needed because of timer)
;;;;;    gui %l_GUI%:Default 


    ;-- Enable the parent window
    gui %p_ParentGUI%:-Disabled


    ;-- Destroy the HotkeyGUI window so that the window can be reused
    gui destroy

    return  ;-- End of subroutines
    }


jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005

This script is incompatible with Autohotkey_L.
Listview shows all keys in one line concatenated.

It seemed a shame that this never got updated, so I decided I'd take on the job myself. I hope the OP doesn't mind.

The fix was actually quite simple, just a matter of replacing the delimiter used in the Key strings. I also corrected some minor layout issues with the GUI.

Thank you for taking the time and effort to post your changes/fixes.

Although I've redesigned/rewritten this function a couple of times since I originally posted it (2007), I don't use it much and so it has been infected with the very hard to cure "low priority" disease. Also, I don't use AutoHotkey_L yet so getting it to work with AHK_L... OK, I think you get it. If/When I post a new version, I will try to incorporate your changes.

Once again, thank you for your interest and your contribution.

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
interstingly, i was going to post an update for the 0.2 version for ahk basic users, i just rearranged the gui also and made some minor changes, because the GUI simply doesn't fit on windows 120 dpi display setting.. we'll see if i can tidy it up

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005
v0.4
Although functionality is basically the same, the function has been reworked to include additional flexibility. A few notes:
[*:14da7lhw]The parameters have changed. Read the documentation carefully before using.

[*:14da7lhw]I've done minimal testing of this function with the latest version of AutoHotkey_L (Unicode). However, since I'm not a regular AutoHotkey_L user (yet), the function is not AutoHotkey_L certified. If you have trouble using this function with AutoHotkey_L (any version), let me know and I'll take a look/see.

[*:14da7lhw]The GUI should work with normal (96 dpi), large (120 dpi), and extra large (144 dpi) system fonts but may not produce desirable results with anything larger. Your results may vary.See the bottom of the top post for a complete list of changes.

Edit: I have been remiss in checking all the posts in this thread for changes to include in the new version. If I missed something that you think would be valuable, please post it or PM me. Thanks.

Edit 2: Updated the system font information.

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
thanks, i can confirm that v0.4 works with 120dpi windows fonts on winxp

i guess no need for me to post my version. all i did was move the "keys" groupbox to the top, and the two sub groupboxes below. and i moved some of the keys in the radios to different radio groups