Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Retrieve Key Names from OnMessage WM_KeyDown


  • Please log in to reply
45 replies to this topic
  • Guests
  • Last active:
  • Joined: --
Hi,

Is there way to retrive key names from OnMessage WM_KeyDown? I tried this but doesn't work. Thanks.
Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, vMyEdit
Gui, Show, h100 w200

WM_KEYDOWN := 0x100
OnMessage(WM_KEYDOWN, "WM_KeyDown") 

WM_KeyDown(p) { 
    GuiControl,, MyEdit, % GetKeyName(p)
} 


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
;)
Gui, Margin, 20, 20

Gui, Add, Text,, Pressed Key

Gui, Add, Edit, ReadOnly vMyEdit

Gui, Show, h100 w200



WM_KEYDOWN := 0x100

OnMessage(WM_KEYDOWN, "WM_KeyDown")

Return

GuiClose:

ExitApp



WM_KeyDown(wParam) {

	GuiControl,, MyEdit,% Chr(wParam)

}


  • Guests
  • Last active:
  • Joined: --
Thanks HotKeyIt. There is a problem. It does not catch some keys such as F keys and Insert, Home etc.

I think wParam returns a Virtual Key code. So I thought this should work but doesn't.
Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit
Gui, Show, h100 w200

WM_KEYDOWN := 0x100
OnMessage(WM_KEYDOWN, "WM_KeyDown")
Return
GuiClose:
ExitApp

WM_KeyDown(wParam) {
   GuiControl,, MyEdit,% GetKeyName("VK" wParam)
}


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
The value following "VK" must be in hexadecimal (the same as when it is used to define a hotkey).
WM_KeyDown(wParam) {
	SetFormat IntegerFast, H
	GuiControl,, MyEdit,% GetKeyName("VK" SubStr(wParam+0, 3))
}
Although undocumented, the "0x" prefix is tolerated, so the SubStr call isn't really necessary.
vk0x20::MsgBox Spacebar.


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
For me F10 does not seems to work, can anybody confirm :?:

  • Guests
  • Last active:
  • Joined: --
Thanks Lexikos.

For me F10 does not seems to work, can anybody confirm :?:

Me too. F10 doesn't work here.

  • Guests
  • Last active:
  • Joined: --
Could somebody improve this code? I'm exhausted. This shows pressed keys in the edit box. It is pretty much like the built-in Hotkey control but can (is going to) support mouse buttons and windows key as well.

Known Issues:
1. Mouse buttons don't get appear with modifier keys and messed up the shown key names.
2. F10 does not appear.
3. Sometimes modifier keys are shown doubled like Shift + A + Shift

#singleinstance, Force

Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit w150
Gui, Show, h100 w200


OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

DetectKeyButtonPress(wParam) {
	Local PrevModifiers, ModifierKeys, VKCode, PressedKeyName
	Static PreviousKeys := Object()
	ModifierKeys := "Control,Shift,Alt,AppsKey,RWin,LWin"
	For Key, valule in PreviousKeys {
		if (A_Index >= 4)		;allowed max number of modifier keys
			Continue
		If GetKeyState(Key, "P")
			PrevModifiers .= Key " + "
		Else
			PreviousKeys.Remove(Key)
	}
	SetFormat IntegerFast, H
	VKCode := "VK" SubStr(wParam+0, 3)
	PressedKeyName := GetKeyName(VKCode)
	GuiControl,, MyEdit, % PrevModifiers . PressedKeyName
	
	if PressedKeyName in %ModifierKeys%
		PreviousKeys[PressedKeyName] := VKCode
}


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
F10 activates the window's menu, like pressing Alt. Add the following to detect F10, Alt and combinations of Alt with other keys:
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")
Btw, I suggest you remove , valule from the FOR loop, since you're not using the value.

  • Guests
  • Last active:
  • Joined: --
Thanks Lexikos.

OK, I improved and simplified a little bit. Still there are some issues yet. Is anybody able to fix it?

1. Mbutton don't get appear.
2. Mouse buttons mess up the retrieved results when pressed with modifier keys
4. Can't prevent built-in Windows Hokteys
5. and more.

Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit w150
Gui, Show, h100 w200


OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

DetectKeyButtonPress(wParam, lParam) {
	ModifierKeyList := "Control,Shift,Alt,RWin,LWin"
	NumPMods := 0
	PressedModifiers := ""
	Loop, Parse, ModifierKeyList, `, 
	{
		if NumPMods > 3
			break
		If GetKeyState(A_LoopField, "P") {		;if it is pressed
			PressedModifiers .= A_LoopField " + "
			NumPMods++
		}
	}
	SetFormat IntegerFast, H
	PressedKeyName := GetKeyName("VK" SubStr(wParam+0, 3))
	If PressedKeyName in %ModifierKeyList%
		GuiControl,, MyEdit, % PressedModifiers
	Else
		GuiControl,, MyEdit, % PressedModifiers . PressedKeyName
}


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
For the mouse messages, wParam is a set of flags, not a VK code. You can use the following to translate them:
Static MouseParamToVK := {1:1, 2:2, 0x10:4, 0x20:5, 0x40:6} ; L,R,M,X1,X2
   if msg >= 0x201 ; Mouse message.
      wParam := MouseParamToVK[wParam & ~12]
Bitwise-AND is used to filter out MK_CONTROL and MK_SHIFT. Notice that only LButton and RButton have the same values. (EDIT: You also need to add , lParam, msg to the parameter list of the message function.)

In theory, you need the following in order to support the fourth and fifth mouse buttons:
OnMessage(WM_XBUTTONDOWN := 0x20B, "DetectKeyButtonPress")
To prevent the default functions of keys/key-combinations such as F10, Alt+F4 and RButton just add:
return 1


  • Guests
  • Last active:
  • Joined: --
Great, thanks Lexikos. Now most of the issues are resolved.

Remaining & Found Issues:
1. Can't prevent built-in Windows Hokteys
2. A non-modifier key disappears from the edit box right after it is pressed if the modifier keys are still pressed.

For #1, defining hotkeys with ifwinactive ahk_id %guihwnd% may work, but for #2, I have no idea what to do.

Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit w150
Gui, Show, h100 w200

OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")
OnMessage(WM_XBUTTONDOWN := 0x20B, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

DetectKeyButtonPress(wParam, lParam, msg) {
	Static MouseParamToVK := {1:1, 2:2, 0x10:4, 0x20:5, 0x40:6} ; L,R,M,X1,X2
	if msg >= 0x201 ; Mouse message.
		wParam := MouseParamToVK[wParam & ~12] 
	ModifierKeyList := "Control,Shift,Alt,RWin,LWin"
	NumPMods := 0
	PressedModifiers := ""
	Loop, Parse, ModifierKeyList, `, 
	{
		if NumPMods > 3
			break
		If GetKeyState(A_LoopField, "P") {		;if it is pressed
			PressedModifiers .= A_LoopField " + "
			NumPMods++
		}
	}
	SetFormat IntegerFast, H
	PressedKeyName := GetKeyName("VK" SubStr(wParam+0, 3))
	If PressedKeyName in %ModifierKeyList%
		GuiControl,, MyEdit, % PressedModifiers
	Else
		GuiControl,, MyEdit, % PressedModifiers . PressedKeyName
		
	Return 1
}


  • Guests
  • Last active:
  • Joined: --
OK, the second issue has been resolved by evaluating with A_TickCount.

Remaining Issue:
1. Can't prevent built-in Windows Hotkeys such as #d, #l etc.

Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit w150
Gui, Show, h100 w200

OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")
OnMessage(WM_XBUTTONDOWN := 0x20B, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

DetectKeyButtonPress(wParam, lParam, msg) {
	Static LastInputTime, MouseParamToVK := {1:1, 2:2, 0x10:4, 0x20:5, 0x40:6} ; L,R,M,X1,X2
	if (A_TickCount < (LastInputTime + 1000))
		Return
	if msg >= 0x201 ; Mouse message.
		wParam := MouseParamToVK[wParam & ~12] 
	ModifierKeyList := "Control,Shift,Alt,RWin,LWin"
	NumPMods := 0
	PressedModifiers := ""
	Loop, Parse, ModifierKeyList, `, 
	{
		if NumPMods > 3
			break
		If GetKeyState(A_LoopField, "P") {		;if it is pressed
			PressedModifiers .= A_LoopField " + "
			NumPMods++
		}
	}
	SetFormat IntegerFast, H
	PressedKeyName := GetKeyName("VK" SubStr(wParam+0, 3))
	If PressedKeyName in %ModifierKeyList%
		GuiControl,, MyEdit, % PressedModifiers
	Else
	{
		GuiControl,, MyEdit, % PressedModifiers . PressedKeyName
		LastInputTime := A_TickCount
	}
	Return 1
}


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
#2 happens for mouse buttons because they don't interrupt key-repeat of the modifier keys. Filtering out key-repeat might be better than setting a timing limitation:
if (msg < 0x200 && lParam & 1<<30) ; Not a mouse message && key-repeat.
      return
Btw, you can filter out clicks outside the Edit box like so:
if A_GuiControl != MyEdit
      return

For #1, the following article at MSDN suggests using a keyboard hook, the same as what would be used by AutoHotkey if you were to override the standard Windows hotkeys. That probably means there isn't any better way.
Disabling Shortcut Keys in Games
You mentioned #l. I think it's best to leave it up to the user to disable its native function (or not), as they would normally need to do before using it as a hotkey.

  • Guests
  • Last active:
  • Joined: --
Thanks Lexikos for the further input.

You mentioned #l. I think it's best to leave it up to the user to disable its native function (or not), as they would normally need to do before using it as a hotkey.

I agree with the part to leave it to the user. But I think if the user presses the Windows Key in the Hotkey definition GUI (the one we have been working on in this thread), it means he/she wants to override the native Windows Key functionality. So I wouldn't worry about disabling the native Windows Key function only on the GUI window. The problem is that I don't know how. I'll remove RWin and LWin from the function and put a check box for it as the manual in the Hotkey control section suggests.

Just for now, I added some code to remove a value from the edit box if it consists of only modifier keys, meaning something like "Shift + Alt +" will be removed automatically.
#singleinstance, Force

Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Key
Gui, Add, Edit, ReadOnly vMyEdit w150 Hwndhwnd_MyEdit
Gui, Show, h100 w200

OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")
OnMessage(WM_XBUTTONDOWN := 0x20B, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

ClearModifierOnlyValue:
	ControlGetText, DisplayedKeys, , ahk_id %hwnd_MyEdit%	; ControlGet, DisplayedKeys, Line , 1,,  ahk_id %hwnd_MyEdit%,
	ModifierKeyList := "Control,Shift,Alt"	;,RWin,LWin are removed
	if (SubStr(Trim(DisplayedKeys, A_Space), 0) = "+") {
		Loop, Parse, ModifierKeyList, `, 
			If GetKeyState(A_LoopField, "P") 		;still holding down
				Return	
		GuiControl,, MyEdit,		;clear it
	}
Return
DetectKeyButtonPress(wParam, lParam, msg) {
	Static MouseParamToVK := {1:1, 2:2, 0x10:4, 0x20:5, 0x40:6} ; L,R,M,X1,X2
	if (msg < 0x200 && lParam & 1<<30) ; Not a mouse message && key-repeat.
		return
	if A_GuiControl != MyEdit
		return
	if msg >= 0x201 ; Mouse message.
		wParam := MouseParamToVK[wParam & ~12] 
	ModifierKeyList := "Control,Shift,Alt"	;,RWin,LWin are removed
	NumPMods := 0
	PressedModifiers := ""
	Loop, Parse, ModifierKeyList, `, 
	{
		if NumPMods > 3
			break
		If GetKeyState(A_LoopField, "P") {		;if it is pressed
			PressedModifiers .= A_LoopField " + "
			NumPMods++
		}
	}
	SetFormat IntegerFast, H
	PressedKeyName := GetKeyName("VK" SubStr(wParam+0, 3))
	If PressedKeyName in %ModifierKeyList%
		GuiControl,, MyEdit, % PressedModifiers
	Else
		GuiControl,, MyEdit, % PressedModifiers . PressedKeyName
	SetTimer, ClearModifierOnlyValue, -300
	Return 1	
}

There is a problem with the code. If the ClearModifierOnlyValue label is put inside the function DetectKeyButtonPress after the line Return 1, ControlGetText, DisplayedKeys, , ahk_id %hwnd_MyEdit% no longer retrieves the value. But it works outside the function. I wonder why.

Found Issue:
1. Sometimes the text value in the edit box gets highlighted.

To do:
1. Give up Windows Key auto-detection and put a Windows Key check box instead.
2. Make the edit box background white.

For To-do #2, I'm working on a method of using RegisterCallback() but it seems there is no example code for 64 bit. I posted a related question here. Also this thread suggests to change the GUI background color but I haven't tried it yet. Can anybody suggest a better way if there is?

  • Guests
  • Last active:
  • Joined: --
OK, improved it a little bit. I could make the edit box's background white with SetParent. It's getting really nice.

Remaining & Found Issue:
1. Sometimes the text value in the edit box gets highlighted.
2. The edit box appears with the default text highlighted.

To Do:
1. Insert "Win" into the edit box's text output if the check box is checked.

#singleinstance, Force

SizeEditBox := "w150 h20"
EditBoxDefaultText := "Press keys or mouse buttons."
Gui, Margin, 20, 20
Gui, Add, Text,, Pressed Keys:
Gui, Add, Text, ReadOnly w200 h40 x20 y45 Hwndhwnd_Container 
Gui, Add, Checkbox, x20 y76 , Windows Key

Gui, 2: +LastFound -Caption
hwnd_gui2 := WinExist()
Gui, 2: Margin, 0, 0
Gui, 2: Font, cGray
Gui, 2: Add, Edit, +ReadOnly vMyEdit Hwndhwnd_Keys %SizeEditBox%, %EditBoxDefaultText%
; Gui, 2: Font, cBlack	;doesn't work
Gui, 2:Color, White

Gui, 2:Show, %SizeEditBox% x0 y0,
Gui, Show, h110 w200
DllCall("SetParent", "uint", hwnd_gui2, "uint", hwnd_Container)

OnMessage(WM_KEYDOWN := 0x100, "DetectKeyButtonPress")
OnMessage(WM_LBUTTONDOWN := 0x201, "DetectKeyButtonPress")
OnMessage(WM_RBUTTONDOWN := 0x204, "DetectKeyButtonPress")
OnMessage(WM_MBUTTONDOWN := 0x207, "DetectKeyButtonPress")
OnMessage(WM_SYSKEYDOWN := 0x0104, "DetectKeyButtonPress")
OnMessage(WM_XBUTTONDOWN := 0x20B, "DetectKeyButtonPress")

Return
GuiClose:
ExitApp

ClearModifierOnlyValue:
	ControlGetText, DisplayedKeys,, ahk_id %hwnd_Keys%	; ControlGet, DisplayedKeys, Line , 1,,  ahk_id %hwnd_MyEdit%,
	ModifierKeyList := "Control,Shift,Alt"	;,RWin,LWin are removed
	if (SubStr(Trim(DisplayedKeys, A_Space), 0) = "+") {
		Loop, Parse, ModifierKeyList, `, 
			If GetKeyState(A_LoopField, "P") 		;still holding down
				Return	
		Gui, 2:Font, cGray	
		GuiControl, 2:Font, MyEdit		
		ControlSetText,, % EditBoxDefaultText, ahk_id %hwnd_Keys%,
	}
Return

DetectKeyButtonPress(wParam, lParam, msg) {
	Static MouseParamToVK := {1:1, 2:2, 0x10:4, 0x20:5, 0x40:6} ; L,R,M,X1,X2
	if (msg < 0x200 && lParam & 1<<30) ; Not a mouse message && key-repeat.
		return
	if A_GuiControl != MyEdit
		return
	if msg >= 0x201 ; Mouse message.
		wParam := MouseParamToVK[wParam & ~12] 
	ModifierKeyList := "Control,Shift,Alt"	;,RWin,LWin are removed
	DisabledKeyList := "RWin,LWin"
	NumPMods := 0
	PressedModifiers := ""
	Loop, Parse, ModifierKeyList, `, 
	{
		if NumPMods > 3
			break
		If GetKeyState(A_LoopField, "P") {		;if it is pressed
			PressedModifiers .= A_LoopField " + "
			NumPMods++
		}
	}
	SetFormat IntegerFast, H
	PressedKeyName := GetKeyName("VK" SubStr(wParam+0, 3))
	If PressedKeyName in %DisabledKeyList%
		Return
	Gui, 2:Font, cBlack
	GuiControl, 2:Font, MyEdit	
	If PressedKeyName in %ModifierKeyList%
		GuiControl,, MyEdit, % PressedModifiers
	Else
		GuiControl,, MyEdit, % PressedModifiers . PressedKeyName
	SetTimer, ClearModifierOnlyValue, -300
	Return 1	
}