mcp-remotetouch 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  An MCP server for remotely controlling a touchscreen on any Linux device over SSH.
4
4
 
5
- Creates a virtual touch device via Linux `uinput` and injects tap, swipe, long press, and double tap events. **No installation required on the remote device** — the Python daemon is base64-encoded and sent as an SSH command argument, using only Python's standard library.
5
+ Injects tap, swipe, long press, double tap, and keyboard events directly into the device. The daemon auto-detects the touchscreen and screen resolution. Keyboard input is injected via a virtual keyboard device created through `/dev/uinput`. **No installation required on the remote device** — the Python daemon is sent via stdin over SSH, using only Python's standard library.
6
6
 
7
7
  ## Architecture
8
8
 
@@ -14,14 +14,19 @@ Dev Machine Remote Linux Device
14
14
  │ MCP Server (TS) │ ──────────────────> │ Python daemon │
15
15
  │ stdio transport │ JSON-line proto │ (stdlib only) │
16
16
  │ │ <────────────────── │ │
17
- │ touch_tap │ │ /dev/uinput
18
- │ touch_swipe │ │
19
- │ touch_long_press │ │ Virtual touch
20
- │ touch_double_tap │ │
21
- touch_disconnect │ │ Linux Input
17
+ │ touch_tap │ │ Auto-detect
18
+ │ touch_swipe │ │ touchscreen
19
+ │ touch_long_press │ │
20
+ │ touch_double_tap │ │ /dev/input/eventN
21
+ key_press │ │
22
+ │ key_type │ │ /dev/uinput (kbd)│
23
+ │ touch_disconnect │ │ ↓ │
24
+ │ │ │ Linux Input │
22
25
  └──────────────────┘ └──────────────────┘
23
26
  ```
24
27
 
28
+ The daemon scans `/proc/bus/input/devices` to find the physical touchscreen (by checking `INPUT_PROP_DIRECT` and `ABS_MT_POSITION_X`), then injects events directly into it. This works reliably with containerized compositors (e.g., Torizon with Qt EGLFS) where virtual uinput devices may not be detected.
29
+
25
30
  ### HTTP server mode (`--server`)
26
31
 
27
32
  ```
@@ -45,7 +50,8 @@ AI Agent (remote) ──HTTP/SSE──> Express + StreamableHTTPServerTransport
45
50
 
46
51
  - Any Linux device with a touchscreen (Raspberry Pi, SBC, embedded system, etc.)
47
52
  - Python 3
48
- - Access to `/dev/uinput`
53
+ - Read/write access to `/dev/input/eventN` (the touchscreen device)
54
+ - Write access to `/dev/uinput` (for keyboard input — optional, touch works without it)
49
55
 
50
56
  Add the user to the `input` group on the remote device:
51
57
 
@@ -53,48 +59,48 @@ Add the user to the `input` group on the remote device:
53
59
  sudo usermod -aG input $USER
54
60
  ```
55
61
 
56
- Re-login for the change to take effect.
62
+ Re-login for the change to take effect. Alternatively, use the `useSudo` option.
57
63
 
58
64
  ## Installation
59
65
 
60
66
  ```bash
61
- git clone https://github.com/signal-slot/mcp-remotetouch.git
62
- cd mcp-remotetouch
63
- npm install
64
- npm run build
67
+ npm install -g mcp-remotetouch
68
+ ```
69
+
70
+ Or run directly with `npx`:
71
+
72
+ ```bash
73
+ npx mcp-remotetouch
65
74
  ```
66
75
 
67
- ## Registering as an MCP Server
76
+ ## Usage
68
77
 
69
- Add to Claude Desktop's `claude_desktop_config.json`:
78
+ Add to your MCP client configuration (e.g. Claude Desktop's `claude_desktop_config.json`):
70
79
 
71
80
  ```json
72
81
  {
73
82
  "mcpServers": {
74
83
  "remotetouch": {
75
- "command": "node",
76
- "args": ["/path/to/mcp-remotetouch/build/index.js"],
77
- "env": {
78
- "REMOTETOUCH_SSH_HOST": "192.168.1.100",
79
- "REMOTETOUCH_SSH_USER": "pi",
80
- "REMOTETOUCH_SCREEN_WIDTH": "800",
81
- "REMOTETOUCH_SCREEN_HEIGHT": "480"
82
- }
84
+ "command": "npx",
85
+ "args": ["mcp-remotetouch"],
86
+ "env": {}
83
87
  }
84
88
  }
85
89
  }
86
90
  ```
87
91
 
92
+ Screen resolution is auto-detected from the device. You can override it with `REMOTETOUCH_SCREEN_WIDTH` and `REMOTETOUCH_SCREEN_HEIGHT` if needed.
93
+
88
94
  ## Environment Variables
89
95
 
90
96
  | Variable | Default | Description |
91
97
  |---|---|---|
92
- | `REMOTETOUCH_SSH_HOST` | (required) | SSH host of the remote device |
98
+ | `REMOTETOUCH_SSH_HOST` | (none) | SSH host of the remote device |
93
99
  | `REMOTETOUCH_SSH_USER` | `pi` | SSH username |
94
100
  | `REMOTETOUCH_SSH_PORT` | `22` | SSH port |
95
101
  | `REMOTETOUCH_SSH_KEY` | (none) | Path to SSH private key |
96
- | `REMOTETOUCH_SCREEN_WIDTH` | `800` | Screen width in pixels |
97
- | `REMOTETOUCH_SCREEN_HEIGHT` | `480` | Screen height in pixels |
102
+ | `REMOTETOUCH_SCREEN_WIDTH` | auto-detected | Screen width in pixels |
103
+ | `REMOTETOUCH_SCREEN_HEIGHT` | auto-detected | Screen height in pixels |
98
104
  | `REMOTETOUCH_USE_SUDO` | `false` | Run daemon with sudo |
99
105
 
100
106
  ## Tools
@@ -109,8 +115,8 @@ Connect to a remote Linux device via SSH and start the touch daemon. Returns a s
109
115
  | `user` | string? | SSH username |
110
116
  | `port` | number? | SSH port |
111
117
  | `sshKey` | string? | Path to SSH private key |
112
- | `screenWidth` | number? | Screen width in pixels |
113
- | `screenHeight` | number? | Screen height in pixels |
118
+ | `screenWidth` | number? | Screen width (auto-detected if omitted) |
119
+ | `screenHeight` | number? | Screen height (auto-detected if omitted) |
114
120
  | `useSudo` | boolean? | Run with sudo |
115
121
 
116
122
  ### `touch_tap`
@@ -159,6 +165,25 @@ Double tap at the given coordinates.
159
165
  | `x` | number | X coordinate |
160
166
  | `y` | number | Y coordinate |
161
167
 
168
+ ### `key_press`
169
+
170
+ Press a key with optional modifier keys. Requires `/dev/uinput` access on the remote device.
171
+
172
+ | Parameter | Type | Description |
173
+ |---|---|---|
174
+ | `sessionId` | string | Session ID |
175
+ | `key` | string | Key name (e.g. `enter`, `a`, `tab`, `f1`, `up`, `space`) |
176
+ | `modifiers` | string[]? | Modifier keys to hold (e.g. `["ctrl"]`, `["ctrl", "shift"]`) |
177
+
178
+ ### `key_type`
179
+
180
+ Type a string of text by simulating individual key presses. Requires `/dev/uinput` access on the remote device.
181
+
182
+ | Parameter | Type | Description |
183
+ |---|---|---|
184
+ | `sessionId` | string | Session ID |
185
+ | `text` | string | Text to type (e.g. `Hello, World!`) |
186
+
162
187
  ### `touch_disconnect`
163
188
 
164
189
  Disconnect a session and clean up the remote daemon.
@@ -179,13 +204,10 @@ Instead of running as a stdio MCP server, you can run `mcp-remotetouch` as an HT
179
204
 
180
205
  ```bash
181
206
  # Default: listen on 0.0.0.0:3000
182
- node build/index.js --server
207
+ npx mcp-remotetouch --server
183
208
 
184
209
  # Custom port and host
185
- node build/index.js --server --port 8080 --host 127.0.0.1
186
-
187
- # Or use the convenience script
188
- npm run start:server
210
+ npx mcp-remotetouch --server --port 8080 --host 127.0.0.1
189
211
  ```
190
212
 
191
213
  ### CLI arguments
@@ -198,58 +220,45 @@ npm run start:server
198
220
 
199
221
  Without `--server`, the process runs in stdio mode (the default, backward-compatible behavior).
200
222
 
201
- ### Connecting from an AI agent
223
+ ## Workflow
202
224
 
203
- The server exposes a single endpoint at `/mcp` that speaks the MCP Streamable HTTP transport protocol.
225
+ A typical session from Claude Desktop:
204
226
 
205
- ```bash
206
- # Initialize a session
207
- curl -X POST http://localhost:3000/mcp \
208
- -H "Content-Type: application/json" \
209
- -H "Accept: application/json, text/event-stream" \
210
- -d '{
211
- "jsonrpc": "2.0",
212
- "method": "initialize",
213
- "params": {
214
- "protocolVersion": "2025-03-26",
215
- "capabilities": {},
216
- "clientInfo": { "name": "test", "version": "1.0" }
217
- },
218
- "id": 1
219
- }'
220
- ```
221
227
 
222
- The response includes an `mcp-session-id` header. Include it in all subsequent requests:
228
+ 1. `touch_connect` connect to the remote device
229
+ 2. `touch_tap` / `touch_swipe` / `touch_long_press` / `touch_double_tap` — interact with the screen
230
+ 3. `key_press` / `key_type` — send keyboard input
231
+ 4. `touch_disconnect` — end the session
223
232
 
224
- ```bash
225
- curl -X POST http://localhost:3000/mcp \
226
- -H "Content-Type: application/json" \
227
- -H "Accept: application/json, text/event-stream" \
228
- -H "mcp-session-id: <session-id>" \
229
- -d '{"jsonrpc":"2.0","method":"tools/list","id":2}'
230
- ```
233
+ ## Troubleshooting
231
234
 
232
- ## Usage
235
+ ### Permission denied
233
236
 
234
- From Claude Desktop:
237
+ The user on the remote device needs access to `/dev/input/eventN`. Either:
235
238
 
236
- 1. `touch_connect` to connect to the remote device
237
- 2. `touch_tap` to tap a coordinate on the screen
238
- 3. `touch_swipe` to scroll or swipe
239
- 4. `touch_disconnect` to end the session
239
+ - Add the user to the `input` group: `sudo usermod -aG input $USER` (re-login required)
240
+ - Or set `REMOTETOUCH_USE_SUDO=true`
240
241
 
241
- ## Troubleshooting
242
+ ### No physical touchscreen device found
242
243
 
243
- ### Permission denied accessing /dev/uinput
244
+ The daemon could not find a touchscreen in `/proc/bus/input/devices`. Verify:
244
245
 
245
- The user on the remote device is not in the `input` group:
246
+ - The device has a touchscreen connected and its driver is loaded
247
+ - The device shows `INPUT_PROP_DIRECT` and has `ABS_MT_POSITION_X` capability
246
248
 
247
- ```bash
248
- sudo usermod -aG input $USER
249
- # Re-login for the change to take effect
250
- ```
249
+ ### Keyboard input not available
250
+
251
+ The `key_press` and `key_type` tools require write access to `/dev/uinput`. If keyboard is reported as unavailable:
252
+
253
+ - Add a udev rule to grant access:
254
+ ```bash
255
+ echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uinput.rules
256
+ sudo udevadm control --reload-rules && sudo udevadm trigger
257
+ ```
258
+ - Ensure the user is in the `input` group: `sudo usermod -aG input $USER` (re-login required)
259
+ - Or set `REMOTETOUCH_USE_SUDO=true`
251
260
 
252
- Alternatively, set `REMOTETOUCH_USE_SUDO=true`.
261
+ Touch tools continue to work even if `/dev/uinput` is not accessible.
253
262
 
254
263
  ### SSH connection fails
255
264
 
package/build/index.js CHANGED
@@ -8,13 +8,15 @@ import { SshTouchSessionManager } from "./ssh-touch-session.js";
8
8
  import { randomUUID } from "node:crypto";
9
9
  // Defaults from environment variables
10
10
  function defaultConfig(overrides = {}) {
11
+ const envWidth = process.env.REMOTETOUCH_SCREEN_WIDTH;
12
+ const envHeight = process.env.REMOTETOUCH_SCREEN_HEIGHT;
11
13
  return {
12
14
  host: overrides.host ?? process.env.REMOTETOUCH_SSH_HOST ?? "",
13
15
  user: overrides.user ?? process.env.REMOTETOUCH_SSH_USER ?? "pi",
14
16
  port: overrides.port ?? Number(process.env.REMOTETOUCH_SSH_PORT ?? "22"),
15
17
  sshKey: overrides.sshKey ?? process.env.REMOTETOUCH_SSH_KEY ?? undefined,
16
- screenWidth: overrides.screenWidth ?? Number(process.env.REMOTETOUCH_SCREEN_WIDTH ?? "800"),
17
- screenHeight: overrides.screenHeight ?? Number(process.env.REMOTETOUCH_SCREEN_HEIGHT ?? "480"),
18
+ screenWidth: overrides.screenWidth ?? (envWidth ? Number(envWidth) : undefined),
19
+ screenHeight: overrides.screenHeight ?? (envHeight ? Number(envHeight) : undefined),
18
20
  useSudo: overrides.useSudo ?? (process.env.REMOTETOUCH_USE_SUDO === "true"),
19
21
  };
20
22
  }
@@ -22,15 +24,15 @@ function defaultConfig(overrides = {}) {
22
24
  function createServer(manager) {
23
25
  const server = new McpServer({
24
26
  name: "mcp-remotetouch",
25
- version: "0.1.0",
27
+ version: "0.2.0",
26
28
  });
27
29
  server.tool("touch_connect", "Connect to a remote Linux device via SSH and start the touch daemon. Returns a session ID for subsequent touch commands.", {
28
30
  host: z.string().optional().describe("SSH host (default: env REMOTETOUCH_SSH_HOST)"),
29
31
  user: z.string().optional().describe("SSH user (default: env REMOTETOUCH_SSH_USER or 'pi')"),
30
32
  port: z.number().optional().describe("SSH port (default: env REMOTETOUCH_SSH_PORT or 22)"),
31
33
  sshKey: z.string().optional().describe("Path to SSH private key"),
32
- screenWidth: z.number().optional().describe("Screen width in pixels (default: env REMOTETOUCH_SCREEN_WIDTH or 800)"),
33
- screenHeight: z.number().optional().describe("Screen height in pixels (default: env REMOTETOUCH_SCREEN_HEIGHT or 480)"),
34
+ screenWidth: z.number().optional().describe("Screen width in pixels (default: auto-detected from device, or env REMOTETOUCH_SCREEN_WIDTH)"),
35
+ screenHeight: z.number().optional().describe("Screen height in pixels (default: auto-detected from device, or env REMOTETOUCH_SCREEN_HEIGHT)"),
34
36
  useSudo: z.boolean().optional().describe("Run daemon with sudo (default: env REMOTETOUCH_USE_SUDO or false)"),
35
37
  }, async (params) => {
36
38
  const config = defaultConfig({
@@ -50,8 +52,11 @@ function createServer(manager) {
50
52
  }
51
53
  try {
52
54
  const sessionId = await manager.connect(config);
55
+ const session = manager.getSession(sessionId);
56
+ const w = session.config.screenWidth ?? "unknown";
57
+ const h = session.config.screenHeight ?? "unknown";
53
58
  return {
54
- content: [{ type: "text", text: `Connected. Session ID: ${sessionId}\nHost: ${config.user}@${config.host}:${config.port}\nScreen: ${config.screenWidth}x${config.screenHeight}` }],
59
+ content: [{ type: "text", text: `Connected. Session ID: ${sessionId}\nHost: ${config.user}@${config.host}:${config.port}\nScreen: ${w}x${h}` }],
55
60
  };
56
61
  }
57
62
  catch (err) {
@@ -161,6 +166,50 @@ function createServer(manager) {
161
166
  return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
162
167
  }
163
168
  });
169
+ server.tool("key_press", "Press a key with optional modifier keys on the remote device. Requires /dev/uinput access.", {
170
+ sessionId: z.string().describe("Session ID from touch_connect"),
171
+ key: z.string().describe("Key name (e.g. 'enter', 'a', 'tab', 'f1', 'up', 'space')"),
172
+ modifiers: z.array(z.string()).optional().describe("Modifier keys to hold (e.g. ['ctrl'], ['ctrl', 'shift'])"),
173
+ }, async (params) => {
174
+ const cmd = {
175
+ id: `keypress-${Date.now()}`,
176
+ type: "key_press",
177
+ key: params.key,
178
+ modifiers: params.modifiers,
179
+ };
180
+ try {
181
+ const resp = await manager.sendCommand(params.sessionId, cmd);
182
+ if (resp.status === "error") {
183
+ return { content: [{ type: "text", text: `Key press failed: ${resp.message}` }], isError: true };
184
+ }
185
+ const mods = params.modifiers?.length ? params.modifiers.join("+") + "+" : "";
186
+ return { content: [{ type: "text", text: `Pressed ${mods}${params.key}` }] };
187
+ }
188
+ catch (err) {
189
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
190
+ }
191
+ });
192
+ server.tool("key_type", "Type a string of text on the remote device by simulating individual key presses. Requires /dev/uinput access.", {
193
+ sessionId: z.string().describe("Session ID from touch_connect"),
194
+ text: z.string().describe("Text to type (e.g. 'Hello, World!')"),
195
+ }, async (params) => {
196
+ const cmd = {
197
+ id: `keytype-${Date.now()}`,
198
+ type: "key_type",
199
+ text: params.text,
200
+ };
201
+ try {
202
+ const resp = await manager.sendCommand(params.sessionId, cmd);
203
+ if (resp.status === "error") {
204
+ return { content: [{ type: "text", text: `Key type failed: ${resp.message}` }], isError: true };
205
+ }
206
+ const display = params.text.length > 50 ? params.text.substring(0, 50) + "..." : params.text;
207
+ return { content: [{ type: "text", text: `Typed: ${display}` }] };
208
+ }
209
+ catch (err) {
210
+ return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
211
+ }
212
+ });
164
213
  server.tool("touch_disconnect", "Disconnect a touch session and clean up the remote daemon.", {
165
214
  sessionId: z.string().describe("Session ID to disconnect"),
166
215
  }, async (params) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- export declare const PYTHON_DAEMON_SCRIPT = "\nimport sys\nimport os\nimport json\nimport struct\nimport fcntl\nimport time\n\n# ioctl constants\nUI_SET_EVBIT = 0x40045564\nUI_SET_ABSBIT = 0x40045567\nUI_SET_PROPBIT = 0x4004556e\nUI_DEV_SETUP = 0x405c5503\nUI_DEV_CREATE = 0x5501\nUI_DEV_DESTROY = 0x5502\n\n# Event types\nEV_SYN = 0x00\nEV_ABS = 0x03\n\n# Sync codes\nSYN_REPORT = 0x00\n\n# ABS codes\nABS_MT_SLOT = 0x2f\nABS_MT_TRACKING_ID = 0x39\nABS_MT_POSITION_X = 0x35\nABS_MT_POSITION_Y = 0x36\n\n# Input properties\nINPUT_PROP_DIRECT = 0x01\n\n# uinput_abs_setup struct: __u16 code, struct input_absinfo { __s32 value, min, max, fuzz, flat, resolution }\n# = HiiiiiI -> but let's use the raw struct\n# Actually uinput_abs_setup = __u16 + padding + input_absinfo(6 x __s32)\n# struct uinput_abs_setup { __u16 code; __u16 pad; struct input_absinfo { __s32 value, minimum, maximum, fuzz, flat, resolution; }; };\nUI_ABS_SETUP = 0x405c5504\n\nUINPUT_MAX_NAME_SIZE = 80\n\ndef make_input_event(tv_sec, tv_usec, ev_type, code, value):\n # struct input_event uses struct timeval (long, long) + __u16 + __u16 + __s32\n # native long size handles 32/64 bit automatically\n return struct.pack('llHHi', tv_sec, tv_usec, ev_type, code, value)\n\ndef write_event(fd, ev_type, code, value):\n now = time.time()\n sec = int(now)\n usec = int((now - sec) * 1000000)\n os.write(fd, make_input_event(sec, usec, ev_type, code, value))\n\ndef syn_report(fd):\n write_event(fd, EV_SYN, SYN_REPORT, 0)\n\ndef touch_down(fd, slot, tracking_id, x, y):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, tracking_id)\n write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)\n write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)\n syn_report(fd)\n\ndef touch_move(fd, slot, x, y):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)\n write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)\n syn_report(fd)\n\ndef touch_up(fd, slot):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1)\n syn_report(fd)\n\ndef setup_uinput(screen_width, screen_height):\n fd = os.open('/dev/uinput', os.O_WRONLY | os.O_NONBLOCK)\n\n # Enable EV_ABS\n fcntl.ioctl(fd, UI_SET_EVBIT, EV_ABS)\n\n # Enable ABS axes\n fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT)\n fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID)\n fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X)\n fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y)\n\n # Set INPUT_PROP_DIRECT for touchscreen\n fcntl.ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT)\n\n # Setup ABS axes with uinput_abs_setup\n # struct uinput_abs_setup { __u16 code; __u16 pad; struct input_absinfo { __s32 value, minimum, maximum, fuzz, flat, resolution; }; };\n abs_setup_fmt = 'HH6i'\n\n # ABS_MT_SLOT: 0 to 9\n data = struct.pack(abs_setup_fmt, ABS_MT_SLOT, 0, 0, 0, 9, 0, 0, 0)\n fcntl.ioctl(fd, UI_ABS_SETUP, data)\n\n # ABS_MT_TRACKING_ID: 0 to 65535\n data = struct.pack(abs_setup_fmt, ABS_MT_TRACKING_ID, 0, 0, 0, 65535, 0, 0, 0)\n fcntl.ioctl(fd, UI_ABS_SETUP, data)\n\n # ABS_MT_POSITION_X: 0 to screen_width - 1\n data = struct.pack(abs_setup_fmt, ABS_MT_POSITION_X, 0, 0, 0, screen_width - 1, 0, 0, 0)\n fcntl.ioctl(fd, UI_ABS_SETUP, data)\n\n # ABS_MT_POSITION_Y: 0 to screen_height - 1\n data = struct.pack(abs_setup_fmt, ABS_MT_POSITION_Y, 0, 0, 0, screen_height - 1, 0, 0, 0)\n fcntl.ioctl(fd, UI_ABS_SETUP, data)\n\n # uinput_setup: char name[UINPUT_MAX_NAME_SIZE]; struct input_id { __u16 bustype, vendor, product, version; };\n # struct input_id: HHH H (bustype=0x03 USB, vendor=0x1234, product=0x5678, version=1)\n # struct uinput_setup: 80s HHHH I (ff_effects_max)\n name = b'mcp-remotetouch'\n setup_data = struct.pack('80sHHHHI', name.ljust(UINPUT_MAX_NAME_SIZE, b'\\x00'), 0x03, 0x1234, 0x5678, 1, 0)\n fcntl.ioctl(fd, UI_DEV_SETUP, setup_data)\n\n # Create the device\n fcntl.ioctl(fd, UI_DEV_CREATE)\n\n # Give udev time to create the device node\n time.sleep(0.2)\n\n return fd\n\ndef send_response(cmd_id, status, message=None):\n resp = {'id': cmd_id, 'status': status}\n if message is not None:\n resp['message'] = message\n sys.stdout.write(json.dumps(resp) + '\\n')\n sys.stdout.flush()\n\ntracking_id_counter = 0\n\ndef next_tracking_id():\n global tracking_id_counter\n tracking_id_counter = (tracking_id_counter + 1) % 65536\n return tracking_id_counter\n\ndef handle_tap(fd, cmd):\n x = int(cmd['x'])\n y = int(cmd['y'])\n duration_ms = cmd.get('duration_ms', 50)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(duration_ms / 1000.0)\n touch_up(fd, 0)\n\ndef handle_swipe(fd, cmd):\n x1 = int(cmd['x'])\n y1 = int(cmd['y'])\n x2 = int(cmd['x2'])\n y2 = int(cmd['y2'])\n duration_ms = cmd.get('duration_ms', 300)\n steps = cmd.get('steps', max(int(duration_ms / 15), 2))\n tid = next_tracking_id()\n\n touch_down(fd, 0, tid, x1, y1)\n for i in range(1, steps + 1):\n t = i / steps\n cx = int(x1 + (x2 - x1) * t)\n cy = int(y1 + (y2 - y1) * t)\n time.sleep(duration_ms / 1000.0 / steps)\n touch_move(fd, 0, cx, cy)\n touch_up(fd, 0)\n\ndef handle_long_press(fd, cmd):\n x = int(cmd['x'])\n y = int(cmd['y'])\n duration_ms = cmd.get('duration_ms', 800)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(duration_ms / 1000.0)\n touch_up(fd, 0)\n\ndef handle_double_tap(fd, cmd):\n x = int(cmd['x'])\n y = int(cmd['y'])\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(0.05)\n touch_up(fd, 0)\n time.sleep(0.1)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(0.05)\n touch_up(fd, 0)\n\ndef main():\n fd = None\n try:\n for line in sys.stdin:\n line = line.strip()\n if not line:\n continue\n try:\n cmd = json.loads(line)\n except json.JSONDecodeError as e:\n sys.stderr.write('Invalid JSON: ' + str(e) + '\\n')\n continue\n\n cmd_id = cmd.get('id', '?')\n cmd_type = cmd.get('type', '')\n\n try:\n if cmd_type == 'init':\n screen_width = cmd.get('screen_width', 800)\n screen_height = cmd.get('screen_height', 480)\n fd = setup_uinput(screen_width, screen_height)\n send_response(cmd_id, 'ready', 'uinput device created')\n elif cmd_type == 'shutdown':\n send_response(cmd_id, 'ok', 'shutting down')\n break\n elif fd is None:\n send_response(cmd_id, 'error', 'device not initialized, send init first')\n elif cmd_type == 'tap':\n handle_tap(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'swipe':\n handle_swipe(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'long_press':\n handle_long_press(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'double_tap':\n handle_double_tap(fd, cmd)\n send_response(cmd_id, 'ok')\n else:\n send_response(cmd_id, 'error', 'unknown command: ' + cmd_type)\n except PermissionError:\n send_response(cmd_id, 'error', 'Permission denied accessing /dev/uinput. Ensure user is in the input group: sudo usermod -aG input $USER')\n except Exception as e:\n send_response(cmd_id, 'error', str(e))\n finally:\n if fd is not None:\n try:\n fcntl.ioctl(fd, UI_DEV_DESTROY)\n os.close(fd)\n except Exception:\n pass\n\nif __name__ == '__main__':\n main()\n";
1
+ export declare const PYTHON_DAEMON_SCRIPT = "\nimport sys\nimport os\nimport json\nimport struct\nimport time\nimport glob\nimport re\n\n# Event types\nEV_SYN = 0x00\nEV_KEY = 0x01\nEV_ABS = 0x03\n\n# Sync codes\nSYN_REPORT = 0x00\n\n# Key codes\nBTN_TOUCH = 0x14a\n\n# ABS codes\nABS_X = 0x00\nABS_Y = 0x01\nABS_MT_SLOT = 0x2f\nABS_MT_TRACKING_ID = 0x39\nABS_MT_POSITION_X = 0x35\nABS_MT_POSITION_Y = 0x36\n\n# uinput constants\nUI_SET_EVBIT = 0x40045564\nUI_SET_KEYBIT = 0x40045565\nUI_DEV_CREATE = 0x5501\nUI_DEV_DESTROY = 0x5502\nEV_REP = 0x14\n\n# Key code mapping: key name -> Linux keycode\nKEY_MAP = {\n 'a': 30, 'b': 48, 'c': 46, 'd': 32, 'e': 18, 'f': 33, 'g': 34, 'h': 35,\n 'i': 23, 'j': 36, 'k': 37, 'l': 38, 'm': 50, 'n': 49, 'o': 24, 'p': 25,\n 'q': 16, 'r': 19, 's': 31, 't': 20, 'u': 22, 'v': 47, 'w': 17, 'x': 45,\n 'y': 21, 'z': 44,\n '1': 2, '2': 3, '3': 4, '4': 5, '5': 6, '6': 7, '7': 8, '8': 9, '9': 10, '0': 11,\n 'enter': 28, 'tab': 15, 'space': 57, 'backspace': 14, 'escape': 1, 'delete': 111,\n 'up': 103, 'down': 108, 'left': 105, 'right': 106,\n 'home': 102, 'end': 107, 'pageup': 104, 'pagedown': 109, 'insert': 110,\n 'ctrl': 29, 'shift': 42, 'alt': 56, 'meta': 125,\n 'ctrl_r': 97, 'shift_r': 54, 'alt_r': 100,\n 'f1': 59, 'f2': 60, 'f3': 61, 'f4': 62, 'f5': 63, 'f6': 64,\n 'f7': 65, 'f8': 66, 'f9': 67, 'f10': 68, 'f11': 87, 'f12': 88,\n 'minus': 12, 'equal': 13, 'leftbrace': 26, 'rightbrace': 27,\n 'semicolon': 39, 'apostrophe': 40, 'grave': 41, 'backslash': 43,\n 'comma': 51, 'dot': 52, 'slash': 53, 'capslock': 58,\n}\n\n# Character to (key_name, needs_shift) mapping for key_type\nCHAR_MAP = {\n 'a': ('a', False), 'b': ('b', False), 'c': ('c', False), 'd': ('d', False),\n 'e': ('e', False), 'f': ('f', False), 'g': ('g', False), 'h': ('h', False),\n 'i': ('i', False), 'j': ('j', False), 'k': ('k', False), 'l': ('l', False),\n 'm': ('m', False), 'n': ('n', False), 'o': ('o', False), 'p': ('p', False),\n 'q': ('q', False), 'r': ('r', False), 's': ('s', False), 't': ('t', False),\n 'u': ('u', False), 'v': ('v', False), 'w': ('w', False), 'x': ('x', False),\n 'y': ('y', False), 'z': ('z', False),\n 'A': ('a', True), 'B': ('b', True), 'C': ('c', True), 'D': ('d', True),\n 'E': ('e', True), 'F': ('f', True), 'G': ('g', True), 'H': ('h', True),\n 'I': ('i', True), 'J': ('j', True), 'K': ('k', True), 'L': ('l', True),\n 'M': ('m', True), 'N': ('n', True), 'O': ('o', True), 'P': ('p', True),\n 'Q': ('q', True), 'R': ('r', True), 'S': ('s', True), 'T': ('t', True),\n 'U': ('u', True), 'V': ('v', True), 'W': ('w', True), 'X': ('x', True),\n 'Y': ('y', True), 'Z': ('z', True),\n '0': ('0', False), '1': ('1', False), '2': ('2', False), '3': ('3', False),\n '4': ('4', False), '5': ('5', False), '6': ('6', False), '7': ('7', False),\n '8': ('8', False), '9': ('9', False),\n ' ': ('space', False), '\\t': ('tab', False), '\\n': ('enter', False),\n '-': ('minus', False), '=': ('equal', False),\n '[': ('leftbrace', False), ']': ('rightbrace', False),\n ';': ('semicolon', False), \"'\": ('apostrophe', False),\n '`': ('grave', False), '\\\\': ('backslash', False),\n ',': ('comma', False), '.': ('dot', False), '/': ('slash', False),\n '!': ('1', True), '@': ('2', True), '#': ('3', True), '$': ('4', True),\n '%': ('5', True), '^': ('6', True), '&': ('7', True), '*': ('8', True),\n '(': ('9', True), ')': ('0', True),\n '_': ('minus', True), '+': ('equal', True),\n '{': ('leftbrace', True), '}': ('rightbrace', True),\n ':': ('semicolon', True), '\"': ('apostrophe', True),\n '~': ('grave', True), '|': ('backslash', True),\n '<': ('comma', True), '>': ('dot', True), '?': ('slash', True),\n}\n\ndef setup_uinput_keyboard():\n \"\"\"Create a virtual keyboard device via /dev/uinput.\"\"\"\n uinput_fd = os.open('/dev/uinput', os.O_WRONLY | os.O_NONBLOCK)\n # Enable EV_KEY and EV_REP event types\n fcntl.ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY)\n fcntl.ioctl(uinput_fd, UI_SET_EVBIT, EV_REP)\n # Enable all keycodes in KEY_MAP\n for keycode in KEY_MAP.values():\n fcntl.ioctl(uinput_fd, UI_SET_KEYBIT, keycode)\n # Write uinput_user_dev struct: 80-byte name + 1036 bytes of zeros = 1116 bytes\n name = b'mcp-remotetouch-kbd'\n dev_struct = name + b'\\x00' * (80 - len(name)) # name[80]\n dev_struct += struct.pack('HH', 0x03, 0x01) # id: bustype=BUS_VIRTUAL, vendor\n dev_struct += struct.pack('HH', 0x01, 0x01) # id: product, version\n dev_struct += b'\\x00' * (1116 - len(dev_struct)) # ff_effects_max + absmin/max/fuzz/flat\n os.write(uinput_fd, dev_struct)\n fcntl.ioctl(uinput_fd, UI_DEV_CREATE)\n time.sleep(0.2) # Wait for device to be registered\n return uinput_fd\n\ndef destroy_uinput_keyboard(uinput_fd):\n \"\"\"Destroy the virtual keyboard device.\"\"\"\n try:\n fcntl.ioctl(uinput_fd, UI_DEV_DESTROY)\n except Exception:\n pass\n try:\n os.close(uinput_fd)\n except Exception:\n pass\n\ndef kbd_write_event(uinput_fd, ev_type, code, value):\n \"\"\"Write an input event to the uinput keyboard device.\"\"\"\n now = time.time()\n sec = int(now)\n usec = int((now - sec) * 1000000)\n os.write(uinput_fd, struct.pack('llHHi', sec, usec, ev_type, code, value))\n\ndef kbd_syn(uinput_fd):\n kbd_write_event(uinput_fd, EV_SYN, SYN_REPORT, 0)\n\ndef handle_key_press(uinput_fd, cmd):\n \"\"\"Handle key_press command: press a key with optional modifiers.\"\"\"\n key = cmd.get('key', '').lower()\n modifiers = cmd.get('modifiers', [])\n keycode = KEY_MAP.get(key)\n if keycode is None:\n raise ValueError('Unknown key: ' + cmd.get('key', ''))\n # Press modifier keys\n mod_codes = []\n for mod in modifiers:\n mc = KEY_MAP.get(mod.lower())\n if mc is None:\n raise ValueError('Unknown modifier: ' + mod)\n mod_codes.append(mc)\n kbd_write_event(uinput_fd, EV_KEY, mc, 1)\n kbd_syn(uinput_fd)\n # Press and release main key\n kbd_write_event(uinput_fd, EV_KEY, keycode, 1)\n kbd_syn(uinput_fd)\n time.sleep(0.02)\n kbd_write_event(uinput_fd, EV_KEY, keycode, 0)\n kbd_syn(uinput_fd)\n # Release modifiers in reverse order\n for mc in reversed(mod_codes):\n kbd_write_event(uinput_fd, EV_KEY, mc, 0)\n kbd_syn(uinput_fd)\n\ndef handle_key_type(uinput_fd, cmd):\n \"\"\"Handle key_type command: type a string of text character by character.\"\"\"\n text = cmd.get('text', '')\n shift_code = KEY_MAP['shift']\n for ch in text:\n entry = CHAR_MAP.get(ch)\n if entry is None:\n continue # Skip unmapped characters\n key_name, needs_shift = entry\n keycode = KEY_MAP[key_name]\n if needs_shift:\n kbd_write_event(uinput_fd, EV_KEY, shift_code, 1)\n kbd_syn(uinput_fd)\n kbd_write_event(uinput_fd, EV_KEY, keycode, 1)\n kbd_syn(uinput_fd)\n time.sleep(0.01)\n kbd_write_event(uinput_fd, EV_KEY, keycode, 0)\n kbd_syn(uinput_fd)\n if needs_shift:\n kbd_write_event(uinput_fd, EV_KEY, shift_code, 0)\n kbd_syn(uinput_fd)\n time.sleep(0.01)\n\n# EVIOCGABS ioctl: _IOR('E', 0x40 + abs_code, struct input_absinfo)\n# struct input_absinfo = 6 x __s32 = 24 bytes\n# _IOR('E', N, 24) = (2 << 30) | (24 << 16) | (ord('E') << 8) | N\ndef EVIOCGABS(abs_code):\n return (2 << 30) | (24 << 16) | (ord('E') << 8) | (0x40 + abs_code)\n\ndef make_input_event(tv_sec, tv_usec, ev_type, code, value):\n return struct.pack('llHHi', tv_sec, tv_usec, ev_type, code, value)\n\ndef write_event(fd, ev_type, code, value):\n now = time.time()\n sec = int(now)\n usec = int((now - sec) * 1000000)\n os.write(fd, make_input_event(sec, usec, ev_type, code, value))\n\ndef syn_report(fd):\n write_event(fd, EV_SYN, SYN_REPORT, 0)\n\ndef touch_down(fd, slot, tracking_id, x, y):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, tracking_id)\n write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)\n write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)\n write_event(fd, EV_ABS, ABS_X, x)\n write_event(fd, EV_ABS, ABS_Y, y)\n write_event(fd, EV_KEY, BTN_TOUCH, 1)\n syn_report(fd)\n\ndef touch_move(fd, slot, x, y):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)\n write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)\n write_event(fd, EV_ABS, ABS_X, x)\n write_event(fd, EV_ABS, ABS_Y, y)\n syn_report(fd)\n\ndef touch_up(fd, slot):\n write_event(fd, EV_ABS, ABS_MT_SLOT, slot)\n write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1)\n write_event(fd, EV_KEY, BTN_TOUCH, 0)\n syn_report(fd)\n\ndef detect_screen_resolution():\n \"\"\"Detect screen resolution from framebuffer or DRM.\"\"\"\n # Try framebuffer first\n try:\n with open('/sys/class/graphics/fb0/virtual_size', 'r') as f:\n parts = f.read().strip().split(',')\n if len(parts) == 2:\n return int(parts[0]), int(parts[1])\n except Exception:\n pass\n\n # Try DRM\n try:\n import glob as g\n for mode_path in g.glob('/sys/class/drm/*/modes'):\n with open(mode_path, 'r') as f:\n line = f.readline().strip()\n if 'x' in line:\n parts = line.split('x')\n return int(parts[0]), int(parts[1])\n except Exception:\n pass\n\n return None, None\n\ndef find_touchscreen():\n \"\"\"Find the physical touchscreen event device by scanning /proc/bus/input/devices.\"\"\"\n try:\n with open('/proc/bus/input/devices', 'r') as f:\n content = f.read()\n except Exception:\n return None\n\n for block in content.split('\\n\\n'):\n lines = block.strip().split('\\n')\n name = ''\n handlers = ''\n props = ''\n evbits = ''\n absbits = ''\n for line in lines:\n if line.startswith('N: Name='):\n name = line.split('=', 1)[1].strip('\"')\n elif line.startswith('H: Handlers='):\n handlers = line.split('=', 1)[1]\n elif line.startswith('B: PROP='):\n props = line.split('=', 1)[1]\n elif line.startswith('B: EV='):\n evbits = line.split('=', 1)[1]\n elif line.startswith('B: ABS='):\n absbits = line.split('=', 1)[1]\n\n # Skip virtual devices (mcp-remotetouch)\n if 'mcp-remotetouch' in name:\n continue\n\n # Check for INPUT_PROP_DIRECT (bit 1 in PROP)\n try:\n prop_val = int(props.strip(), 16)\n except (ValueError, IndexError):\n prop_val = 0\n if not (prop_val & 0x02):\n continue\n\n # Check that it has ABS_MT_POSITION_X (bit 0x35) in ABS bitmask\n try:\n abs_parts = absbits.strip().split()\n abs_val = 0\n for i, part in enumerate(reversed(abs_parts)):\n abs_val |= int(part, 16) << (i * 32)\n except (ValueError, IndexError):\n abs_val = 0\n if not (abs_val & (1 << ABS_MT_POSITION_X)):\n continue\n\n # Extract event device number\n m = re.search(r'event(\\d+)', handlers)\n if m:\n return '/dev/input/event' + m.group(1)\n\n return None\n\nimport fcntl\n\ndef get_abs_range(fd, abs_code):\n \"\"\"Get the min/max range of an ABS axis using EVIOCGABS ioctl.\"\"\"\n try:\n buf = bytearray(24)\n fcntl.ioctl(fd, EVIOCGABS(abs_code), buf)\n value, minimum, maximum, fuzz, flat, resolution = struct.unpack('6i', buf)\n return minimum, maximum\n except Exception:\n return None, None\n\ndef open_touch_device(screen_width, screen_height):\n \"\"\"Open the physical touchscreen device for event injection.\"\"\"\n dev_path = find_touchscreen()\n if dev_path is None:\n raise RuntimeError('No physical touchscreen device found')\n\n fd = os.open(dev_path, os.O_WRONLY)\n\n # Read the actual ABS ranges from the device\n rd_fd = os.open(dev_path, os.O_RDONLY)\n x_min, x_max = get_abs_range(rd_fd, ABS_MT_POSITION_X)\n y_min, y_max = get_abs_range(rd_fd, ABS_MT_POSITION_Y)\n os.close(rd_fd)\n\n if x_max is None or y_max is None:\n x_max = screen_width - 1\n y_max = screen_height - 1\n x_min = 0\n y_min = 0\n\n return fd, dev_path, x_min, x_max, y_min, y_max\n\ndef send_response(cmd_id, status, message=None, screen_width=None, screen_height=None):\n resp = {'id': cmd_id, 'status': status}\n if message is not None:\n resp['message'] = message\n if screen_width is not None:\n resp['screen_width'] = screen_width\n if screen_height is not None:\n resp['screen_height'] = screen_height\n sys.stdout.write(json.dumps(resp) + '\\n')\n sys.stdout.flush()\n\ntracking_id_counter = 0\n\ndef next_tracking_id():\n global tracking_id_counter\n tracking_id_counter = (tracking_id_counter + 1) % 65536\n return tracking_id_counter\n\n# Coordinate mapping globals\ndev_x_min = 0\ndev_x_max = 0\ndev_y_min = 0\ndev_y_max = 0\nscr_w = 0\nscr_h = 0\n\ndef map_x(x):\n \"\"\"Map screen coordinate to device coordinate.\"\"\"\n return dev_x_min + int(x * (dev_x_max - dev_x_min) / (scr_w - 1))\n\ndef map_y(y):\n \"\"\"Map screen coordinate to device coordinate.\"\"\"\n return dev_y_min + int(y * (dev_y_max - dev_y_min) / (scr_h - 1))\n\ndef handle_tap(fd, cmd):\n x = map_x(int(cmd['x']))\n y = map_y(int(cmd['y']))\n duration_ms = cmd.get('duration_ms', 50)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(duration_ms / 1000.0)\n touch_up(fd, 0)\n\ndef handle_swipe(fd, cmd):\n x1 = int(cmd['x'])\n y1 = int(cmd['y'])\n x2 = int(cmd['x2'])\n y2 = int(cmd['y2'])\n duration_ms = cmd.get('duration_ms', 300)\n steps = cmd.get('steps', max(int(duration_ms / 15), 2))\n tid = next_tracking_id()\n\n touch_down(fd, 0, tid, map_x(x1), map_y(y1))\n for i in range(1, steps + 1):\n t = i / steps\n cx = int(x1 + (x2 - x1) * t)\n cy = int(y1 + (y2 - y1) * t)\n time.sleep(duration_ms / 1000.0 / steps)\n touch_move(fd, 0, map_x(cx), map_y(cy))\n touch_up(fd, 0)\n\ndef handle_long_press(fd, cmd):\n x = map_x(int(cmd['x']))\n y = map_y(int(cmd['y']))\n duration_ms = cmd.get('duration_ms', 800)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(duration_ms / 1000.0)\n touch_up(fd, 0)\n\ndef handle_double_tap(fd, cmd):\n x = map_x(int(cmd['x']))\n y = map_y(int(cmd['y']))\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(0.05)\n touch_up(fd, 0)\n time.sleep(0.1)\n tid = next_tracking_id()\n touch_down(fd, 0, tid, x, y)\n time.sleep(0.05)\n touch_up(fd, 0)\n\ndef main():\n global dev_x_min, dev_x_max, dev_y_min, dev_y_max, scr_w, scr_h\n fd = None\n kbd_fd = None\n try:\n for line in sys.stdin:\n line = line.strip()\n if not line:\n continue\n try:\n cmd = json.loads(line)\n except json.JSONDecodeError as e:\n sys.stderr.write('Invalid JSON: ' + str(e) + '\\n')\n continue\n\n cmd_id = cmd.get('id', '?')\n cmd_type = cmd.get('type', '')\n\n try:\n if cmd_type == 'init':\n scr_w = cmd.get('screen_width', 0)\n scr_h = cmd.get('screen_height', 0)\n if scr_w <= 0 or scr_h <= 0:\n det_w, det_h = detect_screen_resolution()\n if det_w and det_h:\n scr_w = det_w\n scr_h = det_h\n else:\n scr_w = scr_w or 800\n scr_h = scr_h or 480\n fd, dev_path, dev_x_min, dev_x_max, dev_y_min, dev_y_max = open_touch_device(scr_w, scr_h)\n # Best-effort keyboard setup \u2014 touch works even if uinput fails\n try:\n kbd_fd = setup_uinput_keyboard()\n kbd_msg = ' (keyboard: ok)'\n except Exception as ke:\n kbd_fd = None\n kbd_msg = ' (keyboard: unavailable - ' + str(ke) + ')'\n send_response(cmd_id, 'ready', 'injecting into ' + dev_path + kbd_msg, scr_w, scr_h)\n elif cmd_type == 'shutdown':\n send_response(cmd_id, 'ok', 'shutting down')\n break\n elif fd is None:\n send_response(cmd_id, 'error', 'device not initialized, send init first')\n elif cmd_type == 'tap':\n handle_tap(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'swipe':\n handle_swipe(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'long_press':\n handle_long_press(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'double_tap':\n handle_double_tap(fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'key_press':\n if kbd_fd is None:\n send_response(cmd_id, 'error', 'keyboard not available: /dev/uinput not accessible')\n else:\n handle_key_press(kbd_fd, cmd)\n send_response(cmd_id, 'ok')\n elif cmd_type == 'key_type':\n if kbd_fd is None:\n send_response(cmd_id, 'error', 'keyboard not available: /dev/uinput not accessible')\n else:\n handle_key_type(kbd_fd, cmd)\n send_response(cmd_id, 'ok')\n else:\n send_response(cmd_id, 'error', 'unknown command: ' + cmd_type)\n except PermissionError:\n send_response(cmd_id, 'error', 'Permission denied. Run with sudo or ensure user is in the input group: sudo usermod -aG input $USER')\n except Exception as e:\n send_response(cmd_id, 'error', str(e))\n finally:\n if kbd_fd is not None:\n destroy_uinput_keyboard(kbd_fd)\n if fd is not None:\n try:\n os.close(fd)\n except Exception:\n pass\n\nif __name__ == '__main__':\n main()\n";
@@ -3,44 +3,188 @@ import sys
3
3
  import os
4
4
  import json
5
5
  import struct
6
- import fcntl
7
6
  import time
8
-
9
- # ioctl constants
10
- UI_SET_EVBIT = 0x40045564
11
- UI_SET_ABSBIT = 0x40045567
12
- UI_SET_PROPBIT = 0x4004556e
13
- UI_DEV_SETUP = 0x405c5503
14
- UI_DEV_CREATE = 0x5501
15
- UI_DEV_DESTROY = 0x5502
7
+ import glob
8
+ import re
16
9
 
17
10
  # Event types
18
11
  EV_SYN = 0x00
12
+ EV_KEY = 0x01
19
13
  EV_ABS = 0x03
20
14
 
21
15
  # Sync codes
22
16
  SYN_REPORT = 0x00
23
17
 
18
+ # Key codes
19
+ BTN_TOUCH = 0x14a
20
+
24
21
  # ABS codes
22
+ ABS_X = 0x00
23
+ ABS_Y = 0x01
25
24
  ABS_MT_SLOT = 0x2f
26
25
  ABS_MT_TRACKING_ID = 0x39
27
26
  ABS_MT_POSITION_X = 0x35
28
27
  ABS_MT_POSITION_Y = 0x36
29
28
 
30
- # Input properties
31
- INPUT_PROP_DIRECT = 0x01
32
-
33
- # uinput_abs_setup struct: __u16 code, struct input_absinfo { __s32 value, min, max, fuzz, flat, resolution }
34
- # = HiiiiiI -> but let's use the raw struct
35
- # Actually uinput_abs_setup = __u16 + padding + input_absinfo(6 x __s32)
36
- # struct uinput_abs_setup { __u16 code; __u16 pad; struct input_absinfo { __s32 value, minimum, maximum, fuzz, flat, resolution; }; };
37
- UI_ABS_SETUP = 0x405c5504
29
+ # uinput constants
30
+ UI_SET_EVBIT = 0x40045564
31
+ UI_SET_KEYBIT = 0x40045565
32
+ UI_DEV_CREATE = 0x5501
33
+ UI_DEV_DESTROY = 0x5502
34
+ EV_REP = 0x14
35
+
36
+ # Key code mapping: key name -> Linux keycode
37
+ KEY_MAP = {
38
+ 'a': 30, 'b': 48, 'c': 46, 'd': 32, 'e': 18, 'f': 33, 'g': 34, 'h': 35,
39
+ 'i': 23, 'j': 36, 'k': 37, 'l': 38, 'm': 50, 'n': 49, 'o': 24, 'p': 25,
40
+ 'q': 16, 'r': 19, 's': 31, 't': 20, 'u': 22, 'v': 47, 'w': 17, 'x': 45,
41
+ 'y': 21, 'z': 44,
42
+ '1': 2, '2': 3, '3': 4, '4': 5, '5': 6, '6': 7, '7': 8, '8': 9, '9': 10, '0': 11,
43
+ 'enter': 28, 'tab': 15, 'space': 57, 'backspace': 14, 'escape': 1, 'delete': 111,
44
+ 'up': 103, 'down': 108, 'left': 105, 'right': 106,
45
+ 'home': 102, 'end': 107, 'pageup': 104, 'pagedown': 109, 'insert': 110,
46
+ 'ctrl': 29, 'shift': 42, 'alt': 56, 'meta': 125,
47
+ 'ctrl_r': 97, 'shift_r': 54, 'alt_r': 100,
48
+ 'f1': 59, 'f2': 60, 'f3': 61, 'f4': 62, 'f5': 63, 'f6': 64,
49
+ 'f7': 65, 'f8': 66, 'f9': 67, 'f10': 68, 'f11': 87, 'f12': 88,
50
+ 'minus': 12, 'equal': 13, 'leftbrace': 26, 'rightbrace': 27,
51
+ 'semicolon': 39, 'apostrophe': 40, 'grave': 41, 'backslash': 43,
52
+ 'comma': 51, 'dot': 52, 'slash': 53, 'capslock': 58,
53
+ }
54
+
55
+ # Character to (key_name, needs_shift) mapping for key_type
56
+ CHAR_MAP = {
57
+ 'a': ('a', False), 'b': ('b', False), 'c': ('c', False), 'd': ('d', False),
58
+ 'e': ('e', False), 'f': ('f', False), 'g': ('g', False), 'h': ('h', False),
59
+ 'i': ('i', False), 'j': ('j', False), 'k': ('k', False), 'l': ('l', False),
60
+ 'm': ('m', False), 'n': ('n', False), 'o': ('o', False), 'p': ('p', False),
61
+ 'q': ('q', False), 'r': ('r', False), 's': ('s', False), 't': ('t', False),
62
+ 'u': ('u', False), 'v': ('v', False), 'w': ('w', False), 'x': ('x', False),
63
+ 'y': ('y', False), 'z': ('z', False),
64
+ 'A': ('a', True), 'B': ('b', True), 'C': ('c', True), 'D': ('d', True),
65
+ 'E': ('e', True), 'F': ('f', True), 'G': ('g', True), 'H': ('h', True),
66
+ 'I': ('i', True), 'J': ('j', True), 'K': ('k', True), 'L': ('l', True),
67
+ 'M': ('m', True), 'N': ('n', True), 'O': ('o', True), 'P': ('p', True),
68
+ 'Q': ('q', True), 'R': ('r', True), 'S': ('s', True), 'T': ('t', True),
69
+ 'U': ('u', True), 'V': ('v', True), 'W': ('w', True), 'X': ('x', True),
70
+ 'Y': ('y', True), 'Z': ('z', True),
71
+ '0': ('0', False), '1': ('1', False), '2': ('2', False), '3': ('3', False),
72
+ '4': ('4', False), '5': ('5', False), '6': ('6', False), '7': ('7', False),
73
+ '8': ('8', False), '9': ('9', False),
74
+ ' ': ('space', False), '\\t': ('tab', False), '\\n': ('enter', False),
75
+ '-': ('minus', False), '=': ('equal', False),
76
+ '[': ('leftbrace', False), ']': ('rightbrace', False),
77
+ ';': ('semicolon', False), "'": ('apostrophe', False),
78
+ '\`': ('grave', False), '\\\\': ('backslash', False),
79
+ ',': ('comma', False), '.': ('dot', False), '/': ('slash', False),
80
+ '!': ('1', True), '@': ('2', True), '#': ('3', True), '$': ('4', True),
81
+ '%': ('5', True), '^': ('6', True), '&': ('7', True), '*': ('8', True),
82
+ '(': ('9', True), ')': ('0', True),
83
+ '_': ('minus', True), '+': ('equal', True),
84
+ '{': ('leftbrace', True), '}': ('rightbrace', True),
85
+ ':': ('semicolon', True), '"': ('apostrophe', True),
86
+ '~': ('grave', True), '|': ('backslash', True),
87
+ '<': ('comma', True), '>': ('dot', True), '?': ('slash', True),
88
+ }
89
+
90
+ def setup_uinput_keyboard():
91
+ """Create a virtual keyboard device via /dev/uinput."""
92
+ uinput_fd = os.open('/dev/uinput', os.O_WRONLY | os.O_NONBLOCK)
93
+ # Enable EV_KEY and EV_REP event types
94
+ fcntl.ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY)
95
+ fcntl.ioctl(uinput_fd, UI_SET_EVBIT, EV_REP)
96
+ # Enable all keycodes in KEY_MAP
97
+ for keycode in KEY_MAP.values():
98
+ fcntl.ioctl(uinput_fd, UI_SET_KEYBIT, keycode)
99
+ # Write uinput_user_dev struct: 80-byte name + 1036 bytes of zeros = 1116 bytes
100
+ name = b'mcp-remotetouch-kbd'
101
+ dev_struct = name + b'\\x00' * (80 - len(name)) # name[80]
102
+ dev_struct += struct.pack('HH', 0x03, 0x01) # id: bustype=BUS_VIRTUAL, vendor
103
+ dev_struct += struct.pack('HH', 0x01, 0x01) # id: product, version
104
+ dev_struct += b'\\x00' * (1116 - len(dev_struct)) # ff_effects_max + absmin/max/fuzz/flat
105
+ os.write(uinput_fd, dev_struct)
106
+ fcntl.ioctl(uinput_fd, UI_DEV_CREATE)
107
+ time.sleep(0.2) # Wait for device to be registered
108
+ return uinput_fd
109
+
110
+ def destroy_uinput_keyboard(uinput_fd):
111
+ """Destroy the virtual keyboard device."""
112
+ try:
113
+ fcntl.ioctl(uinput_fd, UI_DEV_DESTROY)
114
+ except Exception:
115
+ pass
116
+ try:
117
+ os.close(uinput_fd)
118
+ except Exception:
119
+ pass
38
120
 
39
- UINPUT_MAX_NAME_SIZE = 80
121
+ def kbd_write_event(uinput_fd, ev_type, code, value):
122
+ """Write an input event to the uinput keyboard device."""
123
+ now = time.time()
124
+ sec = int(now)
125
+ usec = int((now - sec) * 1000000)
126
+ os.write(uinput_fd, struct.pack('llHHi', sec, usec, ev_type, code, value))
127
+
128
+ def kbd_syn(uinput_fd):
129
+ kbd_write_event(uinput_fd, EV_SYN, SYN_REPORT, 0)
130
+
131
+ def handle_key_press(uinput_fd, cmd):
132
+ """Handle key_press command: press a key with optional modifiers."""
133
+ key = cmd.get('key', '').lower()
134
+ modifiers = cmd.get('modifiers', [])
135
+ keycode = KEY_MAP.get(key)
136
+ if keycode is None:
137
+ raise ValueError('Unknown key: ' + cmd.get('key', ''))
138
+ # Press modifier keys
139
+ mod_codes = []
140
+ for mod in modifiers:
141
+ mc = KEY_MAP.get(mod.lower())
142
+ if mc is None:
143
+ raise ValueError('Unknown modifier: ' + mod)
144
+ mod_codes.append(mc)
145
+ kbd_write_event(uinput_fd, EV_KEY, mc, 1)
146
+ kbd_syn(uinput_fd)
147
+ # Press and release main key
148
+ kbd_write_event(uinput_fd, EV_KEY, keycode, 1)
149
+ kbd_syn(uinput_fd)
150
+ time.sleep(0.02)
151
+ kbd_write_event(uinput_fd, EV_KEY, keycode, 0)
152
+ kbd_syn(uinput_fd)
153
+ # Release modifiers in reverse order
154
+ for mc in reversed(mod_codes):
155
+ kbd_write_event(uinput_fd, EV_KEY, mc, 0)
156
+ kbd_syn(uinput_fd)
157
+
158
+ def handle_key_type(uinput_fd, cmd):
159
+ """Handle key_type command: type a string of text character by character."""
160
+ text = cmd.get('text', '')
161
+ shift_code = KEY_MAP['shift']
162
+ for ch in text:
163
+ entry = CHAR_MAP.get(ch)
164
+ if entry is None:
165
+ continue # Skip unmapped characters
166
+ key_name, needs_shift = entry
167
+ keycode = KEY_MAP[key_name]
168
+ if needs_shift:
169
+ kbd_write_event(uinput_fd, EV_KEY, shift_code, 1)
170
+ kbd_syn(uinput_fd)
171
+ kbd_write_event(uinput_fd, EV_KEY, keycode, 1)
172
+ kbd_syn(uinput_fd)
173
+ time.sleep(0.01)
174
+ kbd_write_event(uinput_fd, EV_KEY, keycode, 0)
175
+ kbd_syn(uinput_fd)
176
+ if needs_shift:
177
+ kbd_write_event(uinput_fd, EV_KEY, shift_code, 0)
178
+ kbd_syn(uinput_fd)
179
+ time.sleep(0.01)
180
+
181
+ # EVIOCGABS ioctl: _IOR('E', 0x40 + abs_code, struct input_absinfo)
182
+ # struct input_absinfo = 6 x __s32 = 24 bytes
183
+ # _IOR('E', N, 24) = (2 << 30) | (24 << 16) | (ord('E') << 8) | N
184
+ def EVIOCGABS(abs_code):
185
+ return (2 << 30) | (24 << 16) | (ord('E') << 8) | (0x40 + abs_code)
40
186
 
41
187
  def make_input_event(tv_sec, tv_usec, ev_type, code, value):
42
- # struct input_event uses struct timeval (long, long) + __u16 + __u16 + __s32
43
- # native long size handles 32/64 bit automatically
44
188
  return struct.pack('llHHi', tv_sec, tv_usec, ev_type, code, value)
45
189
 
46
190
  def write_event(fd, ev_type, code, value):
@@ -57,73 +201,149 @@ def touch_down(fd, slot, tracking_id, x, y):
57
201
  write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, tracking_id)
58
202
  write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)
59
203
  write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)
204
+ write_event(fd, EV_ABS, ABS_X, x)
205
+ write_event(fd, EV_ABS, ABS_Y, y)
206
+ write_event(fd, EV_KEY, BTN_TOUCH, 1)
60
207
  syn_report(fd)
61
208
 
62
209
  def touch_move(fd, slot, x, y):
63
210
  write_event(fd, EV_ABS, ABS_MT_SLOT, slot)
64
211
  write_event(fd, EV_ABS, ABS_MT_POSITION_X, x)
65
212
  write_event(fd, EV_ABS, ABS_MT_POSITION_Y, y)
213
+ write_event(fd, EV_ABS, ABS_X, x)
214
+ write_event(fd, EV_ABS, ABS_Y, y)
66
215
  syn_report(fd)
67
216
 
68
217
  def touch_up(fd, slot):
69
218
  write_event(fd, EV_ABS, ABS_MT_SLOT, slot)
70
219
  write_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1)
220
+ write_event(fd, EV_KEY, BTN_TOUCH, 0)
71
221
  syn_report(fd)
72
222
 
73
- def setup_uinput(screen_width, screen_height):
74
- fd = os.open('/dev/uinput', os.O_WRONLY | os.O_NONBLOCK)
75
-
76
- # Enable EV_ABS
77
- fcntl.ioctl(fd, UI_SET_EVBIT, EV_ABS)
78
-
79
- # Enable ABS axes
80
- fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT)
81
- fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID)
82
- fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X)
83
- fcntl.ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y)
84
-
85
- # Set INPUT_PROP_DIRECT for touchscreen
86
- fcntl.ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT)
87
-
88
- # Setup ABS axes with uinput_abs_setup
89
- # struct uinput_abs_setup { __u16 code; __u16 pad; struct input_absinfo { __s32 value, minimum, maximum, fuzz, flat, resolution; }; };
90
- abs_setup_fmt = 'HH6i'
91
-
92
- # ABS_MT_SLOT: 0 to 9
93
- data = struct.pack(abs_setup_fmt, ABS_MT_SLOT, 0, 0, 0, 9, 0, 0, 0)
94
- fcntl.ioctl(fd, UI_ABS_SETUP, data)
95
-
96
- # ABS_MT_TRACKING_ID: 0 to 65535
97
- data = struct.pack(abs_setup_fmt, ABS_MT_TRACKING_ID, 0, 0, 0, 65535, 0, 0, 0)
98
- fcntl.ioctl(fd, UI_ABS_SETUP, data)
99
-
100
- # ABS_MT_POSITION_X: 0 to screen_width - 1
101
- data = struct.pack(abs_setup_fmt, ABS_MT_POSITION_X, 0, 0, 0, screen_width - 1, 0, 0, 0)
102
- fcntl.ioctl(fd, UI_ABS_SETUP, data)
103
-
104
- # ABS_MT_POSITION_Y: 0 to screen_height - 1
105
- data = struct.pack(abs_setup_fmt, ABS_MT_POSITION_Y, 0, 0, 0, screen_height - 1, 0, 0, 0)
106
- fcntl.ioctl(fd, UI_ABS_SETUP, data)
107
-
108
- # uinput_setup: char name[UINPUT_MAX_NAME_SIZE]; struct input_id { __u16 bustype, vendor, product, version; };
109
- # struct input_id: HHH H (bustype=0x03 USB, vendor=0x1234, product=0x5678, version=1)
110
- # struct uinput_setup: 80s HHHH I (ff_effects_max)
111
- name = b'mcp-remotetouch'
112
- setup_data = struct.pack('80sHHHHI', name.ljust(UINPUT_MAX_NAME_SIZE, b'\\x00'), 0x03, 0x1234, 0x5678, 1, 0)
113
- fcntl.ioctl(fd, UI_DEV_SETUP, setup_data)
114
-
115
- # Create the device
116
- fcntl.ioctl(fd, UI_DEV_CREATE)
117
-
118
- # Give udev time to create the device node
119
- time.sleep(0.2)
223
+ def detect_screen_resolution():
224
+ """Detect screen resolution from framebuffer or DRM."""
225
+ # Try framebuffer first
226
+ try:
227
+ with open('/sys/class/graphics/fb0/virtual_size', 'r') as f:
228
+ parts = f.read().strip().split(',')
229
+ if len(parts) == 2:
230
+ return int(parts[0]), int(parts[1])
231
+ except Exception:
232
+ pass
233
+
234
+ # Try DRM
235
+ try:
236
+ import glob as g
237
+ for mode_path in g.glob('/sys/class/drm/*/modes'):
238
+ with open(mode_path, 'r') as f:
239
+ line = f.readline().strip()
240
+ if 'x' in line:
241
+ parts = line.split('x')
242
+ return int(parts[0]), int(parts[1])
243
+ except Exception:
244
+ pass
245
+
246
+ return None, None
247
+
248
+ def find_touchscreen():
249
+ """Find the physical touchscreen event device by scanning /proc/bus/input/devices."""
250
+ try:
251
+ with open('/proc/bus/input/devices', 'r') as f:
252
+ content = f.read()
253
+ except Exception:
254
+ return None
255
+
256
+ for block in content.split('\\n\\n'):
257
+ lines = block.strip().split('\\n')
258
+ name = ''
259
+ handlers = ''
260
+ props = ''
261
+ evbits = ''
262
+ absbits = ''
263
+ for line in lines:
264
+ if line.startswith('N: Name='):
265
+ name = line.split('=', 1)[1].strip('"')
266
+ elif line.startswith('H: Handlers='):
267
+ handlers = line.split('=', 1)[1]
268
+ elif line.startswith('B: PROP='):
269
+ props = line.split('=', 1)[1]
270
+ elif line.startswith('B: EV='):
271
+ evbits = line.split('=', 1)[1]
272
+ elif line.startswith('B: ABS='):
273
+ absbits = line.split('=', 1)[1]
274
+
275
+ # Skip virtual devices (mcp-remotetouch)
276
+ if 'mcp-remotetouch' in name:
277
+ continue
278
+
279
+ # Check for INPUT_PROP_DIRECT (bit 1 in PROP)
280
+ try:
281
+ prop_val = int(props.strip(), 16)
282
+ except (ValueError, IndexError):
283
+ prop_val = 0
284
+ if not (prop_val & 0x02):
285
+ continue
286
+
287
+ # Check that it has ABS_MT_POSITION_X (bit 0x35) in ABS bitmask
288
+ try:
289
+ abs_parts = absbits.strip().split()
290
+ abs_val = 0
291
+ for i, part in enumerate(reversed(abs_parts)):
292
+ abs_val |= int(part, 16) << (i * 32)
293
+ except (ValueError, IndexError):
294
+ abs_val = 0
295
+ if not (abs_val & (1 << ABS_MT_POSITION_X)):
296
+ continue
297
+
298
+ # Extract event device number
299
+ m = re.search(r'event(\\d+)', handlers)
300
+ if m:
301
+ return '/dev/input/event' + m.group(1)
302
+
303
+ return None
120
304
 
121
- return fd
305
+ import fcntl
122
306
 
123
- def send_response(cmd_id, status, message=None):
307
+ def get_abs_range(fd, abs_code):
308
+ """Get the min/max range of an ABS axis using EVIOCGABS ioctl."""
309
+ try:
310
+ buf = bytearray(24)
311
+ fcntl.ioctl(fd, EVIOCGABS(abs_code), buf)
312
+ value, minimum, maximum, fuzz, flat, resolution = struct.unpack('6i', buf)
313
+ return minimum, maximum
314
+ except Exception:
315
+ return None, None
316
+
317
+ def open_touch_device(screen_width, screen_height):
318
+ """Open the physical touchscreen device for event injection."""
319
+ dev_path = find_touchscreen()
320
+ if dev_path is None:
321
+ raise RuntimeError('No physical touchscreen device found')
322
+
323
+ fd = os.open(dev_path, os.O_WRONLY)
324
+
325
+ # Read the actual ABS ranges from the device
326
+ rd_fd = os.open(dev_path, os.O_RDONLY)
327
+ x_min, x_max = get_abs_range(rd_fd, ABS_MT_POSITION_X)
328
+ y_min, y_max = get_abs_range(rd_fd, ABS_MT_POSITION_Y)
329
+ os.close(rd_fd)
330
+
331
+ if x_max is None or y_max is None:
332
+ x_max = screen_width - 1
333
+ y_max = screen_height - 1
334
+ x_min = 0
335
+ y_min = 0
336
+
337
+ return fd, dev_path, x_min, x_max, y_min, y_max
338
+
339
+ def send_response(cmd_id, status, message=None, screen_width=None, screen_height=None):
124
340
  resp = {'id': cmd_id, 'status': status}
125
341
  if message is not None:
126
342
  resp['message'] = message
343
+ if screen_width is not None:
344
+ resp['screen_width'] = screen_width
345
+ if screen_height is not None:
346
+ resp['screen_height'] = screen_height
127
347
  sys.stdout.write(json.dumps(resp) + '\\n')
128
348
  sys.stdout.flush()
129
349
 
@@ -134,9 +354,25 @@ def next_tracking_id():
134
354
  tracking_id_counter = (tracking_id_counter + 1) % 65536
135
355
  return tracking_id_counter
136
356
 
357
+ # Coordinate mapping globals
358
+ dev_x_min = 0
359
+ dev_x_max = 0
360
+ dev_y_min = 0
361
+ dev_y_max = 0
362
+ scr_w = 0
363
+ scr_h = 0
364
+
365
+ def map_x(x):
366
+ """Map screen coordinate to device coordinate."""
367
+ return dev_x_min + int(x * (dev_x_max - dev_x_min) / (scr_w - 1))
368
+
369
+ def map_y(y):
370
+ """Map screen coordinate to device coordinate."""
371
+ return dev_y_min + int(y * (dev_y_max - dev_y_min) / (scr_h - 1))
372
+
137
373
  def handle_tap(fd, cmd):
138
- x = int(cmd['x'])
139
- y = int(cmd['y'])
374
+ x = map_x(int(cmd['x']))
375
+ y = map_y(int(cmd['y']))
140
376
  duration_ms = cmd.get('duration_ms', 50)
141
377
  tid = next_tracking_id()
142
378
  touch_down(fd, 0, tid, x, y)
@@ -152,18 +388,18 @@ def handle_swipe(fd, cmd):
152
388
  steps = cmd.get('steps', max(int(duration_ms / 15), 2))
153
389
  tid = next_tracking_id()
154
390
 
155
- touch_down(fd, 0, tid, x1, y1)
391
+ touch_down(fd, 0, tid, map_x(x1), map_y(y1))
156
392
  for i in range(1, steps + 1):
157
393
  t = i / steps
158
394
  cx = int(x1 + (x2 - x1) * t)
159
395
  cy = int(y1 + (y2 - y1) * t)
160
396
  time.sleep(duration_ms / 1000.0 / steps)
161
- touch_move(fd, 0, cx, cy)
397
+ touch_move(fd, 0, map_x(cx), map_y(cy))
162
398
  touch_up(fd, 0)
163
399
 
164
400
  def handle_long_press(fd, cmd):
165
- x = int(cmd['x'])
166
- y = int(cmd['y'])
401
+ x = map_x(int(cmd['x']))
402
+ y = map_y(int(cmd['y']))
167
403
  duration_ms = cmd.get('duration_ms', 800)
168
404
  tid = next_tracking_id()
169
405
  touch_down(fd, 0, tid, x, y)
@@ -171,8 +407,8 @@ def handle_long_press(fd, cmd):
171
407
  touch_up(fd, 0)
172
408
 
173
409
  def handle_double_tap(fd, cmd):
174
- x = int(cmd['x'])
175
- y = int(cmd['y'])
410
+ x = map_x(int(cmd['x']))
411
+ y = map_y(int(cmd['y']))
176
412
  tid = next_tracking_id()
177
413
  touch_down(fd, 0, tid, x, y)
178
414
  time.sleep(0.05)
@@ -184,7 +420,9 @@ def handle_double_tap(fd, cmd):
184
420
  touch_up(fd, 0)
185
421
 
186
422
  def main():
423
+ global dev_x_min, dev_x_max, dev_y_min, dev_y_max, scr_w, scr_h
187
424
  fd = None
425
+ kbd_fd = None
188
426
  try:
189
427
  for line in sys.stdin:
190
428
  line = line.strip()
@@ -201,10 +439,25 @@ def main():
201
439
 
202
440
  try:
203
441
  if cmd_type == 'init':
204
- screen_width = cmd.get('screen_width', 800)
205
- screen_height = cmd.get('screen_height', 480)
206
- fd = setup_uinput(screen_width, screen_height)
207
- send_response(cmd_id, 'ready', 'uinput device created')
442
+ scr_w = cmd.get('screen_width', 0)
443
+ scr_h = cmd.get('screen_height', 0)
444
+ if scr_w <= 0 or scr_h <= 0:
445
+ det_w, det_h = detect_screen_resolution()
446
+ if det_w and det_h:
447
+ scr_w = det_w
448
+ scr_h = det_h
449
+ else:
450
+ scr_w = scr_w or 800
451
+ scr_h = scr_h or 480
452
+ fd, dev_path, dev_x_min, dev_x_max, dev_y_min, dev_y_max = open_touch_device(scr_w, scr_h)
453
+ # Best-effort keyboard setup — touch works even if uinput fails
454
+ try:
455
+ kbd_fd = setup_uinput_keyboard()
456
+ kbd_msg = ' (keyboard: ok)'
457
+ except Exception as ke:
458
+ kbd_fd = None
459
+ kbd_msg = ' (keyboard: unavailable - ' + str(ke) + ')'
460
+ send_response(cmd_id, 'ready', 'injecting into ' + dev_path + kbd_msg, scr_w, scr_h)
208
461
  elif cmd_type == 'shutdown':
209
462
  send_response(cmd_id, 'ok', 'shutting down')
210
463
  break
@@ -222,16 +475,29 @@ def main():
222
475
  elif cmd_type == 'double_tap':
223
476
  handle_double_tap(fd, cmd)
224
477
  send_response(cmd_id, 'ok')
478
+ elif cmd_type == 'key_press':
479
+ if kbd_fd is None:
480
+ send_response(cmd_id, 'error', 'keyboard not available: /dev/uinput not accessible')
481
+ else:
482
+ handle_key_press(kbd_fd, cmd)
483
+ send_response(cmd_id, 'ok')
484
+ elif cmd_type == 'key_type':
485
+ if kbd_fd is None:
486
+ send_response(cmd_id, 'error', 'keyboard not available: /dev/uinput not accessible')
487
+ else:
488
+ handle_key_type(kbd_fd, cmd)
489
+ send_response(cmd_id, 'ok')
225
490
  else:
226
491
  send_response(cmd_id, 'error', 'unknown command: ' + cmd_type)
227
492
  except PermissionError:
228
- send_response(cmd_id, 'error', 'Permission denied accessing /dev/uinput. Ensure user is in the input group: sudo usermod -aG input $USER')
493
+ send_response(cmd_id, 'error', 'Permission denied. Run with sudo or ensure user is in the input group: sudo usermod -aG input $USER')
229
494
  except Exception as e:
230
495
  send_response(cmd_id, 'error', str(e))
231
496
  finally:
497
+ if kbd_fd is not None:
498
+ destroy_uinput_keyboard(kbd_fd)
232
499
  if fd is not None:
233
500
  try:
234
- fcntl.ioctl(fd, UI_DEV_DESTROY)
235
501
  os.close(fd)
236
502
  except Exception:
237
503
  pass
@@ -1 +1 @@
1
- {"version":3,"file":"python-daemon.js","sourceRoot":"","sources":["../src/python-daemon.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgPnC,CAAC"}
1
+ {"version":3,"file":"python-daemon.js","sourceRoot":"","sources":["../src/python-daemon.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0fnC,CAAC"}
@@ -16,8 +16,7 @@ export class SshTouchSessionManager {
16
16
  pending: null,
17
17
  };
18
18
  this.sessions.set(sessionId, session);
19
- const scriptBase64 = Buffer.from(PYTHON_DAEMON_SCRIPT).toString("base64");
20
- const pythonCmd = `python3 -u -c "import base64,sys;exec(base64.b64decode(sys.argv[1]))" "${scriptBase64}"`;
19
+ const pythonCmd = `python3 -u -c "import sys,base64;exec(base64.b64decode(input()))"`;
21
20
  const remoteCmd = config.useSudo ? `sudo ${pythonCmd}` : pythonCmd;
22
21
  const sshArgs = [
23
22
  "-T",
@@ -35,6 +34,9 @@ export class SshTouchSessionManager {
35
34
  stdio: ["pipe", "pipe", "pipe"],
36
35
  });
37
36
  session.process = proc;
37
+ // Send the daemon script via stdin to avoid ARG_MAX limits on embedded systems
38
+ const scriptBase64 = Buffer.from(PYTHON_DAEMON_SCRIPT).toString("base64");
39
+ proc.stdin.write(scriptBase64 + "\n");
38
40
  const rl = createInterface({ input: proc.stdout });
39
41
  rl.on("line", (line) => {
40
42
  let resp;
@@ -83,6 +85,13 @@ export class SshTouchSessionManager {
83
85
  this.cleanup(session);
84
86
  throw new Error(`Daemon init failed: ${resp.message}`);
85
87
  }
88
+ // Update config with daemon-detected screen resolution
89
+ if (resp.screen_width) {
90
+ session.config.screenWidth = resp.screen_width;
91
+ }
92
+ if (resp.screen_height) {
93
+ session.config.screenHeight = resp.screen_height;
94
+ }
86
95
  session.active = true;
87
96
  }
88
97
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"ssh-touch-session.js","sourceRoot":"","sources":["../src/ssh-touch-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ssh-touch-session.js","sourceRoot":"","sources":["../src/ssh-touch-session.ts"],"names":[],"mappings":"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"}
package/build/types.d.ts CHANGED
@@ -4,8 +4,8 @@ export interface SessionConfig {
4
4
  user: string;
5
5
  port: number;
6
6
  sshKey?: string;
7
- screenWidth: number;
8
- screenHeight: number;
7
+ screenWidth?: number;
8
+ screenHeight?: number;
9
9
  useSudo: boolean;
10
10
  }
11
11
  export interface TouchSession {
@@ -18,7 +18,7 @@ export interface TouchSession {
18
18
  reject: (reason: Error) => void;
19
19
  } | null;
20
20
  }
21
- export type DaemonCommandType = "init" | "tap" | "swipe" | "long_press" | "double_tap" | "shutdown";
21
+ export type DaemonCommandType = "init" | "tap" | "swipe" | "long_press" | "double_tap" | "key_press" | "key_type" | "shutdown";
22
22
  export interface DaemonCommand {
23
23
  id: string;
24
24
  type: DaemonCommandType;
@@ -30,9 +30,14 @@ export interface DaemonCommand {
30
30
  steps?: number;
31
31
  screen_width?: number;
32
32
  screen_height?: number;
33
+ key?: string;
34
+ modifiers?: string[];
35
+ text?: string;
33
36
  }
34
37
  export interface DaemonResponse {
35
38
  id: string;
36
39
  status: "ok" | "error" | "ready";
37
40
  message?: string;
41
+ screen_width?: number;
42
+ screen_height?: number;
38
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-remotetouch",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for remote touch input via SSH to any Linux device",
5
5
  "type": "module",
6
6
  "main": "build/index.js",