Use a reMarkable 2 as a pressure-sensitive drawing tablet on Windows and Linux — no drivers, no root modifications, no third-party services.
The tablet connects over SSH (USB or Wi-Fi). The pen's raw evdev events are streamed to the PC and injected as native pointer input, giving you full pressure sensitivity, tilt, hover detection, and eraser support in any compatible application. Optional multi-touch gestures (pinch / pan / rotate) inject as real touch contacts to apps that consume them.
- Tablet: reMarkable 2 (firmware tested: Wacom I2C Digitizer, version 1231)
- PC: Windows 10 1809 or later (Windows Ink pointer injection API)
- Connection: USB cable (SSH at
10.11.99.1) or Wi-Fi (same SSH, different IP) - Root password: Settings → Help → Copyrights and licenses → scroll to bottom
- Tablet: reMarkable 2 (same as above)
- PC: Any x86-64 Linux with kernel 4.5+ (uinput module)
- Connection: USB cable or Wi-Fi (same as Windows)
- Permissions: membership in the
inputgroup (one-time setup, see below)
Download RemtabletApp-*.zip from Releases, extract, run RemarkableTablet.App.exe.
The app lives in the system tray. Right-click → Connect... to open Settings, enter your device IP and root password, and click Connect.
The Settings dialog also exposes a Touch Gestures checkbox to enable pinch / pan / rotate from the rM2 touchscreen (see the Touch gestures section), and a Pressure dropdown to pick between Linear, Soft (boosts light strokes), and Hard (suppresses light strokes) response curves.
Download remtablet-*-win-x64.zip from Releases, extract, and run:
remtablet.exe --password <root-password>
Download remtablet-*-linux-x64.tar.gz from Releases, extract, and run:
# One-time: grant /dev/uinput access (log out and back in after)
sudo usermod -aG input $USER
# Run
./remtablet --password <root-password>If your display resolution is not 1920×1080, pass it explicitly:
./remtablet --password <root-password> --width 2560 --height 1440Press Ctrl-C to stop.
| Flag | Default | Description |
|---|---|---|
--password <pw> |
— | Root password (required unless --key is set) |
--key <path> |
— | Path to SSH private key file |
--address <ip> |
10.11.99.1 |
Device IP address |
--orientation <value> |
portrait |
portrait, landscape, portraitflipped, landscapeflipped |
--output <value> |
ink |
ink (full pressure+tilt) or mouse (cursor only, Windows only) |
--width <px> |
auto (Windows) / 1920 (Linux) | Screen width in pixels |
--height <px> |
auto (Windows) / 1080 (Linux) | Screen height in pixels |
--debug |
off | Print pipeline stage info on startup |
--gestures <value> |
off |
touch (inject multi-touch contacts for pinch / pan / rotate) or off. The rM2 firmware suppresses touch while the pen is in proximity, so two-finger gestures only register when the pen is set aside. |
--pressure <value> |
linear |
Pressure response curve. linear (1:1), soft (boosts light strokes — pen feels lighter), or hard (suppresses light strokes — pen feels stiffer). |
Hold the tablet with the pen slot at the bottom for portrait (default). Orientation controls how the tablet's native coordinate space maps to the screen:
| Value | Physical position |
|---|---|
portrait |
Pen slot at bottom (default drawing position) |
landscape |
Pen slot on right |
portraitflipped |
Pen slot at top |
landscapeflipped |
Pen slot on left |
Pass --gestures touch to enable pinch / pan / rotate gestures from the rM2's
capacitive touchscreen. The tool opens a second SSH stream against
/dev/input/event2 and injects multi-touch contacts to the host:
- Windows: synthetic touch contacts via
CreateSyntheticPointerDevice(PT_TOUCH)InjectSyntheticPointerInput. Apps that handle Windows touch (Krita, Photoshop, Affinity, browsers) run their own gesture recognition on the injected contacts.
- Linux: a second uinput device (
reMarkable 2 Touch) using the MT-B slot protocol withINPUT_PROP_DIRECT. Apps reading the input subsystem see real multi-touch contacts.
Important hardware behavior: the rM2 firmware suppresses touch reporting
while the pen is in proximity (verified via evtest). This means
simultaneous draw + pinch is not possible at the hardware level — the
workflow is "lift pen → pinch / pan / rotate → resume drawing." This is a
property of the device, not the tool.
- Krita — Settings → Configure Krita → Tablet → set input to Windows 8+ Pointer Input
- Photoshop 2018+ — works out of the box
- Affinity Photo / Designer — works out of the box
- Clip Studio Paint — works out of the box
- Paint Tool SAI v2 — requires "Tablet" input mode in preferences
Use Mouse mode only as a fallback for applications that don't support Windows Ink.
The virtual device appears as a standard pen tablet to any app that reads from the Linux input subsystem:
- Krita — works out of the box with pressure and tilt
- GIMP — enable extended input devices: Edit → Input Devices
- Inkscape — Input Devices dialog, set the virtual tablet to "Screen" mode
- MyPaint — works out of the box
- Blender — works with tablet pressure in sculpt and paint modes
The device uses INPUT_PROP_DIRECT so absolute coordinates map 1:1 to screen pixels. Pressure is reported on the 0–1024 scale.
Pinch / pan / rotate compatibility depends on whether the host application consumes Windows touch (or Linux multi-touch) gestures. Confirmed working where verified; rows marked "untested" are expected to work but haven't been hands-on validated.
| App | Pinch zoom | Pan | Rotate | Notes |
|---|---|---|---|---|
| Windows | ||||
| Krita | ✅ | ✅ | ✅ | Real touch + Windows Ink coexist cleanly. |
| Photoshop | untested | untested | untested | Expected to work — Photoshop has full Windows touch support. |
| Affinity Photo / Designer | untested | untested | untested | Expected to work. |
| Clip Studio Paint | untested | untested | untested | |
| Microsoft Edge / Chrome | untested | untested | n/a | Browser pinch-zoom of pages. |
| Windows Photos | untested | untested | n/a | Native Windows app — should work. |
| Linux | ||||
| Krita | untested | untested | untested | |
| GIMP | untested | untested | n/a | |
| Inkscape | untested | untested | n/a | |
| Blender | untested | untested | n/a |
If you confirm or find a failure, the table above is the place to record it.
The /dev/uinput device node requires write access. The cleanest approach is a udev rule (no sudo required after setup):
# Option A: add yourself to the input group (requires log out/in)
sudo usermod -aG input $USER
# Option B: udev rule for uinput specifically
echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' \
| sudo tee /etc/udev/rules.d/70-uinput.rules
sudo udevadm control --reload && sudo udevadm triggerThe GUI app (Windows) saves settings to:
%APPDATA%\remarkable-input-tablet\settings.json
Passwords are never stored. You will be prompted each session.
The pipeline reconnects automatically if the SSH stream drops (USB unplugged, device sleeps, Wi-Fi hiccup). Before each reconnect attempt a synthetic pen-up and an "all touch contacts released" event are injected so drawing applications don't get a stuck pen or stuck touch contacts. Retry delays follow exponential backoff: 1 s, 2 s, 4 s, 8 s, 16 s, 30 s (capped).
Requires .NET 10 SDK.
git clone <repo>
cd remarkable-input-tabletdotnet build
dotnet test# Build and test Linux-compatible projects.
# -f net10.0 skips the Windows TFM (CLI is multi-targeted).
dotnet build src/RemarkableTablet.Cli -f net10.0
dotnet test tests/RemarkableTablet.Core.Testsdotnet publish src/RemarkableTablet.Cli -c Release -r win-x64 -f net10.0-windows `
-p:PublishAot=true -p:InvariantGlobalization=true -o out/cli# Prerequisite: clang and zlib headers
sudo apt-get install -y clang zlib1g-dev # Debian/Ubuntu
dotnet publish src/RemarkableTablet.Cli -c Release -r linux-x64 -f net10.0 \
-p:PublishAot=true -p:InvariantGlobalization=true -o out/clidotnet publish src/RemarkableTablet.App -c Release -r win-x64 `
-p:SelfContained=true -p:PublishSingleFile=true -o out/appTrimming is intentionally not enabled: the tray icon uses
System.Windows.Forms.NotifyIcon, and WinForms is not trim-compatible (NETSDK1175). The CLI ships smaller because it uses NativeAOT instead.
reMarkable 2 Host PC
───────────────────────────── ─────────────────────────────────────────────
/dev/input/event1 (pen)
│
cat (SSH stdout) ──┐
│
/dev/input/event2 (touch, when --gestures touch)
│ │
cat (SSH stdout) ──┤
│
─── SSH (TCP) ────►┴► SshTransport ── one SshClient, one SshDeviceStream per evdev device
│
├──► EvdevParser → Channel<EvdevEvent> ──► TabletStateMachine
│ │ Channel<PenFrame>
│ CoordinateMapper
│ │ MappedFrame
│ IOutputMode
│ ├─ WindowsInkOutput (Windows Ink injection)
│ ├─ MouseOutput (cursor only, Windows)
│ └─ UinputOutput (Linux pen tablet)
│
└──► EvdevParser → Channel<EvdevEvent> ──► TouchStateMachine
│ Channel<TouchFrame>
TouchCoordinateMapper
│ MappedTouchFrame
ITouchOutput
├─ WindowsTouchInjectionOutput (synthetic touch, Windows)
└─ UinputTouchOutput (Linux MT-B touchscreen)
Projects:
| Project | Platform | Role |
|---|---|---|
RemarkableTablet.Core |
Any | Platform-agnostic pipeline: evdev parser, state machines (pen + touch), coordinate mappers, gesture engine, multi-stream SSH transport |
RemarkableTablet.Windows |
Windows | Win32 P/Invoke layer: Windows Ink pen injection, mouse output, synthetic touch injection (PT_TOUCH) |
RemarkableTablet.Linux |
Linux | uinput P/Invoke layer: virtual pen tablet + virtual MT-B multi-touch device |
RemarkableTablet.Cli |
Windows + Linux | remtablet — headless CLI, NativeAOT |
RemarkableTablet.App |
Windows | RemarkableTablet.App.exe — system tray GUI, WPF + WinForms |
tools/EventDiagnostics |
Windows | Live evdev event stream logger — streams events to console for debugging |
Confirmed via evtest on firmware version 1231 (Wacom I2C Digitizer).
Axis convention re-verified 2026-05-07 against the touchscreen — earlier docs
had ABS_X / ABS_Y rotated 180°.
| Axis | Range | Notes |
|---|---|---|
| ABS_X | 0 – 20966 | Long axis: 0 = top of device, max = USB/bottom (portrait) |
| ABS_Y | 0 – 15725 | Short axis: 0 = right, max = left (portrait) |
| Pressure | 0 – 4095 | 12-bit, mapped to 0–1024 via shaping curve (Windows Ink scale) |
| Distance | 0 – 255 | Hover height above surface |
| Tilt X/Y | −9000 – 9000 | Firmware units, mapped to ±90° |
Capacitive multi-touch panel, driver pt_mt. Confirmed via evtest 2026-05-07.
| Axis | Range | Notes |
|---|---|---|
| ABS_MT_POSITION_X | 0 – 1403 | Display-aligned, INPUT_PROP_DIRECT |
| ABS_MT_POSITION_Y | 0 – 1871 | Display-aligned, INPUT_PROP_DIRECT |
| ABS_MT_PRESSURE | 0 – 255 | Per-contact pressure |
| ABS_MT_SLOT | 0 – 31 | Hardware-reported; tool caps tracking at 5 |
| ABS_MT_TRACKING_ID | 0 – 65535 | Monotonically incrementing per-contact ID |
| Sample rate | ~85 Hz | Measured under continuous motion |
Pen-priority hardware behavior: the rM2 firmware suppresses the touchscreen entirely while the pen is in proximity. This is verified — the
PenToolGatewas originally planned as a host-side workaround but turned out to be unnecessary. Workflow: lift the pen, gesture, then resume drawing.
Note on tilt: tilt rotation matches the position transform that aligns with the touchscreen. The Windows Ink sign convention (positive tilt-X = pen leans toward +X screen axis) is not independently verified — if brush highlights point the wrong direction, the four cases in
CoordinateMapper.RotateTiltare the place to flip signs.
MIT