smcombs

Shift Stuck Solved!

14 posts in this topic

#1 ·  Posted (edited)

Ok it seems I have been searching for this forever and finally have it. I was making a program similar to Console2 and while I was controlsend() my keys into the application the captial letters were staying capital after I would hold and press the shift key down. I could never get it to release until I manually pressed the left shift key. Even if I had pressed the right to begin with. So here is a DllCall that will release the shift key regardless. This is for people having problems with "{SHIFTUP}" not working or "{LSHIFT UP}" or any of the combinations. This DLLCALL will release the shift key. So here it tis:

$dll = DllOpen("user32.dll")
$vkvalue = 16
DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",0,"long",0) ;To press a key
DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;To release a key
DllClose($dll)

btw, here is a link to the source of this. It also has, all the keycodes in it for every key. I hope this works for you and enjoy.

Link to the vk codes

Edited by smcombs

Share this post


Link to post
Share on other sites



$dll = DllOpen("user32.dll")
$vkvalue = 16
DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",0,"long",0) ;To press a key
DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;To release a key
DllClose($dll)

I also experienced the same thing with the SHIFT / CTRL / ALT.

I've sent my problem HERE

Can you give examples of its use?

Thank you for your attention, 'cause I do not have the basic programming language. :)

Share this post


Link to post
Share on other sites

Yeah just use this code here. Go to that link first and find the key thats getting stuck for you. Find its value and replace my 16 for vkvalue with the key you have being stuck down.

Share this post


Link to post
Share on other sites

This thread certainly got me started in the right direction. While working with Timehorse's

Farmville bot and trying to adapt it to use on farmtown, I introduced a few new hotkey definitions

that used the ctrl key as a modifier. Heck, I was logging off and on to get windows acting right

before I realized it was a stuck left ctrl key causing all the problems. Anyway, using your

DllCall by itself didn't seem to fix it, perhaps it was because the user (me) may have been

bouncing around on the key, or holding it down too long. Anyway, i wrapped a bit of code

around the calls and it seems stable now. Here is some example code including my implementation

of an unstick_key function.

Any comments appreciated!

#cs
This is my function for handling stuck ctrl, alt, win, & shift keys from a farmtown
bot program I am working on (Thanks Timehorse and Jackalo for the farmville bot that I
started from). Anyone familier with that script will certainly recognize the logic
that I "borrowed" from Timehorse :)

in particular - I was running into big problems when I implemented a chat routine and
used ctrl+key hotkeys to access it. Frequently the ctrl key would get stuck. I found
that problem also existed for alt+key sequences... didn't really test the shift/win
sequences, but through those keys in too.
#ce

#include <Timers.au3>
#Include <Array.au3>

; Keyboard cleanup handler
Global $user32dll = DllOpen("user32.dll")           ; should be cleaned up at exit
Global $key_down_too_long = 1000                    ; if key held down over a second reset it

; Global Array for timer functions corresponding to keys defined below
Global $key_timer[8] = [0, 0, 0, 0, 0, 0, 0, 0]

; Keys of interest are hotkey modifiers for ctrl, alt, win, and shift
Global Const $keys[8] = [0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x5b, 0x5c]
;0xa0   LSHIFT
;0xa1   RSHIFT
;0xa2   LCTRL
;0xa3   RCTRL
;0xa4   LALT
;0xa5   RALT
;0x5b   LWIN
;0x5c   RWIN

Global $in_chat = False

; Hot Keys
Global $msg1_key1 = "^{UP}"
Global $msg2_key1 = "^{LEFT}"
Global $msg3_key1 = "^{RIGHT}"

Func unstick_keys($force_unstick=False)
    Local $i

    ;Format of DllCall to press/release a key
    ;DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",0,"long",0)         ;To press a key
    ;DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0)   ;To release a key

    If $force_unstick Then
        For $vkvalue in $keys
            DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;Release each key
        Next
    Else
        $i = 0
        For $vkvalue in $keys
            If _IsPressed($vkvalue) Then
                If $key_timer[$i] = 0 Then
                    $key_timer[$i] = _Timer_Init() ; initialize a timer to watch this key
                ElseIf  TimerDiff($key_timer[$i]) >= $key_down_too_long Then ; check elapsed time
                    DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ; release the key
                    $key_timer[$i] = 0 ; reset the timer
                EndIf
            EndIf
            $i = $i + 1
        Next
    EndIf
EndFunc

Func do_exit()      ; call for common exit point
    DllClose($user32dll)
    unstick_keys(True)
    Exit
EndFunc

; previously troublesome function here - can't use ControlSend because the
; input field is part of a flash game app
Func chat($text)
    $in_chat = True     ; want to keep from re-entering function before it is finished

    Local $mymsg = $text
    Local $sav_pos = MouseGetPos()  ; remember mouse position
    Local $i

    MouseClick("primary", $chatx, $chaty, 1, 4) ; click input area

    For $i = 1 to Mod($msgdotcount, 2) ; flash (or Farmtown) wants different message each time
        $mymsg = $mymsg & "."
    Next

    Send($mymsg, 1)
    Sleep(100)
    Send("{ENTER}", 0)
    MouseMove($sav_pos[0], $sav_pos[1], 1)  ; restore mouse

    $msgdotcount = $msgdotcount + 1
    unstick_keys()
    $in_chat = False
EndFunc

; put calls to unstick_keys at bottom of every hot-key handler function
; also place calls wherever you think they might be handy in your code

Func clear_hotkeys()
    If $msg1_key1 Then HotKeySet($msg1_key1)
    If $msg2_key1 Then HotKeySet($msg2_key1)
    If $msg3_key1 Then HotKeySet($msg3_key1)
EndFunc

Func activate_hotkeys()
    If $msg1_key1 Then HotKeySet($msg1_key1, "on_msg1_1")
    If $msg2_key1 Then HotKeySet($msg2_key1, "on_msg2_1")
    If $msg3_key1 Then HotKeySet($msg3_key1, "on_msg3_1")
EndFunc

Func on_msg1_1()
    If allow_chat() Then
        msg1_action()
    Else
        hotkey_passthrough($msg1_key1, "on_msg1_1")
    EndIf
EndFunc

; skipping msg2 and msg3
Func allow_chat()
    Return ( is_idle() Or is_paused() ) And Not is_click_only() And Not is_in_chat()
EndFunc

Func msg1_action()
    chat($msg1)
;   unstick_keys()          ; function moved to end of common chat function
EndFunc

; main program
    While 1
        ; do some stuff
        If something Then func_1()
        ElseIf something Then func_2()
        ElseIf something Then func_3()
        EndIf

        If something Then do_exit()

        sleep(50)
        unstick_keys()
    WEnd

    Func func_1()
        For ........

            For .....
                ;do stuff
                sleep(50)
                unstick_keys()
            Next
        Next
    EndFunc

    ; func2 and func3 similar to func1, has call in inner loop

Share this post


Link to post
Share on other sites

pheromonez, I could kiss you (in a strictly friendly way of course) :D

Your solution works like a charm.

I solved all my problems with stuck keys by just making a small UnstickKeys function which I put at the end of every function I call using hotkeys. Problem solved!

$dll = DllOpen("C:\Windows\System32\user32.dll")

Global Const $keys[8] = [0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x5b, 0x5c]
;0xa0   LSHIFT
;0xa1   RSHIFT
;0xa2   LCTRL
;0xa3   RCTRL
;0xa4   LALT
;0xa5   RALT
;0x5b   LWIN
;0x5c   RWIN

Func UnstickKeys()
    For $vkvalue in $keys
        DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;Release each key
    Next
EndFunc

Thank you so much!

This thread certainly got me started in the right direction. While working with Timehorse's

Farmville bot and trying to adapt it to use on farmtown, I introduced a few new hotkey definitions

that used the ctrl key as a modifier. Heck, I was logging off and on to get windows acting right

before I realized it was a stuck left ctrl key causing all the problems. Anyway, using your

DllCall by itself didn't seem to fix it, perhaps it was because the user (me) may have been

bouncing around on the key, or holding it down too long. Anyway, i wrapped a bit of code

around the calls and it seems stable now. Here is some example code including my implementation

of an unstick_key function.

Any comments appreciated!

#cs
This is my function for handling stuck ctrl, alt, win, & shift keys from a farmtown
bot program I am working on (Thanks Timehorse and Jackalo for the farmville bot that I
started from). Anyone familier with that script will certainly recognize the logic
that I "borrowed" from Timehorse :)

in particular - I was running into big problems when I implemented a chat routine and
used ctrl+key hotkeys to access it. Frequently the ctrl key would get stuck. I found
that problem also existed for alt+key sequences... didn't really test the shift/win
sequences, but through those keys in too.
#ce

#include <Timers.au3>
#Include <Array.au3>

; Keyboard cleanup handler
Global $user32dll = DllOpen("user32.dll")           ; should be cleaned up at exit
Global $key_down_too_long = 1000                    ; if key held down over a second reset it

; Global Array for timer functions corresponding to keys defined below
Global $key_timer[8] = [0, 0, 0, 0, 0, 0, 0, 0]

; Keys of interest are hotkey modifiers for ctrl, alt, win, and shift
Global Const $keys[8] = [0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x5b, 0x5c]
;0xa0   LSHIFT
;0xa1   RSHIFT
;0xa2   LCTRL
;0xa3   RCTRL
;0xa4   LALT
;0xa5   RALT
;0x5b   LWIN
;0x5c   RWIN

Global $in_chat = False

; Hot Keys
Global $msg1_key1 = "^{UP}"
Global $msg2_key1 = "^{LEFT}"
Global $msg3_key1 = "^{RIGHT}"

Func unstick_keys($force_unstick=False)
    Local $i

    ;Format of DllCall to press/release a key
    ;DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",0,"long",0)         ;To press a key
    ;DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0)   ;To release a key

    If $force_unstick Then
        For $vkvalue in $keys
            DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;Release each key
        Next
    Else
        $i = 0
        For $vkvalue in $keys
            If _IsPressed($vkvalue) Then
                If $key_timer[$i] = 0 Then
                    $key_timer[$i] = _Timer_Init() ; initialize a timer to watch this key
                ElseIf  TimerDiff($key_timer[$i]) >= $key_down_too_long Then ; check elapsed time
                    DllCall($user32dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ; release the key
                    $key_timer[$i] = 0 ; reset the timer
                EndIf
            EndIf
            $i = $i + 1
        Next
    EndIf
EndFunc

Func do_exit()      ; call for common exit point
    DllClose($user32dll)
    unstick_keys(True)
    Exit
EndFunc

; previously troublesome function here - can't use ControlSend because the
; input field is part of a flash game app
Func chat($text)
    $in_chat = True     ; want to keep from re-entering function before it is finished

    Local $mymsg = $text
    Local $sav_pos = MouseGetPos()  ; remember mouse position
    Local $i

    MouseClick("primary", $chatx, $chaty, 1, 4) ; click input area

    For $i = 1 to Mod($msgdotcount, 2) ; flash (or Farmtown) wants different message each time
        $mymsg = $mymsg & "."
    Next

    Send($mymsg, 1)
    Sleep(100)
    Send("{ENTER}", 0)
    MouseMove($sav_pos[0], $sav_pos[1], 1)  ; restore mouse

    $msgdotcount = $msgdotcount + 1
    unstick_keys()
    $in_chat = False
EndFunc

; put calls to unstick_keys at bottom of every hot-key handler function
; also place calls wherever you think they might be handy in your code

Func clear_hotkeys()
    If $msg1_key1 Then HotKeySet($msg1_key1)
    If $msg2_key1 Then HotKeySet($msg2_key1)
    If $msg3_key1 Then HotKeySet($msg3_key1)
EndFunc

Func activate_hotkeys()
    If $msg1_key1 Then HotKeySet($msg1_key1, "on_msg1_1")
    If $msg2_key1 Then HotKeySet($msg2_key1, "on_msg2_1")
    If $msg3_key1 Then HotKeySet($msg3_key1, "on_msg3_1")
EndFunc

Func on_msg1_1()
    If allow_chat() Then
        msg1_action()
    Else
        hotkey_passthrough($msg1_key1, "on_msg1_1")
    EndIf
EndFunc

; skipping msg2 and msg3
Func allow_chat()
    Return ( is_idle() Or is_paused() ) And Not is_click_only() And Not is_in_chat()
EndFunc

Func msg1_action()
    chat($msg1)
;   unstick_keys()          ; function moved to end of common chat function
EndFunc

; main program
    While 1
        ; do some stuff
        If something Then func_1()
        ElseIf something Then func_2()
        ElseIf something Then func_3()
        EndIf

        If something Then do_exit()

        sleep(50)
        unstick_keys()
    WEnd

    Func func_1()
        For ........

            For .....
                ;do stuff
                sleep(50)
                unstick_keys()
            Next
        Next
    EndFunc

    ; func2 and func3 similar to func1, has call in inner loop

Share this post


Link to post
Share on other sites

pheromonez, I could kiss you (in a strictly friendly way of course) :D

Your solution works like a charm.

I solved all my problems with stuck keys by just making a small UnstickKeys function which I put at the end of every function I call using hotkeys. Problem solved!

$dll = DllOpen("C:\Windows\System32\user32.dll")

Global Const $keys[8] = [0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x5b, 0x5c]
;0xa0   LSHIFT
;0xa1   RSHIFT
;0xa2   LCTRL
;0xa3   RCTRL
;0xa4   LALT
;0xa5   RALT
;0x5b   LWIN
;0x5c   RWIN

Func UnstickKeys()
    For $vkvalue in $keys
        DllCall($dll,"int","keybd_event","int",$vkvalue,"int",0,"long",2,"long",0) ;Release each key
    Next
EndFunc

Thank you so much!

So glad you could make use of it, and a kiss is definately not necessary :huggles:

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Woot! I'm going to try this. I've also been having serious issues with stuck keys. (Mainly alt, and control)

Edited by Terrafire

Share this post


Link to post
Share on other sites

Defining The Problem & A Better Solution On The Way

Good News! I have determined that inserting a "sleep()" command before the "send()" command will also reliably resolve the stuck-key problem. On slow computers, a "send(300)" was required, while on fast machines, a "send(100)" was enough. Most importantly, this experiment showed that the problem occurs BECAUSE the "send()" action starts before the hotkey detection function completes. When the "send()" action starts too soon, it seems to cause the detection function to silently error out and fail to finish it's normal cleanup after each use (speculation).

At the very least, this new information about the problem should give some developer (more intelligent than myself) a clue about where to look in the "hotkey()" and "send()" source code to see what's actually breaking. It should now be easy to find, and a REAL resolution can probably be made for the next release.

If anyone picks this up and runs with it, please post a reply stating that it's being worked on.

Share this post


Link to post
Share on other sites

Defining The Problem & A Better Solution On The Way

Good News! I have determined that inserting a "sleep()" command before the "send()" command will also reliably resolve the stuck-key problem. On slow computers, a "send(300)" was required, while on fast machines, a "send(100)" was enough. Most importantly, this experiment showed that the problem occurs BECAUSE the "send()" action starts before the hotkey detection function completes. When the "send()" action starts too soon, it seems to cause the detection function to silently error out and fail to finish it's normal cleanup after each use (speculation).

At the very least, this new information about the problem should give some developer (more intelligent than myself) a clue about where to look in the "hotkey()" and "send()" source code to see what's actually breaking. It should now be easy to find, and a REAL resolution can probably be made for the next release.

If anyone picks this up and runs with it, please post a reply stating that it's being worked on.

It is not considered to be a fault and the developers will not try to fix it. For some situations this might be helpful.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Hey, that seems to fix the problem that I was having! I wasn't even looking to fix that error and stumbled across this and tried it out. Thanks for the tip.


Gnatwork Networks

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Necro-posting is generally bad, but this thread is still prettily useful :)

Edited by fiz

Share this post


Link to post
Share on other sites

Necro-posting is generally bad, but this thread is still prettily useful :)

Thank you fiz for reviving this topic, if not for you I may not have found it at all.  I know it's probably too late to say, but I hope the response you got hasn't discouraged you from this site as well as this scripting language or other languages/applications offered freely and supported by dedicated users/developers only looking to help others and keep it going.  Though usually you find good, honest, and helpful people that aren't out to be harder to work with than the issue that brought you here in the first place, you do occasionally run into it.  I guess it's like they say, one bad apple can ruin the entire basket. 

 

Correct so don't !

You are quick to give a command Jos.  Maybe a solution to this problem reflected in AutoIT would be more productive than bashing someone's post when this issue exists in the current release even though it was originally reported 6 years ago and was brought up Again 3 years ago. You know, since you are a developer on here and all...

 

So if you're not breaking out the Source Code as we spoke Jos, I would suggest this be a sticky post near the top of the support forums, or maybe mention it in the help file, that you so love to reference in so many posts on here rather than provide a solution or assistance.  I (and various others I'm sure) have spent a lot of time trying to figure out why our scripts using this product were not working only to find a forum topic pointing out this issue and a work around years ago buried in the support forums for that product. 

 

Thank you pheromonez and smcombs for an excellent work around.  If only the attention to detail in your findings could have been reflected in the application itself.  Then we wouldn't have to necropost bug solutions almost as old as the Windows 7 operating system. 


Necroposting is generally bad, but reviving a topic with useful information to an existing issue when that post resolved your issue is not bad.  A developer who's only post on a topic is to bark orders at a poster for bumping a solution to a bug in the software that developer is here to support is worse.   

Do you feel like that is correct Jos?

Share this post


Link to post
Share on other sites

You are quick to give a command Jos.  Maybe a solution to this problem reflected in AutoIT would be more productive than bashing someone's post when this issue exists in the current release even though it was originally reported 6 years ago and was brought up Again 3 years ago. You know, since you are a developer on here and all...

 

So if you're not breaking out the Source Code as we spoke Jos, I would suggest this be a sticky post near the top of the support forums, or maybe mention it in the help file, that you so love to reference in so many posts on here rather than provide a solution or assistance.  I (and various others I'm sure) have spent a lot of time trying to figure out why our scripts using this product were not working only to find a forum topic pointing out this issue and a work around years ago buried in the support forums for that product. 

 

Thank you pheromonez and smcombs for an excellent work around.  If only the attention to detail in your findings could have been reflected in the application itself.  Then we wouldn't have to necropost bug solutions almost as old as the Windows 7 operating system. 


Necroposting is generally bad, but reviving a topic with useful information to an existing issue when that post resolved your issue is not bad.  A developer who's only post on a topic is to bark orders at a poster for bumping a solution to a bug in the software that developer is here to support is worse.   

Do you feel like that is correct Jos?

Command or comment? ;)

So you signed up and the first thing you thought you would do is give me/us a nice long lecture session and expect me to respond to that?

Well ...I conformed to your expectation and just did.

Cya,
Jos

-click-

 


Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.