Jump to content
Yashied

HotKeyInput UDF

Recommended Posts

C:\Program Files\AutoIt3\Include\HotKeyInput.au3(115,66) : ERROR: Opt() called with illegal argument 1: "OnExitFunc"
Global $OnHotKeyInputExit = Opt('OnExitFunc', 'OnHotKeyInputExit')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
C:\Program Files\AutoIt3\Include\HotKeyInput.au3(122,1) : ERROR: syntax error
==
^

Share this post


Link to post
Share on other sites

@Yashied, These Hotkey UDFs that you made are really great. Studying them has been very educational. Thank you very much for sharing. :(

One change that I made is to the VK Array. Instead of having a third include file, I just tucked into a small stringsplit function.

Global $VK = _VK_Array()

Func _VK_Array()

    Local $sVK = 'None||||||||Backspace|Tab|||Clear|Enter||||||Pause|CapsLosk|||||||Esc|||||Spacebar|PgUp|PgDown|End|Home|' & _
    'Left|Up|Right|Down|Select|Print|Execute|PrtScr|Ins|Del|Help|0|1|2|3|4|5|6|7|8|9||||||||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|Win|Win|0x5D||Sleep|Num 0|Num 1|Num 2|Num 3|Num 4|Num 5|Num 6|Num 7|Num 8|Num 9|Num *|Num +|0x6C|' & _
    'Num -|Num .|Num /|F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24|||||||||NumLock|' & _
    'ScrollLock|||||||||||||||Shift|Shift|Ctrl|Ctrl|Alt|Alt|BrowserBack|BrowserForward|BrowserRefresh|BrowserStop|BrowserSearch|' & _
    'BrowserFavorites|BrowserStart|VolumeMute|VolumeDown|VolumeUp|NextTrack|PreviousTrack|StopMedia|Play|Mail|Media|0xB6|0xB7|||' & _
    ';|+|,|-|.|/|~|||||||||||||||||||||||||||[|\|]|"|0xDF|||0xE2|||0xE5||0xE7|||||0xEC||||||||||0xF6|0xF7|0xF8|0xF9|0xFA|0xFB|0xFC|0xFD|0xFE|'

     Return StringSplit($sVK, '|', 2)

EndFunc

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

I want to use it to write simple script to make hotkeys and I need LAlt, RAlt, LCtrl etc... and just it, without other keys. It is possible to change this script for this?

Share this post


Link to post
Share on other sites

I want to use it to write simple script to make hotkeys and I need LAlt, RAlt, LCtrl etc... and just it, without other keys. It is possible to change this script for this?

No. Edited by Yashied

Share this post


Link to post
Share on other sites

The library has been updated.

v1.3

  • Added compatibility with UAC elevated windows (Windows Vista+).
  • Renamed _GUICtrlHotKey* to _GUICtrlHKI_*.
  • vkArray.au3 integrated into the library.


Share this post


Link to post
Share on other sites

Thanks for this. I was on the verge of figuring out how to create this myself.

Libraries are one of the greatest things about programming...no more recreating the wheel!

Share this post


Link to post
Share on other sites

How can I make it so that if the user clicks outside of the input control (but within the scripts GUI), the control stops trying to capture input?

Share this post


Link to post
Share on other sites

How can I make it so that if the user clicks outside of the input control (but within the scripts GUI), the control stops trying to capture input?

This is what I did to "fix" this:

I maintain an array of the coordinates of each hotkey input in the GUI, and for each mouse click in the GUI check to see if a hotkey input is focused, and if it is, and the click isn't within the coordinates of a hotkey input, I focus the "background" of the window.

$ctrlID_main_unfocused = _WinAPI_GetDlgCtrlID(ControlGetHandle($title, "", ControlGetFocus($title)))


Case $GUI_EVENT_PRIMARYDOWN
    $hotkeyIsFocused = _hotkey_isInputFocused()
    ; Unfocus hotkey input boxes if click outside of them
    If Not _hotkey_clickedIn($extendedMsg[3], $extendedMsg[4]) Then
        If $hotkeyIsFocused Then
            ControlFocus($hwndGUI_main, "", $ctrlID_main_unfocused)
        EndIf
    Else
        $inputHasFocus = False
    EndIf

In other news:

@Yashied: How does this work with non-English language keyboards? I don't have access to such a thing, but I'm wondering how this will work.

I noticed this line...

Global $hkVk = StringSplit('None||||||||Backspace|Tab|||Clear|Enter||||||Pause|CapsLosk|||||||Esc|||||Spacebar|PgUp|PgDown|End|Home|Left|Up|Right|Down|Select|Print|Execute|PrtScr|Ins|Del|Help|0|1|2|3|4|5|6|7|8|9||||||||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|Win|Win|0x5D||Sleep|Num 0|Num 1|Num 2|Num 3|Num 4|Num 5|Num 6|Num 7|Num 8|Num 9|Num *|Num +|0x6C|Num -|Num .|Num /|F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|F13|F14|F15|F16|F17|F18|F19|F20|F21|F22|F23|F24|||||||||NumLock|ScrollLock|||||||||||||||Shift|Shift|Ctrl|Ctrl|Alt|Alt|BrowserBack|BrowserForward|BrowserRefresh|BrowserStop|BrowserSearch|BrowserFavorites|BrowserStart|VolumeMute|VolumeDown|VolumeUp|NextTrack|PreviousTrack|StopMedia|Play|Mail|Media|0xB6|0xB7|||;|+|,|-|.|/|~|||||||||||||||||||||||||||[|\|]|"|0xDF|||0xE2|||0xE5||0xE7|||||0xEC||||||||||0xF6|0xF7|0xF8|0xF9|0xFA|0xFB|0xFC|0xFD|0xFE|', '|', 2)

Which I assume is used to display the keys pressed. I'm not clear on how non-English keyboards map on to English stuff.

Also, CapsLock is mispelled. :oops:

Edited by therms

Share this post


Link to post
Share on other sites

Global $aKey[256]

$aKey[0x00] = 'Пусто'
$aKey[0x01] = ''
$aKey[0x02] = ''
$aKey[0x03] = ''
$aKey[0x04] = ''
$aKey[0x05] = ''
$aKey[0x06] = ''
$aKey[0x07] = ''
$aKey[0x08] = 'Возврат'
$aKey[0x09] = 'Табуляция'
$aKey[0x0A] = ''
$aKey[0x0B] = ''
$aKey[0x0C] = ''
$aKey[0x0D] = 'Ввод'

; etc.

_KeyLoadName($aKey)


Share this post


Link to post
Share on other sites

Global $aKey[256] $aKey[0x00] = 'Пусто' $aKey[0x01] = '' $aKey[0x02] = '' $aKey[0x03] = '' $aKey[0x04] = '' $aKey[0x05] = '' $aKey[0x06] = '' $aKey[0x07] = '' $aKey[0x08] = 'Возврат' $aKey[0x09] = 'Табуляция' $aKey[0x0A] = '' $aKey[0x0B] = '' $aKey[0x0C] = '' $aKey[0x0D] = 'Ввод' ; etc. _KeyLoadName($aKey)
Damn. I was hoping there was a way to get this info from Windows instead of me having to do manual translation for every language I wanted to support.

Thanks for the info!

Share this post


Link to post
Share on other sites

You can play with the following.

#Include <APIConstants.au3>
#Include <WinAPIEx.au3>

For $i = 0x00 To 0xFF
    ConsoleWrite(Hex($i, 2) & ' - ' & _WinAPI_GetKeyNameText(BitShift(_WinAPI_MapVirtualKey($i, $MAPVK_VK_TO_VSC), -16)) & @CR)
Next

Share this post


Link to post
Share on other sites

Yashied, your UDF is perfect as always, just very hard to read.

I'm trying to change the output to controls for current keyboard layout. For example, if the user switches the keyboard to another language, then will not be able to identify defined shortcuts in the future:

US KB (0x0409): Ctrl + 3

CS KB (0x0405): Ctrl + 3 (but Ctrl + š is correctly)

For this case I tried to modify your UDF function with _WinAPI_GetKeyNameText($lParam) called via GUIRegisterMsg($WM_KEYDOWN, 'WM_KEYDOWN'), but I was unable to incorporate into your script and obtain the correct parameter ($lParam) for the translation of a key. So, Is there any way to get the correct keyname for any keyboard?

This solution is useful, but only for the default KBLayout:

You can play with the following.

#Include <APIConstants.au3>
#Include <WinAPIEx.au3>

For $i = 0x00 To 0xFF
    ConsoleWrite(Hex($i, 2) & ' - ' & _WinAPI_GetKeyNameText(BitShift(_WinAPI_MapVirtualKey($i, $MAPVK_VK_TO_VSC), -16)) & @CR)
Next

Moreover, ability to translate keycode->name for current keyboard layout may be useful for parsing a reading stored shorcuts.

Thanks for UDF and any tip

Edited by Logman

Share this post


Link to post
Share on other sites

No response? I try to rephrase the question...

How do I get KeyNameText of virtual-key code for a specific (and installed) keyboard layout? I tried to search this forum, the MSDN library, but unfortunately I could not find a solution.

The code below will return same result. Function __WinAPI_MapVirtualKeyEx does not accept the parameter $sKbLayout.

The function alway returns only KeyNameText for default keyboard layout specified in Regional and language settings.

; # Question: How do I get the correct name of the key for each keyboard layout?
; # Note: I know two parameters: Virtual codes & KB Layout
; # Note: Both types of keyboards have been installed (Win7 x64, Au3: 3.3.8.1)

; local $sCurrentKbLayout = hex(_WinAPI_GetKeyboardLayout(_WinAPI_GetForegroundWindow()),4)

; $VK_3 >> 0x33: (US keyboard = '3', CS keyboard = 'š')
Const $VK_3 = 0x33

; two types of keyboard layout
Const $US_KbLayout  = '0409'
Const $CS_KbLayout  = '0405'

ConsoleWrite('KeyNameText(US KB): ' & __WinAPI_GetKeyNameText(BitShift(__WinAPI_MapVirtualKeyEx(hex($VK_3), $US_KbLayout), -16)) & @CR)
ConsoleWrite('KeyNameText(CS KB): ' & __WinAPI_GetKeyNameText(BitShift(__WinAPI_MapVirtualKeyEx(hex($VK_3), $CS_KbLayout), -16)) & @CR) ; << same result

Func __WinAPI_MapVirtualKeyEx($sHexKey, $sKbLayout)
    Local Const $MAPVK_VK_TO_VSC  = 0
    Local Const $MAPVK_VSC_TO_VK  = 1
    Local Const $MAPVK_VK_TO_CHAR  = 2
    Local Const $MAPVK_VSC_TO_VK_EX = 3
    Local Const $MAPVK_VK_TO_VSC_EX = 4
    Local $Ret = DllCall('user32.dll', 'long', 'MapVirtualKeyEx', 'int', '0x' & $sHexKey, 'int', $MAPVK_VK_TO_VSC, 'int', '0x' & $sKbLayout)
    Return $Ret[0]
EndFunc   ;==>_WinAPI_MapVirtualKeyEx

Func __WinAPI_GetKeyNameText($lParam)
   Local $Ret = DllCall('user32.dll', 'int', 'GetKeyNameTextW', 'long', $lParam, 'wstr', '', 'int', 256)
   If (@error) Or (Not $Ret[0]) Then
     Return SetError(1, 0, '')
   EndIf
   Return $Ret[2]
EndFunc   ;==>__WinAPI_GetKeyNameText

I'm really confused. Thanks for any guidance.

Edited by Logman

Share this post


Link to post
Share on other sites

US KB (0x0409): Ctrl + 3

CS KB (0x0405): Ctrl + 3 (but Ctrl + š is correctly)

1. No, it's not correct. For the hotkeys you should always use the unshifted character values.

2. You are wrong to use the MapVirtualKeyEx() function.

#Include <APIConstants.au3>
#Include <WinAPIEx.au3>

Global $US_KbLayout  = _WinAPI_LoadKeyboardLayout(0x0409)
Global $CS_KbLayout  = _WinAPI_LoadKeyboardLayout(0x0405)

For $i = 0 To 255
    ConsoleWrite(ChrW(_WinAPI_MapVirtualKeyEx($i, $MAPVK_VK_TO_CHAR, $CS_KbLayout)) & @CR)
Next

Func _WinAPI_MapVirtualKeyEx($iCode, $iType, $hLocale = 0)

    Local $Ret = DllCall('user32.dll', 'uint', 'MapVirtualKeyExW', 'uint', $iCode, 'uint', $iType, 'uint_ptr', $hLocale)

    If (@error) Or (Not $Ret[0]) Then
        Return SetError(1, 0, 0)
    EndIf
    Return $Ret[0]
EndFunc   ;==>_WinAPI_MapVirtualKeyEx

Share this post


Link to post
Share on other sites

Yashied, I have a small problem with the function _GUICtrlHKI_GetHotKey, that returns the wrong value.

I used an example from the first post in the following code where I try to change the shortcut key twice, but the second set returns wrong result. In the following example I am trying to change the hotkey shortcut from F12 to F11 and then back to F12. No change from F11 to F12. Where is the problem?

Thanks

#Include <APIConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <HotKeyInput.au3>

Local $iMyHotKey = 123    ; F12

; F11 (122)
; F12 (123)

$iMyHotKey = _changeHotKey($iMyHotKey)            ; <<--- manually change from F12 to F11 then click to OK
ConsoleWrite ('1: ' & $iMyHotKey & @LF)            ; <<--- Correct (122)

$iMyHotKey = _changeHotKey($iMyHotKey)            ; <<--- manually change from F11 to F12 then click to OK
ConsoleWrite ('2: ' & $iMyHotKey & @LF)            ; <<--- WRONG! Still 122 instead of 123

$iMyHotKey = _changeHotKey($iMyHotKey)            ; you can see wrong value...
Exit

Func _changeHotKey($iOldHK)
    Local $Form, $HKI1, $HKI2, $Button, $Text, $NewHK
    $Form = GUICreate('Test', 300, 160)
    GUISetFont(8.5, 400, 0, 'Tahoma', $Form)
    $HKI1 = _GUICtrlHKI_Create($iOldHK, 56, 55, 230, 20)            ; <<---- OLD HotKey as default
    ; Lock CTRL-ALT-DEL for Hotkey Input control, but not for Windows
    _KeyLock(0x062E)
    GUICtrlCreateLabel('Hotkey1:', 10, 58, 44, 14)
    GUICtrlCreateLabel('Click on Input box and hold a combination of keys.' & @CR & 'Press OK to view the code.', 10, 10, 280, 28)
    $Button = GUICtrlCreateButton('OK', 110, 124, 80, 23)
    GUICtrlSetState(-1, BitOR($GUI_DEFBUTTON, $GUI_FOCUS))
    GUISetState()
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                $NewHK = -1
                ExitLoop
            Case $Button
                $NewHK = _GUICtrlHKI_GetHotKey($HKI1)                ; <<--- second call returns the wrong result ?
                ExitLoop
        EndSwitch
    WEnd
    GUIDelete ($Form)
    Return $NewHK
EndFunc ; ==>> _changeHotKey

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

×
×
  • Create New...