Jump to content

Shift Holding Problem


Recommended Posts

I'm working on a keyboard remapper and met a strange problem. All letter keys, both shifted and unshifted, are mapped to a function that begins with the following:

$ch = @HotKeyPressed
    $shift = False
    If StringLeft($ch, 1) = "+" Then
        $ch = StringRight($ch, 1)
        $shift = True
        While(_IsPressed("10"))
        WEnd
    EndIf

Here we determine if a shifted key is pressed, and if yes, we wait until it's up again. Without the While loop, Shift had a habit to stay pressed after a shifted letter. Executing send("{shiftdown}{shiftup}") didn't help. So I added the While loop as shown above. Now typing Hello results in Hello (and not HELLO), but typing USA gives ASU… My fingers are programmed to type all-caps words like USA by holding Shift, typing the letters and releasing Shift, but after adding the While loop it turns all-caps words backwards.

Let me tell you what happens later in the function, to give a good overview on the story. We determine what letter should the keypress result in. (It's a multi-layout remapper with an autocaps feature.) Then we turn all hotkeys off, send the letter out and turn the hotkeys on again. Turning off is necessary because pressing a letter key that gives the same letter causes an infinite loop. While the hotkeys are pressed, a Blockinput is given to get rid of undefined meanings of the keys to appear.

I believe something is happening with the keyboard buffer, but I never met such a behavior. Can anybody help?

Thank you in advance.

Láng Attila D., LAttilaD.org

Link to comment
Share on other sites

You can Hook the messages: Shift Down/Up (left/right shift key) and check capslock.

#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
OnAutoItExitRegister('OnAutoItExit')

Opt('MustDeclareVars', 1)
Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
Global $hmod = _WinAPI_GetModuleHandle(0)
Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
Global $active = False, $isShift = False, $isCapsLock = False

_Main()

Func _Main()
    Local $gui = GUICreate('Test', 400, 300)
    GUICtrlCreateInput('', 10, 30, 380)
    GUISetState()

    Do
        If BitAND(WinGetState($gui), 8) Then ; so the Hook takes only effect on this GUI
            $active = True
        Else
            $active = False
        EndIf
        If $isShift Then ConsoleWrite('SHIFT' & @CRLF)
        If $isCapsLock Then ConsoleWrite('CAPSLOCK' & @CRLF)
        If $isShift And $isCapsLock Then ConsoleWrite('SHIFT + CAPSLOCK = like NO SHIFT' & @CRLF)
    Until GUIGetMsg() = -3
EndFunc

Func _Exit()
    Exit
EndFunc

;===========================================================
; callback function
;===========================================================
Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode, $ret
    $ret = DllCall("user32.dll","long","GetKeyState","long", 0x14)
    If $ret[0] Then
        $isCapsLock = True
    Else
        $isCapsLock = False
    EndIf
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If $nCode < 0 Or Not $active Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
        If $vkCode = 0xA0 Or $vkCode = 0xA1 Then
            $isShift = True ; left or right Shift-Key down
        EndIf
    Else
        Switch DllStructGetData($tKEYHOOKS, "flags")
            Case 0x80, 0x81 ; 0x80= UP for 'normal' keys and left pairs,  0x81= UP for right pairs
                If $vkCode = 0xA0 Or $vkCode = 0xA1 Then $isShift = False ; LShift, RShift
        EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
EndFunc

Best Regards BugFix  

Link to comment
Share on other sites

You can Hook the messages: Shift Down/Up (left/right shift key) and check capslock.

Well, Bugfix, thank you for the help, but it seems not working yet. I've copied parts from my code into it and tried it. Here is the resulting code. Please start it, hold Shift and type a word, then release Shift. You'll get your word backwards.

Should I modify my code to get along with yours? If yes, how?

(Note that parts of my code are marked with "my parts" remarks. Only modifications in your code was commenting out MustDeclareVars, just to avoid the need to declare vars in my code, and adding an include for misc.au3, to make _IsPressed work.)

#include <misc.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
OnAutoItExitRegister('OnAutoItExit')

;Opt('MustDeclareVars', 1)
Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
Global $hmod = _WinAPI_GetModuleHandle(0)
Global $hHook = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
Global $active = False, $isShift = False, $isCapsLock = False

;my parts
Const $alphabet = "qwertyuiopasdfghjklzxcvbnm"
Dim $capsmode, $caps, $keyson, $layout, $langindex, $gui, $list, $okbutton, $languages, $buffer
keyson()
;end my parts

_Main()

Func _Main()
    Local $gui = GUICreate('Test', 400, 300)
    GUICtrlCreateInput('', 10, 30, 380)
    GUISetState()

    Do
        If BitAND(WinGetState($gui), 8) Then ; so the Hook takes only effect on this GUI
            $active = True
        Else
            $active = False
        EndIf
        If $isShift Then ConsoleWrite('SHIFT' & @CRLF)
        If $isCapsLock Then ConsoleWrite('CAPSLOCK' & @CRLF)
        If $isShift And $isCapsLock Then ConsoleWrite('SHIFT + CAPSLOCK = like NO SHIFT' & @CRLF)
    Until GUIGetMsg() = -3
EndFunc

Func _Exit()
    Exit
EndFunc

;===========================================================
; callback function
;===========================================================
Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode, $ret
    $ret = DllCall("user32.dll","long","GetKeyState","long", 0x14)
    If $ret[0] Then
        $isCapsLock = True
    Else
        $isCapsLock = False
    EndIf
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If $nCode < 0 Or Not $active Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    $vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
        If $vkCode = 0xA0 Or $vkCode = 0xA1 Then
            $isShift = True ; left or right Shift-Key down
        EndIf
    Else
        Switch DllStructGetData($tKEYHOOKS, "flags")
            Case 0x80, 0x81 ; 0x80= UP for 'normal' keys and left pairs,  0x81= UP for right pairs
                If $vkCode = 0xA0 Or $vkCode = 0xA1 Then $isShift = False ; LShift, RShift
        EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_KeyProc)
EndFunc

;----my parts
Func letter_hu()
    $ch = @HotKeyPressed
    $shift = False
    If StringLeft($ch, 1) = "+" Then
        $ch = StringRight($ch, 1)
        $shift = True
        While(_IsPressed("10"))
        WEnd
    EndIf

    If $shift And $ch = "`" Then
        $ch = "0"
    Else
        $i = StringInStr("`0-=\[];'" & $alphabet, $ch)
            $ch = StringMid("uöüóíoúéá" & $alphabet, $i, 1)
            $ch = StringMid("ûöüóíõúéá" & $alphabet, $i, 1)
    EndIf

    If ($capsmode = True And $caps = True) Or $shift = True Then
        $ch = StringUpper($ch)
    EndIf
    keysoff(False)
    Send($ch)
    $caps = False
    keyson()
EndFunc   ;==>letter_hu
Func keyson()

            HotKeySet("a", "letter_hu")
            HotKeySet("b", "letter_hu")
            HotKeySet("c", "letter_hu")
            HotKeySet("d", "letter_hu")
            HotKeySet("e", "letter_hu")
            HotKeySet("f", "letter_hu")
            HotKeySet("g", "letter_hu")
            HotKeySet("h", "letter_hu")
            HotKeySet("i", "letter_hu")
            HotKeySet("j", "letter_hu")
            HotKeySet("k", "letter_hu")
            HotKeySet("l", "letter_hu")
            HotKeySet("m", "letter_hu")
            HotKeySet("n", "letter_hu")
            HotKeySet("o", "letter_hu")
            HotKeySet("p", "letter_hu")
            HotKeySet("q", "letter_hu")
            HotKeySet("r", "letter_hu")
            HotKeySet("s", "letter_hu")
            HotKeySet("t", "letter_hu")
            HotKeySet("u", "letter_hu")
            HotKeySet("v", "letter_hu")
            HotKeySet("w", "letter_hu")
            HotKeySet("x", "letter_hu")
            HotKeySet("y", "letter_hu")
            HotKeySet("z", "letter_hu")
            HotKeySet("`", "letter_hu")
            HotKeySet("0", "letter_hu")
            HotKeySet("-", "letter_hu")
            HotKeySet("=", "letter_hu")
            HotKeySet("\", "letter_hu")
            HotKeySet("[", "letter_hu")
            HotKeySet("]", "letter_hu")
            HotKeySet(";", "letter_hu")
            HotKeySet("'", "letter_hu")
            HotKeySet("+a", "letter_hu")
            HotKeySet("+b", "letter_hu")
            HotKeySet("+c", "letter_hu")
            HotKeySet("+d", "letter_hu")
            HotKeySet("+e", "letter_hu")
            HotKeySet("+f", "letter_hu")
            HotKeySet("+g", "letter_hu")
            HotKeySet("+h", "letter_hu")
            HotKeySet("+i", "letter_hu")
            HotKeySet("+j", "letter_hu")
            HotKeySet("+k", "letter_hu")
            HotKeySet("+l", "letter_hu")
            HotKeySet("+m", "letter_hu")
            HotKeySet("+n", "letter_hu")
            HotKeySet("+o", "letter_hu")
            HotKeySet("+p", "letter_hu")
            HotKeySet("+q", "letter_hu")
            HotKeySet("+r", "letter_hu")
            HotKeySet("+s", "letter_hu")
            HotKeySet("+t", "letter_hu")
            HotKeySet("+u", "letter_hu")
            HotKeySet("+v", "letter_hu")
            HotKeySet("+w", "letter_hu")
            HotKeySet("+x", "letter_hu")
            HotKeySet("+y", "letter_hu")
            HotKeySet("+z", "letter_hu")
            HotKeySet("+`", "letter_hu")
            HotKeySet("+0", "letter_hu")
            HotKeySet("+-", "letter_hu")
            HotKeySet("+=", "letter_hu")
            HotKeySet("+\", "letter_hu")
            HotKeySet("+[", "letter_hu")
            HotKeySet("+]", "letter_hu")
            HotKeySet("+;", "letter_hu")
            HotKeySet("+'", "letter_hu")

    BlockInput(0)
EndFunc   ;==>keyson
Func keysoff($quick = True)
    BlockInput(1)
            HotKeySet("a")
            HotKeySet("b")
            HotKeySet("c")
            HotKeySet("d")
            HotKeySet("e")
            HotKeySet("f")
            HotKeySet("g")
            HotKeySet("h")
            HotKeySet("i")
            HotKeySet("j")
            HotKeySet("k")
            HotKeySet("l")
            HotKeySet("m")
            HotKeySet("n")
            HotKeySet("o")
            HotKeySet("p")
            HotKeySet("q")
            HotKeySet("r")
            HotKeySet("s")
            HotKeySet("t")
            HotKeySet("u")
            HotKeySet("v")
            HotKeySet("w")
            HotKeySet("x")
            HotKeySet("y")
            HotKeySet("z")
            HotKeySet("`")
            HotKeySet("0")
            HotKeySet("-")
            HotKeySet("=")
            HotKeySet("\")
            HotKeySet("[")
            HotKeySet("]")
            HotKeySet(";")
            HotKeySet("'")
            HotKeySet("+a")
            HotKeySet("+b")
            HotKeySet("+c")
            HotKeySet("+d")
            HotKeySet("+e")
            HotKeySet("+f")
            HotKeySet("+g")
            HotKeySet("+h")
            HotKeySet("+i")
            HotKeySet("+j")
            HotKeySet("+k")
            HotKeySet("+l")
            HotKeySet("+m")
            HotKeySet("+n")
            HotKeySet("+o")
            HotKeySet("+p")
            HotKeySet("+q")
            HotKeySet("+r")
            HotKeySet("+s")
            HotKeySet("+t")
            HotKeySet("+u")
            HotKeySet("+v")
            HotKeySet("+w")
            HotKeySet("+x")
            HotKeySet("+y")
            HotKeySet("+z")
            HotKeySet("+`")
            HotKeySet("+0")
            HotKeySet("+-")
            HotKeySet("+=")
            HotKeySet("+\")
            HotKeySet("+[")
            HotKeySet("+]")
            HotKeySet("+;")
            HotKeySet("+'")
            HotKeySet(".")
            HotKeySet("+1")
            HotKeySet("+/")
            HotKeySet("+`")
            HotKeySet("1")
            HotKeySet("2")
            HotKeySet("3")
            HotKeySet("4")
            HotKeySet("5")
            HotKeySet("6")
            HotKeySet("7")
            HotKeySet("8")
            HotKeySet("9")
            HotKeySet("+3")
            HotKeySet("+4")
            HotKeySet("+5")
            HotKeySet("+6")
            HotKeySet("+7")
            HotKeySet("+8")
            HotKeySet("+9")
            HotKeySet(",")
            HotKeySet("/")
            HotKeySet("+,")
            HotKeySet("+.")
            HotKeySet("#[")
            HotKeySet("#,")
            HotKeySet("#.")
            HotKeySet("#/")
            HotKeySet("#;")
            HotKeySet("#'")
EndFunc   ;==>keysoff

Láng Attila D., LAttilaD.org

Link to comment
Share on other sites

Ah, I've missunderstand your problem. Now it's clear.

In this case you don't need a hook. your solution works. But if you use _IsPressed in an loop, new chars will added at front. So you get an reverse string.

I've changed that and meked it also shorter.

#include <misc.au3>

;my parts
Const $alphabet = "qwertyuiopasdfghjklzxcvbnm"
Dim $capsmode, $caps, $keyson, $layout, $langindex, $gui, $list, $okbutton, $languages, $buffer
keyson()
;end my parts

_Main()

Func _Main()
    Local $gui = GUICreate('Test', 400, 300)
    GUICtrlCreateInput('', 10, 30, 380)
    GUISetState()

    Do
    Until GUIGetMsg() = -3
EndFunc


;----my parts
Func letter_hu()
    $ch = @HotKeyPressed
    $shift = False
    If StringLeft($ch, 1) = "+" Then
        $ch = StringRight($ch, 1)
;~         $shift = True
;~         While(_IsPressed("10"))   <== this loop buffers the shifted string revers
;~         WEnd
;####################################
        If _IsPressed("10") Then
            $shift = True
        Else
            $shift = False
        EndIf
;####################################
    EndIf

    If $shift And $ch = "`" Then
        $ch = "0"
    Else
        $i = StringInStr("`0-=\[];'" & $alphabet, $ch)
            $ch = StringMid("uöüóíoúéá" & $alphabet, $i, 1)
            $ch = StringMid("ûöüóíõúéá" & $alphabet, $i, 1)
    EndIf

    If ($capsmode = True And $caps = True) Or $shift = True Then
        $ch = StringUpper($ch)
    EndIf
    keysoff(False)
    Send($ch)
    $caps = False
    keyson()
EndFunc   ;==>letter_hu

Func keyson()
    For $i = 45 To 122
        If $i = 58 Or $i = 60 Then ContinueLoop
        If $i = 62 Then $i = 91
        If $i = 94 Or $i = 95 Then ContinueLoop
        HotKeySet(Chr($i), "letter_hu")
        HotKeySet('+' & Chr($i), "letter_hu")
    Next
    BlockInput(0)
EndFunc   ;==>keyson

Func keysoff($quick = True)
    BlockInput(1)
    For $i = 45 To 122
        If $i = 58 Or $i = 60 Then ContinueLoop
        If $i = 62 Then $i = 91
        If $i = 94 Or $i = 95 Then ContinueLoop
        HotKeySet(Chr($i))
        HotKeySet('+' & Chr($i))
    Next
EndFunc   ;==>keysoff

Best Regards BugFix  

Link to comment
Share on other sites

Do I see it well the only difference is this part?

;~         While(_IsPressed("10"))   <== this loop buffers the shifted string revers
;~         WEnd
;####################################
        If _IsPressed("10") Then
            $shift = True
        Else
            $shift = False
        EndIf

Now, I'm sorry, but the original problem is restored. All-caps strings don't reverse this way, but Shift tends to glue again. Type SaSaSaSaSaSaSa, carefully raising Shift before the a's, and sometimes you will get uppercase A's.

(Edit: missed Autoit tags for first.)

Edited by LAttilaD

Láng Attila D., LAttilaD.org

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...