Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

anyr

any recoil. Reads a mouse event node (read-only, no exclusive grab) and, on every LMB press, injects counter-movements through a uinput virtual device to cancel a recoil pattern. Patterns load from JSON at runtime, no rebuild to switch weapons.

Ships with 19 pre-converted weapon patterns in weapons/the-finals/.

anyr.mp4

If anyr is useful to you, consider starring the repo. This is a solo project and a star genuinely helps with visibility.

Why it isn't detected

AHK and most Windows recoil scripts call SendInput/mouse_event through the Windows API. Kernel anti-cheats (EAC, Vanguard, BE) sit in the driver stack and can see those calls coming from a process that isn't the game, which is what gets them flagged.

anyr works differently. It creates a uinput virtual device, which the kernel presents as a real hardware device node identical to a second physical mouse being plugged in. The anti-cheat sees mouse events arriving from what looks like legitimate hardware. anyr never touches the game process, never reads its memory, and opens your real mouse read-only with no exclusive grab.

Tested across multiple games with kernel-level anti-cheat without detection.

Requirements

  • Linux, kernel with uinput support (virtually all distros ship this). There's no Windows/macOS path: vmouse.c talks to /dev/uinput directly and main.c reads raw linux/input.h events, both Linux-only APIs.
  • gcc and make. cJSON is vendored in third_party/, no other system packages needed.
  • pthread (part of glibc on any modern distro, nothing extra to install).
  • Root, or equivalent permissions, at runtime: reading /dev/input/eventN and creating a device via /dev/uinput both need it. Either run with sudo, or set up a udev rule granting your user access to both nodes if you'd rather not run as root.
  • Python 3 only if you use src/calc_sensitivity.py, no dependencies beyond the standard library.

Setting your sensitivity

python3 src/calc_sensitivity.py

Prompts for your in-game sensitivity, computes SENSITIVITY_CPD from your game's yaw constant (defaults to The Finals, 0.001, edit YAW at the top of the script for a different game), and patches src/config.h directly. You can re-run this any time and make again to update.

Common yaw constants:

Game Yaw
The Finals 0.001
CS2 0.022
Valorant 0.07
Overwatch 2 0.0066

Build

make

Requires gcc and pthread. cJSON is vendored in third_party/, no system packages needed.

Run

sudo ./anyr                                              # scan for mice
sudo ./anyr /dev/input/eventN                             # keyboard auto-detected
sudo ./anyr /dev/input/eventN /dev/input/eventKBD [dir]    # explicit keyboard + patterns folder

By default anyr looks in weapons/ (see PATTERNS_DIR in src/config.h). If that folder contains subfolders, each one is treated as a game/mod and you get a numbered menu to pick one first:

Available games in weapons:
   1) the-finals
   2) some-other-game
Select a game (1-2, or q to quit):

Then, same as before, a numbered menu of that game's *.json patterns:

Available patterns in weapons/the-finals:
   1) 93r.json
   2) akm.json
   3) arn-220.json
   ...

If weapons/ has no subfolders, just .json files dropped straight in (handy while testing a new pattern), the game step is skipped entirely and you go straight to the weapon menu, same as the old flat layout.

A typo re-prompts, it won't kill the program. q or Ctrl+D exits.

Switching mid-session: press the switch key (default P) any time you're not holding LMB, and the weapon menu reopens (within whatever game folder you picked at startup, no need to re-pick the game) without restarting anyr or losing your virtual device. No-op while firing, release LMB first.

Important: if another process already holds EVIOCGRAB on the physical mouse, that device delivers events only to the grabber, so anyr sees nothing on it. Point anyr at that process's virtual output device instead. Run with no args to list all mouse-like nodes, physical and virtual.

Adding a new pattern

Use S4N-T0S/recoil-analyser to generate the JSON. It records a clip of a full magazine fired at a tagged wall, tracks the wall to recover the actual recoil path, and outputs a ready-to-use JSON in this schema. Works for any FPS. See its README for the recording protocol.

Drop the resulting file into weapons/<game>/, no build step needed. A bad or malformed file fails with a clear message and leaves whatever pattern was already loaded untouched.

The fields anyr reads from each JSON:

  • weapon: shown in the banner and menu
  • capture.fps
  • pattern[]: cumulative dx_deg/dy_deg per bullet, converted internally to per-step incremental deltas
  • rpm.intervals_frames[] + capture.fps: converted to per-step delay in microseconds

Configuration

All in src/config.h:

Macro Meaning
SENSITIVITY_CPD Mouse counts per degree, set via calc_sensitivity.py or by hand
INVERT_X / INVERT_Y Flip an axis if the counter moves the wrong direction
PATTERNS_DIR Default folder scanned for *.json (3rd CLI arg overrides)
SWITCH_KEY / SWITCH_KEY_NAME Key that reopens the pattern menu

How it works

  1. pattern_menu_choose() lists *.json in the target folder, blocks on stdin for a number.
  2. pattern_load() parses the JSON (via vendored cJSON), converts cumulative deltas to per-step deltas and frame intervals to microseconds, returns a heap-allocated pattern_t.
  3. On LMB press, a thread walks the steps with absolute-time scheduling (clock_nanosleep(..., TIMER_ABSTIME, ...) against one fixed anchor). Chaining relative usleep() calls would let each step's overhead bleed into the next step's sleep, and that drift compounds across a full magazine. One absolute anchor means it never accumulates.
  4. Each step emits REL_X = -round(dx_deg * CPD), REL_Y = -round(dy_deg * CPD), with a float accumulator carrying the rounding remainder to the next step.
  5. Stops on LMB release or when the pattern ends.
  6. The switch key reopens the menu, waits (bounded) for any in-flight replay thread to finish, then frees the old pattern and loads the new one. Refused outright while LMB is held.

License

MIT, see LICENSE. cJSON (third_party/) is separately MIT-licensed by Dave Gamble and contributors.

About

Linux recoil compensation script for FPS games using a virtual mouse via uinput, with per-weapon JSON patterns and a sensitivity calculator.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages