Opened 11 months ago
Closed 11 months ago
#3990 closed Feature Request (Completed)
_IsPressed() add "indicate whether the key has been pressed since the last query"
Reported by: | argumentum | Owned by: | Jpm |
---|---|---|---|
Milestone: | 3.3.17.0 | Component: | AutoIt |
Version: | Severity: | None | |
Keywords: | GetAsyncKeyState, _IsPressed() | Cc: |
Description
Func _IsPressed($sHexKey, $vDLL = "user32.dll") Local $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", "0x" & $sHexKey) If @error Then Return SetError(@error, @extended, False) Return SetError(0, $aCall[0] = 0xFFFF8000, BitAND($aCall[0], 0x8000) <> 0) EndFunc ;==>_IsPressed
The change adds some extra information that I found was needed using a Bluetooth headset. The chatter about its use is at https://www.autoitscript.com/forum/topic/211304-getasynckeystate-_ispressed-vs-the-bluetooth-headset-now-fight/ .
Does not brake prior script code.
Attachments (0)
Change History (52)
comment:1 Changed 11 months ago by TicketCleanup
- Version Other deleted
comment:2 Changed 11 months ago by Jpm
Hi, I cannot test it but the code look strange
If the @extended is set and the return is always true
So why to set @extended is this case?
comment:3 Changed 11 months ago by Jpm
Hi,
Sorry unless I get an correction to my post above I will close it
comment:4 Changed 11 months ago by argumentum
In my case the @extended is needed. @extended is not always true. Is only true after some MSec. The first query returns false unless it was triggered again.
If you test it, you'll see that it does.
comment:5 Changed 11 months ago by argumentum <argumentum@…>
( adding this just to get an email upon update )
comment:6 Changed 11 months ago by Jpm
comment:7 Changed 11 months ago by argumentum <argumentum@…>
BitAND($aCall[0], 0x8000) <> 0
vs
$aCall[0] = 0xFFFF8000
On action(click/keypress) is 0xFFFF8001 or 0x00000000
The code returns if "BitAND($aCall[0], 0x8000) <> 0"
am adding if "$aCall[0] = 0xFFFF8000"
Unfortunately the only way to see somewhat what the effects are is to keep a key pressed until autorepeat kicks in on a keyboard to somewhat get the gist of it.
comment:8 Changed 11 months ago by Jpm
Are you sure that with this modification working for you we will not get regression as MSDn state
Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the preemptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon.
comment:9 Changed 11 months ago by argumentum <argumentum@…>
No one can tell what M$ is ever gonna do, but is by this feature that the code can tell that the key ( 0xB3 ) and those like it in multimedia ( 0xB0, 0xB1 ) are actively pressed via Bluetooth or not. If it's been there since Win95, I'll bet there's a lot of code depending on it and unlikely to change.
In bluethooth keys, a long press is not the same as a single click/press or a double one. Some even have triple press/click, all with different functionality, faking/masquerading having independent keys, and I believe is a driver thing, but is the M$ driver. There is no alternate driver.
--continue in next post--
comment:10 Changed 11 months ago by argumentum <argumentum@…>
... And the explanation of MSDN gives out is true, but also is true that PCs are way faster than when the warning was presented some 20 years ago when 32 bit was the future and 16 bit was nothing but gone. Actually, one can not run 16 bit code in windows nowadays, it is gone. But the base code is thankfully, backwards compatible.
comment:11 Changed 11 months ago by Jpm
Hi,
thanks for those highlights
Can you confirm that with the change you suggest no other equipment non BlueTooths will not have regression? it seems your post suggest it, I just want to be sure
Thanks for the clarification
Cheers
comment:12 Changed 11 months ago by argumentum <argumentum@…>
As far as I've tested with various hardware, it works as expected.
I don't foresee any problems. I know that it would generally be handled by:
While _IsPressed("B3") Sleep(50) WEnd
But the proposed @extended return, adds that extra GetAsyncKeyState info. that in these particular cases, just saves the day.
By the way, in my testing, this solution is even better than using _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL,...
comment:13 Changed 11 months ago by Jpm
Thank you
what do you propose for doc change for @extended?
comment:14 Changed 11 months ago by argumentum <argumentum@…>
Return Value
@extended is set by least significant bit. The value specifies whether the key was pressed since the last call. (See MSDN remarks)
See Also
Search "https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate#remarks" in MSDN Library.
Hopefully the above is sufficiently explicit.
comment:15 Changed 11 months ago by Jpm
Are you sure of 0xFFFF8000?
Th least significant bit is 0xFFFF8001
right?
comment:16 Changed 11 months ago by argumentum <argumentum@…>
..I'm did a copy and paste and my math skill ..are missing from my brain =/
Then better use this less specific explanation:
Return Value
@extended returns whether the key is still pressed since the last call. (See MSDN remarks)
comment:17 Changed 11 months ago by argumentum <argumentum@…>
...the above don't sit well with me. Is not so. I'll see it on Tuesday, I'll have a less foggy brain, then I'll have a look at it and discern it.
comment:18 Changed 11 months ago by argumentum <argumentum@…>
ok, I've got my head back. This would be the proper code:
Func _IsPressed($sHexKey, $vDLL = "user32.dll") Local $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", "0x" & $sHexKey) If @error Then Return SetError(@error, @extended, False) Return SetError(0, BitAND($aCall[0], 0x1), BitAND($aCall[0], 0x8000) <> 0) EndFunc ;==>_IsPressed
The @extended has the LSB. What is meant is that when the key is first pressed, the LSB is ON. On subsequent calls, the LSB is zero and the claim is to not trust the LSB (BitAND($aCall[0], 0x1)) due to the nature of multitasking, hence the BitAND($aCall[0], 0x8000) return.
So the original description is in fact correct. But is not clear to a non-english native speaker like myself, therefore a better description would be:
@extended returns the LSB of the keypress. (See MSDN remarks)
that way, if the reader wants to know what it really is, can read up on the subject.
comment:19 Changed 11 months ago by argumentum <argumentum@…>
..pardon. The description was correct, the code was wrong. (corrected above)
comment:20 Changed 11 months ago by Jpm
Hi,
I am still confused on how you use @extended with a BlueTooth headset
Can you post an example of how you you it?
For other device the @extended is always set
Thanks for the help
comment:21 Changed 11 months ago by argumentum <argumentum@…>
If _IsPressed("B3", $hDLL_user32) And @extended Then ;VlcSendCmd("{SPACE}") EndIf
The "keyboard" gets stuck in 0x8000. But do trigger the 0x8001 when pressed.
Same with prior and next keys. Volume up/down are not "seen" ( captured by the OS ).
My fight with the headset is at https://www.autoitscript.com/forum/topic/211304-getasynckeystate-_ispressed-vs-the-bluetooth-headset-now-fight/.
I scratched my head for a while until I realized what was going on.
And is a hard sell as far as getting enough people to accept this change given that is against MSDN recommendation ( 20 y/o ) and quite a niche occurrence. Yet, is the only thing that worked.
comment:22 Changed 11 months ago by argumentum <argumentum@…>
For other device the @extended is always set
With the new code, @extended is only triggered the 1st time as true(1) / BitAND($aCall[0], 0x1)
2nd time and on it returns false(0)
comment:23 Changed 11 months ago by Jpm
As I understand the return True with only the Most significant bit set is not enought for you (current implementation) you want to be sure it is the first time
so you don't want to check it is released as MSDN suggest (return false) and do some action
in the next beta version default is the same but now if you pass not a string a a VK_* value the return will wait the touch is release if you pass an array of $VK_* you will get a return if one of them has been clicked
comment:24 Changed 11 months ago by argumentum <argumentum@…>
would you paste here or send a PM/DM to me about this new beta code to take a look at ?
..looking at the beta code would give me a better understanding of what is that you are evaluating. A matching array of VK_ would ... hmmm, could return the "LSB += LSB" to satisfy my request.
comment:25 Changed 11 months ago by Jpm
; #FUNCTION# ==================================================================================================================== ; Author ........: ezzetabi and Jon ; Modified.......: Jpm ; =============================================================================================================================== Func _IsPressed($vKey, $vDLL = "user32.dll", $bCheckModifierKey = True) Local Static $hDLL = DllOpen("user32.dll") Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If IsString($vKey) Then Local $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", "0x" & $vKey) If @error Then Return SetError(@error, @extended, False) Return SetExtended(BitAND($aCall[0], 0x01), BitAND($aCall[0], $iKeyDown) <> 0) EndIf Local $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown) Then Do ; wait until is KeyUp Until Not BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown) Return $i + 1 ; $aKeys[$i] has been clicked EndIf Next EndFunc ;==>_IsPressed
comment:26 Changed 11 months ago by argumentum <argumentum@…>
Now that I've looked at it I understand. Looks good. Thanks.
In my, quite unexpected case, using the VK_* would have gotten me in a (infinite loop) frozen script.
comment:27 Changed 11 months ago by Jpm
Hi, in which case do you get an infinite loop?
comment:28 Changed 11 months ago by argumentum <argumentum@…>
I get an infinite loop with 0xB3 from the bluetooth at:
Do ; wait until is KeyUp Until Not BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown)
..given that in this case of the bluetooth input device (or driver), signals the LSB ( 0x8001 ) and gets stuck in 0x8000, never to get back to 0x0000 as it should. Is the whole reason for the need to know the LSB. Then again, fortunately, is not something that happens on a keyboard.
As I see it ( and tested ), the beta code is good.
comment:29 Changed 11 months ago by argumentum <argumentum@…>
Side note about the VK_* new addition in beta:
1) A user expects action right after pressing the keys, not after releasing them.
2) The $bCheckModifierKey should in my view, default to false.
Then again I have no idea why the new feature is incorporated nor the way it is. Nonetheless I wanted to bring it up. ( unless is outside the scope of this post and is to be discussed elsewhere and/or by MVPs )
comment:30 Changed 11 months ago by Jpm
I don't remember when the extension was introduced
I agree that they are more to handle clicked keys
The default as true is really to have a return on the the key only without the modifier pressed
I need to think if the function must work on pressed only just propose modification so that addition can work
comment:31 Changed 11 months ago by argumentum <argumentum@…>
The default as true is really to have a return on the the key only without the modifier pressed
Well, the array is the first claim. Say I make an array ( $aArray[2] = [0x12,0x58] ; alt - x ) that by default will not work as expected due to defaulting to exclude the alt key, otherwise the code would have to exclude the modifier key declared on the array. That complicates the code. It'd be easier to just default to false, to keep it as is.
Most people using this func are expecting a function key or a combination of modifier and letter, not just a letter.
The part that only returns after keys released, to make it on keypress, either, call the func again with "NOT func()" as it was done before the change, or have an extra parameter to call a func. for the in between state.
So removing the wait on release and defaulting $bCheckModifierKey to false would make the new beta functional.
Also,
Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL ; <<<<
would make more sense if the staic declaration is to be kept.
These changes will obviously change the expected functionality of whomever proposed the change but at least it would make the code widely functional other than just a for OP only.
Therefore, the "fixed" code ( with minimal modification, to just make it functional ) I propose would be:
Func _IsPressed($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If IsString($vKey) Then Local $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", "0x" & $vKey) If @error Then Return SetError(@error, @extended, False) Return SetExtended(BitAND($aCall[0], 0x01), BitAND($aCall[0], $iKeyDown) <> 0) EndIf Local $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown) Then ;~ Do ; wait until is KeyUp ;~ Until Not BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown) Return $i + 1 ; $aKeys[$i] has been clicked EndIf Next Return 0 ; added to be explicit EndFunc ;==>_IsPressed
comment:32 Changed 11 months ago by argumentum <argumentum@…>
..the above code is wrong, can't just remove the Do Until loop. I'll fix it in a moment
comment:33 Changed 11 months ago by argumentum <argumentum@…>
Func _IsPressed($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If IsString($vKey) Then Local $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", "0x" & $vKey) If @error Then Return SetError(@error, @extended, False) Return SetExtended(BitAND($aCall[0], 0x01), BitAND($aCall[0], $iKeyDown) <> 0) EndIf Local $iCounter = 0, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i])[0], $iKeyDown) Then $iCounter += 1 Next Return Int($iCounter = UBound($aKeys)) ; added to be explicit EndFunc ;==>_IsPressed
comment:34 Changed 11 months ago by argumentum
I should have waited but ..., anyway, this is better.
Func _IsPressed($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False If IsString($vKey) Then $vKey = "0x" & $vKey ; this is enough ; @extended returns last key pressed Local $iCounter = 0, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then $iCounter += 1 Next Return SetExtended(BitAND($aCall[0], 0x01), Int($iCounter = UBound($aKeys))) EndFunc ;==>_IsPressed
comment:35 Changed 11 months ago by argumentum
Forgot to declare $aCall
Func _IsPressed($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False If IsString($vKey) Then $vKey = "0x" & $vKey ; this is enough ; @extended returns last key pressed Local $aCall, $iCounter = 0, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then $iCounter += 1 Next Return SetExtended(BitAND($aCall[0], 0x01), Int($iCounter = UBound($aKeys))) EndFunc ;==>_IsPressed
comment:36 Changed 11 months ago by argumentum <argumentum@…>
the help examples to go with the beta:
#include <Misc.au3> #include <MsgBoxConstants.au3> Example() Func Example() Local $aArray[2] = [0x10, 0x12] ; Shift + Alt While 1 If _IsPressed($aArray) Then ConsoleWrite("_IsPressed - Shift & Alt Keys were pressed. (" & @MIN & ':' & @SEC & '.' & @MSEC & ')' & @CRLF) Do ; Wait until key is released. Sleep(50) Until Not _IsPressed($aArray) ConsoleWrite("_IsPressed - Shift & Alt Keys were released. (" & @MIN & ':' & @SEC & '.' & @MSEC & ')' & @CRLF) ElseIf _IsPressed(0x1B) Then MsgBox($MB_SYSTEMMODAL, "_IsPressed", "The Esc Key was pressed, therefore we will close the application.") ExitLoop EndIf Sleep(50) WEnd EndFunc ;==>Example
#include <Misc.au3> #include <MsgBoxConstants.au3> Example() Func Example() While 1 If _IsPressed(0x71, Default, True) Then ConsoleWrite("_IsPressed - F2 (without any modifier keys pressed) was pressed." & @CRLF) ; Wait until key is released. While _IsPressed("71", Default, True) Sleep(50) WEnd ConsoleWrite("_IsPressed - F2 (without any modifier keys pressed) was released." & @CRLF) ElseIf _IsPressed("1B") Then MsgBox($MB_SYSTEMMODAL, "_IsPressed", "The Esc Key was pressed, therefore we will close the application.") ExitLoop EndIf Sleep(50) WEnd EndFunc ;==>Example
comment:37 Changed 11 months ago by argumentum <argumentum@…>
hmm, I should not have use the magic number ( 0x71 ), but the VK_ constant.
comment:38 Changed 11 months ago by Jpm
Thanks but the intention with the array is to watch one of the key not both
can you adapt it and your proposal if needed
Cheers
here is the example i want to work with
#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> Local $sModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[3] = [$VK_ESCAPE, $VK_LBUTTON, $VK_TAB] While 1 Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; Keyboard ESC $sKey = "{ESCAPE}" ExitLoop Case 2 ; MouseClick Left $sKey = "{LBUTTON}" ExitLoop Case 3 ; Keyboard Tab $sKey = "{TAB}" ExitLoop EndSwitch Sleep(100) WEnd ConsoleWrite("The key " & $sKey & " has been stroked." & @CRLF) MsgBox($MB_SYSTEMMODAL, "Result", "The key " & $sKey & " has been stroked.", 2)
comment:39 Changed 11 months ago by argumentum <argumentum@…>
Ok, context. Then retuning TRUE or FALSE. How about retuning my desired data in the return as in
Int($iCounter = UBound($aKeys)) + BitAND($aCall[0], 0x01)
that way, is true either way but truer ( 2 ) if the LSB is present.
Then @extended is reserved for the modifier keys and the return will be true ( by means of 1 or 2 ). That would not brake anyone's existing code either.
I would then use:
If __IsPressed("B3") > 1 Then ....
Is that a good solution ?
comment:40 Changed 11 months ago by argumentum <argumentum@…>
..nope.
Read your original code for the beta and my solution made so sense. ( because it is none sense ). If the extended is the LSB while retuning TRUE then there is no odd result between the expectations.
Cheers
comment:41 Changed 11 months ago by argumentum <argumentum@…>
..then in your example, it'd need to change this line:
Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If Not $iRet And @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF)
comment:42 Changed 11 months ago by argumentum
..this is what I mean, by adding the not return to the example.
( I this was the way it would be coded )
#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> Local $sModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[3] = [$VK_ESCAPE, $VK_LBUTTON, $VK_TAB] While 1 Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If Not $iRet and @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; Keyboard ESC $sKey = "{ESCAPE}" ExitLoop Case 2 ; MouseClick Left $sKey = "{LBUTTON}" ExitLoop Case 3 ; Keyboard Tab $sKey = "{TAB}" ExitLoop EndSwitch Sleep(100) WEnd ConsoleWrite("The key " & $sKey & " has been stroked. (LSB: " & @extended & ")" & @CRLF) MsgBox($MB_SYSTEMMODAL, "Result", "The key " & $sKey & " has been stroked.", 2) Func _IsPressed_($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = DllOpen("user32.dll") If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False If IsString($vKey) Then $vKey = "0x" & $vKey Local $aCall, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Return SetExtended($i, False) Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then Return SetExtended(BitAND($aCall[0], 0x01), $i + 1) ; $aKeys[$i] has been clicked Next EndFunc ;==>_IsPressed
comment:43 Changed 11 months ago by Jpm
THanks
do you agree with my last proposal allowing to DllClose te default Dll and also to wait the modifier being unstroke to avoid multiple Modifier notification
#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> Local $sModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[3] = [$VK_ESCAPE, $VK_LBUTTON, $VK_TAB] While 1 Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If Not $iRet And @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; Keyboard ESC $sKey = "{ESCAPE}" ExitLoop Case 2 ; MouseClick Left $sKey = "{LBUTTON}" ExitLoop Case 3 ; Keyboard Tab $sKey = "{TAB}" ExitLoop EndSwitch Sleep(100) WEnd _IsPressed_() ; to DLLClose the the default Dll created by the previous _IsPressed_(...) ConsoleWrite("The key " & $sKey & " has been stroked. (LSB: " & @extended & ")" & @CRLF) MsgBox($MB_SYSTEMMODAL, "Result", "The key " & $sKey & " has been stroked.", 2) Send("^z") ; to avoid change in the Scite Window Func _IsPressed_($vKey = Default, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = Null If $vKey = Default Then ; to DLLClose the the default Dll created by the previous _IsPressed_(...) DllClose($hDLL) $hDLL = Null Return True EndIf If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL If $hDLL = Null Then $hDLL = DllOpen("user32.dll") Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False If IsString($vKey) Then $vKey = "0x" & $vKey Local $aCall, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then Do Sleep(250) Until BitAND(DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) = 0 Return SetExtended($i, False) EndIf Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($hDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then Return SetExtended(BitAND($aCall[0], 0x01), $i + 1) ; $aKeys[$i] has been clicked Next EndFunc ;==>_IsPressed_
comment:44 Changed 11 months ago by argumentum <argumentum@…>
in the "If $bCheckModifierKey Then"
Do Sleep(250) Until
locks a script. Any function should be as non-locking as possible.
At "Local Static $hDLL = Null", might as well load "user32.dll" as the next line will close it if called. And for what I see, I made the mistake of running everything out of $hDLL instead of $vDLL.
Ok, these are my notes:
#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> Local $sModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[3] = [$VK_ESCAPE, $VK_LBUTTON, $VK_TAB] While 1 Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If Not $iRet And @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; Keyboard ESC $sKey = "{ESCAPE}" ExitLoop Case 2 ; MouseClick Left $sKey = "{LBUTTON}" ExitLoop Case 3 ; Keyboard Tab $sKey = "{TAB}" ExitLoop EndSwitch Sleep(100) WEnd ; ..will self clean with OnAutoItExitRegister ;~ _IsPressed_() ; to DLLClose the the default Dll created by the previous _IsPressed_(...) ConsoleWrite("The key " & $sKey & " has been stroked. (LSB: " & @extended & ")" & @CRLF) MsgBox($MB_SYSTEMMODAL, "Result", "The key " & $sKey & " has been stroked.", 2) Send("^z") ; to avoid change in the Scite Window Func __IsPressed_Close() _IsPressed_() EndFunc Func _IsPressed_($vKey = Default, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = Null If $hDLL = Null Then $hDLL = DllOpen("user32.dll") OnAutoItExitRegister(_IsPressed_Close) EndIf If $vKey = Default Then ; to DLLClose the the default Dll created by the previous _IsPressed_(...) DllClose($hDLL) $hDLL = Null Return SetExtended(100, False) ; True should be False as to avoid furure mishaps. An imposible extended would suffice EndIf If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False ; unless bitwise, then 0 If IsString($vKey) Then $vKey = "0x" & $vKey Local $aCall, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then ;~ Do ; this should be removed as it'd lock the script until the codition changes, or maybe ;~ Sleep(250) ; make $bCheckModifierKey bitwise( 1 + 2 ) for a user purposely deciding to wait for the condition. ;~ Until BitAND(DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) = 0 Return SetExtended($i, False) EndIf Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then Return SetExtended(BitAND($aCall[0], 0x01), $i + 1) ; $aKeys[$i] has been clicked Next EndFunc ;==>_IsPressed_
comment:45 Changed 11 months ago by argumentum <argumentum@…>
.. am no used to not edit/change the post =(
"IsPressed_Close" is named wrong at "OnAutoItExitRegister(_IsPressed_Close)", should be "OnAutoItExitRegister(IsPressed_Close)".
comment:46 Changed 11 months ago by argumentum <argumentum@…>
... and "double underscore" is removed while in this text =/
comment:47 Changed 11 months ago by argumentum
Thinking..., Better not to use the Default in $vKey. Better to use an impossible parameter like "CleanUp" to do the clean up given the the clean up is now automated on exit by an internal function.
#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> Local $sModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[3] = [$VK_ESCAPE, $VK_LBUTTON, $VK_TAB] While 1 Local $iRet = _IsPressed_($aKeys, Default, True) ; Check no modifier If Not $iRet And @extended Then ConsoleWrite("The modifier key " & $sModifierKeys[@extended] & " has been stroked. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; Keyboard ESC $sKey = "{ESCAPE}" ExitLoop Case 2 ; MouseClick Left $sKey = "{LBUTTON}" ExitLoop Case 3 ; Keyboard Tab $sKey = "{TAB}" ExitLoop EndSwitch Sleep(100) WEnd ; ..will self clean with OnAutoItExitRegister ;~ _IsPressed_() ; to DLLClose the the default Dll created by the previous _IsPressed_(...) ConsoleWrite("The key " & $sKey & " has been stroked. (LSB: " & @extended & ")" & @CRLF) MsgBox($MB_SYSTEMMODAL, "Result", "The key " & $sKey & " has been stroked.", 2) Send("^z") ; to avoid change in the Scite Window Func __IsPressed_Close() _IsPressed_("CleanUp") EndFunc Func _IsPressed_($vKey, $vDLL = Default, $bCheckModifierKey = False) Local Static $hDLL = Null If $hDLL = Null Then $hDLL = DllOpen("user32.dll") OnAutoItExitRegister(__IsPressed_Close) EndIf If $vKey = "CleanUp" Then ; to DLLClose the the default Dll created by the previous _IsPressed_(...) DllClose($hDLL) $hDLL = Null Return SetExtended(100, False) ; True should be False as to avoid furure mishaps. An imposible extended would suffice EndIf If $vDLL = Default Or $vDLL = "user32.dll" Or $vDLL = "" Then $vDLL = $hDLL Local Static $iKeyDown = 0x8000 Local Static $aModifierKeys[6] = [0, $VK_SHIFT, $VK_CONTROL, $VK_MENU, $VK_LWIN, $VK_RWIN] If $bCheckModifierKey = Default Then $bCheckModifierKey = False ; unless bitwise, then 0 If IsString($vKey) Then $vKey = "0x" & $vKey Local $aCall, $aKeys[1] If IsArray($vKey) Then ; will check on on of them $aKeys = $vKey Else $aKeys[0] = $vKey EndIf If $bCheckModifierKey Then ; check no modifier keys For $i = 1 To 5 If BitAND(DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) Then ;~ Do ; this should be removed as it'd lock the script until the codition changes, or maybe ;~ Sleep(250) ; make $bCheckModifierKey bitwise( 1 + 2 ) for a user purposely deciding to wait for the condition. ;~ Until BitAND(DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aModifierKeys[$i])[0], $iKeyDown) = 0 Return SetExtended($i, False) EndIf Next EndIf For $i = 0 To UBound($aKeys) - 1 $aCall = DllCall($vDLL, "short", "GetAsyncKeyState", "int", $aKeys[$i]) If BitAND($aCall[0], $iKeyDown) Then Return SetExtended(BitAND($aCall[0], 0x01), $i + 1) ; $aKeys[$i] has been clicked Next EndFunc ;==>_IsPressed_
comment:48 Changed 11 months ago by Jpm
Hi I don't thing the OnAutoItExitRegister(IsPressed_Close)
is needed as the closing of AutoIt will release all resources attached to the process
For the "cleanup" the Null value is different from a valid vKey so why not to use it.
About the Sleep(250), I am not happy to not do it as Getting Same event again without any modification of the user interaction is bad
so I will leave it
comment:49 Changed 11 months ago by argumentum <argumentum@…>
About the Sleep(250), I am not happy to not do it
Then make it a bitwise. At least to have an option to not use it.
For the "cleanup" the Null value is different from a valid vKey so why not to use it.
Yes, that is an invalid call. Sounds good.
comment:50 Changed 11 months ago by argumentum <argumentum@…>
Yes, that is an invalid call. Sounds good.
Should have typed parameter. Is an invalid parameter =)
comment:51 Changed 11 months ago by Jpm
So I will stay with my proposal
comment:52 Changed 11 months ago by Jpm
- Milestone set to 3.3.17.0
- Owner set to Jpm
- Resolution set to Completed
- Status changed from new to closed
Added by revision [13032] in version: 3.3.17.0
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
Automatic ticket cleanup.