Metadata-Version: 2.5
Name: human-presence
Version: 0.2.0
Summary: Keep your computer awake with pointer motion that actually looks human.
Author-email: Benyamin <benyaminjmf@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Benyamin
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: automation,cross-platform,cursor,human-like,idle,keep-awake,linux,macos,mouse,presence,windows,x11
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Desktop Environment
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: pyobjc-framework-quartz>=9.0; sys_platform == 'darwin'
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=5.1; extra == 'dev'
Description-Content-Type: text/markdown

# human-presence

Keep your computer "in use" with pointer motion that actually looks human.

**macOS · Windows · Linux (X11)**

Inspired by [keep-presence](https://github.com/carrot69/keep-presence) by
carrot69 — https://github.com/carrot69/keep-presence

Most keep-awake tools jump the cursor one pixel and call it a day. That is a
teleport: no path, no acceleration, always the same direction. This one
generates real trajectories instead.

```bash
human-presence -g 25 90
```

```
--------------------------------------------------------------
human-presence   gap 25-90s   speed x1
  display 0: 1512x982 at (0,0)
  display 1: 1920x1080 at (1512,-459)
  Ctrl-C to stop.
--------------------------------------------------------------
10:54:52  micro    20px -> (1185,452)
10:55:33  hop      79px -> (1257,518)
10:55:33  scrolled 4 notches up
10:56:41  travel  612px -> (410,244)
```

## What makes the motion human

| Property | How it is modelled |
| --- | --- |
| Path shape | Cubic Bézier with a randomised bow. ~75% single arc, ~25% lazy S. Never a straight line. |
| Speed | Minimum-jerk profile — zero velocity at both ends, so it eases in and eases out. |
| Duration | Fitts's law, `MT = a + b·log2(D/W + 1)`, with per-move noise. 50 px ≈ 280 ms, 1200 px ≈ 730 ms. |
| Precision | Per-step tremor, plus overshoot and a corrective submovement on ~35% of long reaches. |
| Hesitation | Occasional mid-flight pause on long travels, like a person re-aiming. |
| Timing | Log-uniform gaps, so short pauses outnumber long ones. Sometimes a burst of 2–4 quick actions. |
| Target choice | ~45% micro-drift (2–25 px), ~35% short hop (60–350 px), ~20% long travel across the screen. |
| Scrolling | Bursts of 2–6 notches in one direction, each weaker than the last. |

## Supported systems

| System | Status | How it injects input | Extra install |
| --- | --- | --- | --- |
| macOS | supported | Quartz event tap | `pyobjc` (automatic) |
| Windows 10/11 | supported | `SendInput` | none — `ctypes` is built in |
| Linux on **Xorg** | supported | XTest | system X libraries |
| Linux on **Wayland** | not possible | — | — |

Every supported system is checked in CI on each push, and not only for
"does it import". One test injects a real pointer move and asserts the
operating system's own idle clock resets — the single behaviour the whole
tool depends on. If that ever stops being true on a platform, the build
fails.

**Wayland users, read this.** Ubuntu has shipped Wayland as the default desktop
since 22.04, and Wayland blocks programs from injecting input. That is a
security decision, not a missing feature, and no version of this tool can work
around it. To use human-presence on Ubuntu: log out, click the gear icon on the
login screen, choose **"Ubuntu on Xorg"**, and log back in. Run
`echo $XDG_SESSION_TYPE` to check — it should print `x11`. If you launch under
Wayland the tool tells you this and exits, rather than running forever with no
effect.

## Install

Requires Python 3.9+.

```bash
pip install human-presence
```

On Ubuntu, the X libraries are usually already present. If not:

```bash
sudo apt install libx11-6 libxtst6 libxss1 libxinerama1
```

From a checkout:

```bash
git clone https://github.com/agn-7/human-presence.git
cd human-presence
pip install -e '.[dev]'
```

### Permissions

**macOS** will not deliver synthetic pointer events until you allow it. Open
**System Settings → Privacy & Security → Accessibility** and enable whichever
app runs the command — Terminal, iTerm, or your IDE. Without permission the
events are silently dropped.

**Windows** and **Linux/Xorg** need no special permission.

On any system, use `--verify` to check it is working: if the idle clock does
not reset to `0.0s` after an action, the events are not landing.

## Usage

```bash
human-presence [-g MIN MAX] [--speed X] [--hours HH:MM-HH:MM] [--display N]
               [--margin PX] [--no-scroll] [--keys] [--yield-seconds S]
               [--dry-run] [--verify] [--seed N] [-q]
```

| Flag | Meaning |
| --- | --- |
| `-g`, `--gap MIN MAX` | Seconds of **real** inactivity before acting. A fresh random value in this range every time. Default `25 90`. |
| `--speed X` | Movement speed multiplier. `0.7` is slower and calmer. Default `1.0`. |
| `--hours HH:MM-HH:MM` | Only run inside this daily window. Overnight wrap works: `22:00-06:00`. |
| `--display N` | Pin to one display. Default: whichever screen holds the cursor. |
| `--margin PX` | Pixels to keep clear of every screen edge. Default `60`. |
| `--no-scroll` | Never scroll. |
| `--keys` | Also tap shift occasionally. Off by default. |
| `--yield-seconds S` | How long to stand down after you touch the mouse. Default `120`. |
| `--dry-run` | Print the plan, never touch the cursor. |
| `--verify` | Print the system idle clock before and after each action. |
| `--seed N` | Fix the RNG, for reproducible tests. |
| `-q`, `--quiet` | Only log actions. |

### Choosing a gap

Keep the maximum below your screen-sleep setting (System Settings → Lock Screen).

| Command | Behaviour |
| --- | --- |
| `-g 25 90` | Good default. |
| `-g 60 240` | Calmer. Use when screen sleep is 5 minutes or more. |
| `-g 10 30` | Busy. Only when something needs very frequent activity. |

### Preview before the real run

```bash
human-presence --dry-run -g 3 6
```

Nothing moves. You only see what it *would* do.

## How idle is detected

Each platform reads the same clock its own screensaver reads, so keyboard
activity counts as presence, not just the mouse. The tool stays quiet while you
are genuinely working, and only acts once you actually stop.

| System | Idle clock |
| --- | --- |
| macOS | `CGEventSourceSecondsSinceLastEventType` |
| Windows | `GetLastInputInfo` |
| Linux/Xorg | `XScreenSaverQueryInfo` |

Because that clock is also reset by the tool's own events, a gap is measured
from whichever came last: you, or it.

## Staying out of the way

- **You always win.** Touch the mouse and it stands down for `--yield-seconds`.
  It also aborts a move mid-flight if the cursor stops tracking the path.
- **Off the furniture.** Every point is clamped into a safe box, inset from all
  edges. On macOS that also means below the menu bar and clear of the hot
  corners that trigger Mission Control. On Windows and Linux the tool uses the
  work area the system reports, so the taskbar, dock and panel are already
  excluded wherever you keep them.
- **Multi-display aware** on all three systems, including stacked or offset
  monitor layouts and screens positioned left of the origin.

## Run it at login

### macOS

The repository ships a ready template at `packaging/com.agn7.human-presence.plist`.
Copy it to `~/Library/LaunchAgents/`, edit the paths and flags inside, then:

```bash
launchctl load ~/Library/LaunchAgents/com.agn7.human-presence.plist
launchctl list | grep human-presence          # confirm it is running
launchctl unload ~/Library/LaunchAgents/com.agn7.human-presence.plist   # stop
```

Logs go to `/tmp/human-presence.log` and `/tmp/human-presence.err.log`.
launchd does not expand `~`, so use absolute paths if you change them.

Grant Accessibility permission to `/usr/local/bin/python3` (or whichever
interpreter the plist points at), not to Terminal.

### Windows

Press `Win+R`, run `shell:startup`, and put a shortcut there pointing at:

```
pythonw -m human_presence --gap 25 90 --quiet
```

`pythonw` runs it without a console window.

### Linux (Xorg)

Add it to your desktop's Startup Applications, with the command:

```
human-presence --gap 25 90 --quiet
```

## Development

```bash
pip install -e '.[dev]'
pytest
ruff check .
```

Tests cover the movement model, the safe-area maths, the platform arithmetic
(absolute-coordinate mapping, tick-counter wrap, Wayland detection) and the
CLI. They all run on every operating system, because the movement model is
driven through an in-memory fake pointer rather than a real cursor.

The layout:

```
src/human_presence/
    cli.py              movement model + CLI — no OS calls at all
    backends/
        base.py         the Pointer interface, and the fake used by tests
        darwin.py       Quartz
        win32.py        SendInput via ctypes
        x11.py          XTest via ctypes
```

Adding a platform means writing one file in `backends/`. Nothing in `cli.py`
changes.

## Credits and prior art

This project was **inspired by [keep-presence](https://github.com/carrot69/keep-presence)**
by carrot69, released under CC0:

> https://github.com/carrot69/keep-presence

That project supplied the idea — a small program that keeps a machine looking
occupied while you are away — and the shape of the command-line interface.
Thanks to its author.

human-presence is an independent implementation rather than a fork. No code was
copied. The differences:

| | keep-presence | human-presence |
| --- | --- | --- |
| Movement | one-pixel teleport, 4 fixed directions | Bézier path, minimum-jerk speed, Fitts timing |
| Idle detection | compares cursor position between loops | system idle clock, so typing counts too |
| Randomness | the wait interval only | wait, distance, direction, duration, curvature |
| Platform library | `pynput` | direct system calls, no `pynput` |
| Platforms | macOS, Windows, Linux | macOS, Windows, Linux/Xorg |

## License

MIT. The full text is in the `LICENSE` file of the source distribution.
