Snap Tap/Null Movement/Last Input Priority/Simultaneous Opposing Cardinal Directions (SOCD)

Is it possible to enable a feature like Razer’s keyboard , similar to The Null-Movement-Script? Wooting now has this feature too.

Please elaborate on this feature.

What does it do? What is the function of “The Null-Movement-Script”?

Sorry for the brevity of my original post. I learned about this feature through the YouTube video below:

He’ll do a much better job explaining, but essentially it’s a feature for gaming that allows for much more responsive “A-D strafing”

Here’s a description of the script

; Null Movement Script for AutoHotkey v2
; This script updates the A and D keys so that only one is held down at a time
; This avoids the situation where game engines treat holding both strafe keys as not moving
; Instead, holding both strafe keys will cause you to move in the direction of the last one that was pressed
; The same logic is applied to the W and S keys (only one can be held at a time)

and can he found here Null-Movement-Script/Null Movement.ahk at master · Qiasfah/Null-Movement-Script · GitHub

1 Like

Replied in post above ^

Thanks, this makes it clear. I like how easy they made it to configure the feature. I am confident the same behaviour can be scripted using macros on the UHK, but hey, that’s more work, and I guess noone has done it yet.

@mlac I really think the UHK should have a macro library (as you indicated, curated) where users can download macros for specific feature implementations and add them to their keyboard configuration.

There’s a fair bit of debate about whether this mechanical advantage is cheating or not. Software implementations of this are bankable in some games; when it is baked in to the hardware it is much harder to detect.

That is not an argument for or against implementation; just check for what is allowed in the game and let your ethics guide you.

1 Like

I suppose it does have potential for abuse, but for some of us with disabilities, it would be a HUGE help. I’m disabled and have a bit of neuropathy in my hands, so this would be rather nice.

I was just thinking about how annoying this movement cancellation effect is while gaming the other day…

You can demonstrate the same Null Movement Fix issue using the UHK’s mouse movement keys, so I imagine it should be possible with WASD as well? I know nothing about actually implementing this kind of stuff, so I might be totally wrong.

You can try it yourself by holding down a mouse movement key, and then tapping/releasing a different direction. Notice that no matter what, the last pressed direction is active, and if you release a key, it will reactivate any keys that are still being held. Very useful indeed.

Seeing this thread gave me a weird case of deja vu :laughing:
I brought up something similar with the UHK’s mouse keys a few years ago and it was fixed
(see here): https://github.com/UltimateHackingKeyboard/firmware/issues/256#issuecomment-570006439

1 Like

UHK
lol, we can chea- er, um… empower the disabled too. :innocent:

1 Like

@nacho Thanks for elaborating. This feature makes practical sense.

@pcooke9 The UHK mouse movement implementation is an excellent analogy.

@maexxx Can you implement this feature using smart macros? If not, I’m sure @kareltucek will help. As for the macro library, I’m formulating a well-suited system, but having a curated list of the most requested macros would help a lot.

A curated list of macros would indeed be great. As a starting point one could add those loose to the config section – maybe renaming to “My configuration and favorite macros” or something in that direction.

I tried, but I failed.

@kareltucek why is this not working, and what would I have to do to make it work? I mapped two macros snap-left and snap-right to the mod layer cursor left and right keys (US-QWERTY j and l):

snap-left:

holdKey left
ifKeyActive $keyId.l final pressKey right

snap-right:

holdKey right
ifKeyActive $keyId.j final pressKey left

When I hold down left then simultaneously press right it switches over to going right, but when I let go of right while keeping left still down, it does not revert back to going left.

I don’t see why this should help in any way. The pressKey just briefly activates the scancode, because the pressKey is local to the macro, so when the macro terminates, the scancode gets released. Also, this doesn’t deactivate the other key’s scancode in any way…

This problem seems a bit out of scope of smart macro capabilities to me, so I think this will need a core support.

I am unclear on the api of the thing. I mean like:

  • we need to let the user specify mutually-exclusive key pairs, don’t we? Or are we fine with hard-coded arrow clusters? Any ideas how?
  • can we think (on syntactic level) of some new smart macro construct that would make this possible?
1 Like

Ah, I see. So I guess you would need a constantly running macro which manages the press and release of both of these opposing keys. You’d need to control that macro from other macros bound to the actual keys, probably via some global variables.

Definitely better to implement some support for this in the core.

OK, this was a bit harder than I had expected, but it’s doable with smart macros. Thanks, @kareltucek for the hint that keys get released once a macro ends. So I had to move the key activation into a separate macro that gets forked and never stops running.

In my example, the left/right action is still bound to the J and L keys on the mod layer. Map these two keys to the snap-leftright macro. If you want them on other keys, you will need to change the $keyId.j and $keyId.l in the macros below.

In $onInit, add this:

setVar snap_running 0

snap-leftright:

if ( $snap_running == 0 ) {
    setVar snap_mode 0
    fork snap-leftright-worker
}
if ($thisKeyId == $keyId.j) {
    setVar snap_mode 1
}
else if ($thisKeyId == $keyId.l) {
    setVar snap_mode 2
}
delayUntilRelease
ifNotKeyActive $keyId.j ifNotKeyActive $keyId.l final setVar snap_mode 0
ifKeyActive $keyId.j final setVar snap_mode 1
ifKeyActive $keyId.l final setVar snap_mode 2

snap-leftright-worker:

setVar snap_running 1
setVar snap_state 0
// snap_state: current state of left/right movement
// snap_mode: target state of left/right movement
// The worker will send key press/release actions to move
// the current state to the target state.
loop:
if ($snap_state == 0) {
    if ($snap_mode == 1) {
        releaseKey right
        pressKey left
    }
    else if ($snap_mode == 2) {
        releaseKey left
        pressKey right
    }
}
else if ($snap_state == 1) {
    if ($snap_mode == 0) {
        releaseKey left
        releaseKey right
    }
    else if ($snap_mode == 2) {
        releaseKey left
        pressKey right
    }
}
else if ($snap_state == 2) {
    if ($snap_mode == 0) {
        releaseKey right
        releaseKey left
    }
    else if ($snap_mode == 1) {
        releaseKey right
        pressKey left
    }
}
setVar snap_state $snap_mode
goTo loop
// ifNotPlaytime 10000 goTo loop // use this for debugging
// setVar snap_running 0

I am sure it can be optimised somewhat, but hey, proof of concept!

4 Likes

WOW THANKS!!!
I never would’ve figured all that out :melting_face:

Since most First/Third-Person games use WASD instead of arrows for movement, I replaced the J/L ARROW keys with A/D (WASD Strafe).

It took me a while to figure out why I wasn’t moving at all… derp :crazy_face:
I finally realized that in the snap-leftright-worker macro, if the use case is for A/D strafing in games, the values following releaseKey and pressKey should be replaced with A/D. Just don’t get lost in the LEFT/RIGHT ordering, or you’ll never figure out what direction you’re heading :face_with_spiral_eyes:

I tested it in Risk of Rain 2, and it seems to work well so far. After a few minutes of getting used to it, I’m really happy with it.

Thanks again maexxx!

1 Like

Are there any potential dangers/downsides of having this macro continuously running?

I don’t think there are immediate downsides, but yes, that’s an area where some optimisation could be done. It could be changed to stop the worker when you release both keys, and restart it again when you press one of them.

@kareltucek How expensive is fork (vs. leaving the macro running)?

Are there any potential dangers/downsides of having this macro continuously running?

It eats cpu time. Possibly a lot of cpu time, depending on the macro, which can cause decreased responsivity.

If you mess up synchronization, you may end up running the macro multiple times - then you may run out of macro state slots (there’s just something like 16 or so of them), which can have ugly consequences.

If there are bugs in my code then it increases the chance they will exhibit and cause undefined behavior.

How expensive is fork (vs. leaving the macro running)?

Well, depends on why you care. As for cpu time / power consumption, calling fork from time to time is definitely cheaper. As for responsivity, it depends. Fork isn’t super expensive, but the macro state has to be zeroed, so there is some overhead.