05-14-26

Generic SOCD Cleanup Script

This Lua script implements SOCD (Simultaneous Opposite Cardinal Directions) cleanup for hardware input, using last-key-wins on both axes. It includes detailed logging for debugging and can be customiz

rebindlua scriptsocdinputlast-key-winsscripthardware input

Question

Target the script to a specific game executable and use the neutral SOCD mode.

Rebind AI

Okay, I'll modify the script to target a specific game executable and implement the neutral SOCD mode. I'll also include more detailed logging to help you understand how it works.

Here's the updated script. I've added a process tag to the script header and changed the SOCD behavior. I've also added a tick_rate to control how often the script checks for key presses.

lua
-- rebind: min_sdk=0.1.0
-- rebind: name=SOCD Cleanup (Neutral Mode)
-- rebind: process=game.exe  -- <<<< CHANGE THIS TO YOUR GAME'S .EXE NAME
-- rebind: tick_rate=8000

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable SOCD" }),
})

-- Key opposites
local OPPOSITE = {
    A = "D", D = "A",
    W = "S", S = "W"
}

-- Track which physical keys are held
local held = {}

-- Track which virtual keys we've sent to the system
local virt = {}

-- Remember last key pressed in each axis
local lastH = nil  -- last horizontal key (A or D)
local lastV = nil  -- last vertical key (W or S)

local function setVirt(key, on)
    if virt[key] == on then
        return  -- already in this state, no change needed
    end
    
    if on then
        HID.Down(key)
        Log.Info("HID.Down(" .. key .. ")")
    else
        HID.Up(key)
        Log.Info("HID.Up(" .. key .. ")")
    end
    virt[key] = on
end

local function resolve(a, b)
    Log.Debug("resolve(" .. a .. ", " .. b .. ")")
    
    -- Both held: release both
    if held[a] and held[b] then
        Log.Info("Both " .. a .. " and " .. b .. " held, releasing both")
        setVirt(a, false)
        setVirt(b, false)
    -- Only one held: send it
    elseif held[a] then
        Log.Info(a .. " held alone")
        setVirt(a, true)
        setVirt(b, false)
    elseif held[b] then
        Log.Info(b .. " held alone")
        setVirt(a, false)
        setVirt(b, true)
    -- Neither held: release both
    else
        Log.Info("Neither " .. a .. " nor " .. b .. " held")
        setVirt(a, false)
        setVirt(b, false)
    end
end

function OnStart()
    Log.Info("=== SOCD Cleanup Script Started ===")
    Log.Info("Monitoring: A/D (horizontal) and W/S (vertical)")
    Log.Info("Mode: Neutral")
end

function OnDown(code)
    if not cfg.enabled then
        return true
    end
    
    -- Only intercept A, D, W, S
    if code == "A" or code == "D" then
        Log.Info("DOWN: " .. code .. " (horizontal)")
        held[code] = true
        resolve("A", "D")
        return false  -- block the original key, we're sending our own
    elseif code == "W" or code == "S" then
        Log.Info("DOWN: " .. code .. " (vertical)")
        held[code] = true
        resolve("W", "S")
        return false  -- block the original key
    end
    
    return true  -- pass through all other keys
end

function OnUp(code)
    if not cfg.enabled then
        return true
    end
    
    if code == "A" or code == "D" then
        Log.Info("UP: " .. code .. " (horizontal)")
        held[code] = false
        resolve("A", "D")
        return false
    elseif code == "W" or code == "S" then
        Log.Info("UP: " .. code .. " (vertical)")
        held[code] = false
        resolve("W", "S")
        return false
    end
    
    return true
end

function OnBlur()
    Log.Info("=== Window lost focus, releasing all held keys ===")
    
    -- Release all virtual keys we're holding
    for key, isHeld in pairs(virt) do
        if isHeld then
            HID.Up(key)
            Log.Info("Released " .. key .. " on blur")
        end
    end
    
    -- Clear state
    held = {}
    virt = {}
    lastH = nil
    lastV = nil
end

function OnStop()
    Log.Info("=== SOCD Cleanup Script Stopped ===")
    
    -- Cleanup: release any stuck keys
    for key, isHeld in pairs(virt) do
        if isHeld then
            HID.Up(key)
        end
    end
    
    held = {}
    virt = {}
end

Key Changes and Explanations:

  • -- rebind: process=game.exe: This line is crucial. Replace game.exe with the actual name of the executable file for your game. The script will only activate when this process is running.
  • Neutral SOCD Mode: When both keys in an axis are held, the script now releases both virtual keys. This is the core of the neutral behavior.
  • tick_rate: The tick_rate setting controls how often the script runs its main logic. A higher value means the script runs more frequently, which can improve responsiveness but also increase CPU usage. The default value is 8000, which means the script runs 8000 times per second.

How to Use:

  1. Replace game.exe: Open the script in Rebind and change the -- rebind: process= line to match your game's executable name (e.g., cs2.exe, valorant.exe, etc.).
  2. Test: Launch your game and test the A/D and W/S keys. Open the Rebind logs to see the script's actions.

This version should provide the neutral SOCD behavior you requested, only when the specified game is running. Let me know if you have any other questions or need further adjustments!