7

I have a Windows 10 laptop with a keyboard designed by idiots. They tried to cram the arrow keys where they don't belong, with the result that the up arrow key is between the right shift key and the / key (US keyboard layout). This is one of the stupidest things the designers could have done, because it means that when I go to hit the right shift key (which is most of the time), I end up hitting up arrow instead. This is incredibly annoying.

I found a program called Sharp Keys which allows me to remap the keys such that the up arrow behaves as shift and the right shift behaves as up arrow. Now, at least I can type. However, I've now lost important functionality for the up arrow key. Up arrow (now labeled "shift" on my keyboard) doesn't repeat. So, I can't just hold the key down to move up. Instead, I have to hit the key repeatedly. How can I fix this, so my right shift key behaves like up arrow and my up arrow key behaves like right shift ?

EDIT

Following a suggestion from the comments, I installed AutoHotkey. I have the following script:

RShift::Up
Up::RShift

I have the same problem as earlier. But, since AHK is a scripting language, is it possible to use it to change the repeat behavior?

4
  • I know your frustration with some keyboards. Have you tried AHK? I heard about it a while back and now have an arsenal of AHK's that I used almost daily. If you check it out it's pretty awesome -- helps if you have any programming background ever so slightly. autohotkey.com Then if you want it to register your shortcut to be ready at each login you can do that with windows as a start up task. A list of keys: autohotkey.com/docs/KeyList.htm If this works out for you I can help you with the code. There is a learning curve.
    – ejbytes
    Commented Nov 24, 2016 at 0:20
  • Thanks for mentioning AutoHotkey. I tried it, and while it'll be useful for many purposes, it has exactly the same problem as I described above, unless there's a way to use AHK to force a change in the key repeaat behavior. Commented Nov 25, 2016 at 4:33
  • Can you describe repeat? Press and too many repeats? With AHK there are timings you can set, or even Press+Hold commands. Does this help? So up goes up, but if you hold up it continues up up up. Or something else?
    – ejbytes
    Commented Nov 25, 2016 at 6:27
  • I mean that when you press Up, the cursor moves up one line and stops, no matter how long you hold the key. In AHK I tried writing a loop on Up:: to keep checking whether the key was down and send another Up key. But, it made no difference. Commented Nov 25, 2016 at 7:46

3 Answers 3

2

I tried the hotkeys you listed... they worked fine for me and repeated automatically just fine when held down...

#Persistent
Return

#IfWinActive    ; Make replacement operate globally
RShift::Up
Up::RShift

You may be able to try a different SendMode...

RShift::SendInput {Up}
Up::SendInput {RShift}

or...

RShift::SendPlay {Up}
Up::SendPlay {RShift}

Do you have any other programs that are intercepting these or anything like that? Does the key repeat work normally when the script isn't running?

Setting up a custom loop might look something like this...

RShift::
    While GetKeyState("RShift", "P") {
        Send {Up}
        Sleep 50    ; Set delay to taste
    }
Return

EDIT

To address the need for other modifiers to work, a '*' may be used with the hotkey, although in the case of having two shift keys it may not work correctly by default. I've added a special case for the shift key detection but I don't know how that would work if you were to throw other modifiers into the mix... in that case you could look at adding the {blind} modifier to the Send statements to see if you could get it to work properly.

To address the 'race condition' another pre-repeat delay can also be added before the repeat loop along with an initial send statement (see below).

*Up::SendInput {blind}{RShift Down}
*Up Up::SendInput {blind}{RShift Up}

*RShift::
    Send % GetKeyState("LShift", "P") ? "+{Up}" : "{Up}"
    Sleep 250           ; Initial delay before repeat
    While GetKeyState("RShift", "P") {
        Send % GetKeyState("LShift", "P") ? "+{Up}" : "{Up}"
        Sleep 100    ; Repeat delay
    }
Return
4
  • The top block works great. The second and third block, hit and miss for my keyboard. While loop, with GetKeyState, works too. Nice job. A note to anyone using this. I used the while loop in this example and it works. The Windows, "Sticky Key" alerted me; but at intermittent times; so perhaps the comment "Set delay to taste" might help with that problem if it ever persists. The API (Applicaiton Programmer's Interface) here explains what the GetKeyState is and how it's used: autohotkey.com/docs/commands/GetKeyState.htm An upvote from me (y)
    – ejbytes
    Commented Nov 25, 2016 at 11:47
  • The loop mostly works for me. The others don't. This is a brand new machine, so I can't imagine why code that works for everyone else fails on my machine; there's absolutely nothing special here. Anyway, while the loop mostly works, I've still got two issues with it. First, there seems to be a bit of a race condition, whereby if I hit RShift repeatedly, I'll occasionally go up two lines instead of one for a hit. This is annoying, but not too bad. Commented Nov 25, 2016 at 19:31
  • The second issue, which is more significant, is that Shift+Up no longer works. By Adding a similar loop on +Rshift:: and adding Send {Shift down} and Send {Shift up} I can get the cursor to go up when pressing left shift + new_up, but it doesn't have the correct effect of selecting text. Commented Nov 25, 2016 at 19:34
  • I have edited the post in response to these comments and provided some further example code you could try and test or modify.
    – JJohnston2
    Commented Nov 26, 2016 at 20:54
2

The problem with all of the other answers is that repeated shift presses will be ignored because the previous hotkey subroutine is still being executed. By defualt, #MaxThreadsPerHotkey is 1, and #MaxThreads is 10.

Below are two possible solutions. Both works well for me.

Increase #MaxThreadsPerHotkey (and #MaxThreads)

SendMode Input
#MaxThreads 150
#MaxThreadsPerHotkey 150

; return the send command including any pressed modifier keys
getSendCommand() {
    sendCmd = {Up}
    sendCmd = % GetKeyState("LAlt", "P") ? "!" . sendCmd : sendCmd
    sendCmd = % GetKeyState("LCtrl", "P") ? "^" . sendCmd : sendCmd
    sendCmd = % GetKeyState("LShift", "P") ? "+" . sendCmd : sendCmd
    sendCmd = % GetKeyState("Win", "P") ? "#" . sendCmd : sendCmd
    return sendCmd
}

*$RShift::
    ; Immediately send an up key
    Send % getSendCommand()
    Sleep, 450

    While GetKeyState("RShift", "P") {  ; while key remains pressed
        Send % getSendCommand()  ; keep sending up keys
        Sleep, 30
    }
    Return

Immediately abort execution when shift key is released

SendMode Input

; return the send command including any pressed modifier keys
getSendCommand() {
    sendCmd = {Up}
    sendCmd = % GetKeyState("LAlt", "P") ? "!" . sendCmd : sendCmd
    sendCmd = % GetKeyState("LCtrl", "P") ? "^" . sendCmd : sendCmd
    sendCmd = % GetKeyState("LShift", "P") ? "+" . sendCmd : sendCmd
    sendCmd = % GetKeyState("Win", "P") ? "#" . sendCmd : sendCmd
    return sendCmd
}

*$RShift::
    ; Immediately send an up key
    Send % getSendCommand()

    ; Initial wait period (sleep time = 350 ms, execution time ~450 ms)
    Loop 35 {  ; Check keystate every 10 ms, abort execution as soon as shift is released
        Sleep, 10  ; 10 ms is the shortest possible sleep interval
        if not GetKeyState("RShift", "P") {
            return
        }
    }

    ; Start repeating if and while key is still pressed. Stop execution as soon as shift is released
    While GetKeyState("RShift", "P") {
        Send % getSendCommand()

        Loop 2 {
            if not GetKeyState("RShift", "P") {
                return
            }
            Sleep, 10
        }
    }
    Return
0

While JJohnston2's answer gave me part of the solution, I wound up asking several other places and doing a lot of experimentation myself. Here's what I eventually wound up with:

Up::RShift
*RShift::
    delay=400
    While GetKeyState("RShift", "P") {
        Send {Blind}{Up}
        Sleep %delay%    ; Set delay to taste
        delay=30
    }
    Return

This solves the problems of key repeat and allowing shift+up to work as expected. There are two outstanding issues that I haven't solved, but which are low enough in priority that I'm going to consider this question solved anyway:

  1. The race condition isn't solved. I tried to put the first iteration outside of the loop, as JJohnston2 did, but it had no observable effect for me.
  2. The root cause of all this trouble is that the system doesn't seem to repeat the shift, Ctrl, or Alt keys, even though the others repeat. So, AHK can't repeat what it never sees. Since everyone I've asked for help hasn't had this issue, there must be something funky with my setup, but I don't have the foggiest idea what that might be.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .