mcp-remotetouch 0.1.1 → 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
- Injects tap, swipe, long press, and double tap events directly into the physical touchscreen device. The daemon auto-detects the touchscreen and screen resolution. **No installation required on the remote device** — the Python daemon is sent via stdin over SSH, 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
 
@@ -18,6 +18,8 @@ Dev Machine Remote Linux Device
18
18
  │ touch_swipe │ │ touchscreen │
19
19
  │ touch_long_press │ │ ↓ │
20
20
  │ touch_double_tap │ │ /dev/input/eventN│
21
+ │ key_press │ │ ↓ │
22
+ │ key_type │ │ /dev/uinput (kbd)│
21
23
  │ touch_disconnect │ │ ↓ │
22
24
  │ │ │ Linux Input │
23
25
  └──────────────────┘ └──────────────────┘
@@ -49,6 +51,7 @@ AI Agent (remote) ──HTTP/SSE──> Express + StreamableHTTPServerTransport
49
51
  - Any Linux device with a touchscreen (Raspberry Pi, SBC, embedded system, etc.)
50
52
  - Python 3
51
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)
52
55
 
53
56
  Add the user to the `input` group on the remote device:
54
57
 
@@ -162,6 +165,25 @@ Double tap at the given coordinates.
162
165
  | `x` | number | X coordinate |
163
166
  | `y` | number | Y coordinate |
164
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
+
165
187
  ### `touch_disconnect`
166
188
 
167
189
  Disconnect a session and clean up the remote daemon.
@@ -205,7 +227,8 @@ A typical session from Claude Desktop:
205
227
 
206
228
  1. `touch_connect` — connect to the remote device
207
229
  2. `touch_tap` / `touch_swipe` / `touch_long_press` / `touch_double_tap` — interact with the screen
208
- 3. `touch_disconnect` — end the session
230
+ 3. `key_press` / `key_type` send keyboard input
231
+ 4. `touch_disconnect` — end the session
209
232
 
210
233
  ## Troubleshooting
211
234
 
@@ -223,6 +246,20 @@ The daemon could not find a touchscreen in `/proc/bus/input/devices`. Verify:
223
246
  - The device has a touchscreen connected and its driver is loaded
224
247
  - The device shows `INPUT_PROP_DIRECT` and has `ABS_MT_POSITION_X` capability
225
248
 
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`
260
+
261
+ Touch tools continue to work even if `/dev/uinput` is not accessible.
262
+
226
263
  ### SSH connection fails
227
264
 
228
265
  - Ensure SSH public key authentication is configured for the remote device (password authentication is not supported since the connection uses `BatchMode=yes`)
package/build/index.js CHANGED
@@ -24,7 +24,7 @@ function defaultConfig(overrides = {}) {
24
24
  function createServer(manager) {
25
25
  const server = new McpServer({
26
26
  name: "mcp-remotetouch",
27
- version: "0.1.0",
27
+ version: "0.2.0",
28
28
  });
29
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.", {
30
30
  host: z.string().optional().describe("SSH host (default: env REMOTETOUCH_SSH_HOST)"),
@@ -166,6 +166,50 @@ function createServer(manager) {
166
166
  return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
167
167
  }
168
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
+ });
169
213
  server.tool("touch_disconnect", "Disconnect a touch session and clean up the remote daemon.", {
170
214
  sessionId: z.string().describe("Session ID to disconnect"),
171
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 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# 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 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 send_response(cmd_id, 'ready', 'injecting into ' + dev_path, 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 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 fd is not None:\n try:\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";
@@ -26,6 +26,158 @@ ABS_MT_TRACKING_ID = 0x39
26
26
  ABS_MT_POSITION_X = 0x35
27
27
  ABS_MT_POSITION_Y = 0x36
28
28
 
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
120
+
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
+
29
181
  # EVIOCGABS ioctl: _IOR('E', 0x40 + abs_code, struct input_absinfo)
30
182
  # struct input_absinfo = 6 x __s32 = 24 bytes
31
183
  # _IOR('E', N, 24) = (2 << 30) | (24 << 16) | (ord('E') << 8) | N
@@ -270,6 +422,7 @@ def handle_double_tap(fd, cmd):
270
422
  def main():
271
423
  global dev_x_min, dev_x_max, dev_y_min, dev_y_max, scr_w, scr_h
272
424
  fd = None
425
+ kbd_fd = None
273
426
  try:
274
427
  for line in sys.stdin:
275
428
  line = line.strip()
@@ -297,7 +450,14 @@ def main():
297
450
  scr_w = scr_w or 800
298
451
  scr_h = scr_h or 480
299
452
  fd, dev_path, dev_x_min, dev_x_max, dev_y_min, dev_y_max = open_touch_device(scr_w, scr_h)
300
- send_response(cmd_id, 'ready', 'injecting into ' + dev_path, 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)
301
461
  elif cmd_type == 'shutdown':
302
462
  send_response(cmd_id, 'ok', 'shutting down')
303
463
  break
@@ -315,6 +475,18 @@ def main():
315
475
  elif cmd_type == 'double_tap':
316
476
  handle_double_tap(fd, cmd)
317
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')
318
490
  else:
319
491
  send_response(cmd_id, 'error', 'unknown command: ' + cmd_type)
320
492
  except PermissionError:
@@ -322,6 +494,8 @@ def main():
322
494
  except Exception as e:
323
495
  send_response(cmd_id, 'error', str(e))
324
496
  finally:
497
+ if kbd_fd is not None:
498
+ destroy_uinput_keyboard(kbd_fd)
325
499
  if fd is not None:
326
500
  try:
327
501
  os.close(fd)
@@ -1 +1 @@
1
- {"version":3,"file":"python-daemon.js","sourceRoot":"","sources":["../src/python-daemon.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4UnC,CAAC"}
1
+ {"version":3,"file":"python-daemon.js","sourceRoot":"","sources":["../src/python-daemon.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0fnC,CAAC"}
package/build/types.d.ts CHANGED
@@ -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,6 +30,9 @@ 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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-remotetouch",
3
- "version": "0.1.1",
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",