Use your phone's voice dictation to type into any app on your Ubuntu/Linux desktop.
Phone keyboards have excellent voice-to-text engines (Google, Apple, Samsung) that are far better than anything available natively on Linux desktops. This tool bridges the gap: it runs a tiny web server on your computer, you open it on your phone, dictate text, and it gets injected into whatever app is focused on your desktop.
No app install needed on the phone — just a browser.
Phone browser ──HTTP POST──> Python (Flask) ──> ydotool type / wl-copy
│
Prints QR code
+ secret token URL
on startup
- The script starts a Flask web server on your LAN IP
- A URL with a random security token is printed as a QR code in the terminal
- Scan the QR code with your phone to open the mobile web UI
- Type or dictate text, tap SEND
- The text is injected into your focused desktop app
| Component | Role |
|---|---|
| Python 3 / Flask | Lightweight HTTP server serving the mobile UI and receiving text |
| qrcode (Python) | Generates a scannable QR code in the terminal at startup |
| ydotool | Simulates keystrokes via /dev/uinput (works on Wayland + X11) |
wl-clipboard (wl-copy) |
Copies text to the Wayland clipboard (clipboard method) |
| ydotoold | Daemon required by ydotool, needs access to /dev/uinput |
# System dependencies
sudo apt install ydotool wl-clipboard python3.12-venv
# Clone and set up
git clone <repo-url> && cd linux-input-from-web
python3 -m venv venv
venv/bin/pip install flask qrcode
# Run
./run.shsudo apt install ./input-from-web_0.1.0_all.deb
input-from-websudo apt install debhelper dh-python
dpkg-buildpackage -us -uc -b
# Package is created in the parent directory./run.sh [OPTIONS]
| Flag | Description |
|---|---|
--method type |
Simulate keystrokes via ydotool (default) |
--method clipboard |
Copy to clipboard via wl-copy, you paste manually |
--port PORT |
TCP port to listen on (default: 5123) |
--profile NAME |
Use a named profile from the config file |
--permanent-link |
Reuse a stored token across sessions (see below) |
--permanent-link-refresh |
Replace the stored permanent token with a new one |
./run.sh # defaults (type method, port 5123)
./run.sh --method clipboard # clipboard only, you paste with Ctrl+Shift+V
./run.sh --port 8080 # listen on port 8080
./run.sh --profile work # use the "work" profile from configOn first run, a config file is created at ~/.input-from-web-conf.json with
a default profile. You can add more profiles and switch between them.
| Field | Type | Default | Description |
|---|---|---|---|
method |
"type" or "clipboard" |
"type" |
Input injection method. Overridden by --method |
auto_paste |
boolean | false |
After clipboard copy, simulate Ctrl+V via ydotool. Only applies to clipboard method. Useful for GUI apps, not terminals |
port |
integer | 5123 |
TCP port. Overridden by --port |
use_security_token |
boolean | true |
Require secret token in URL. Only disable on trusted networks |
voice_send |
object | (see below) | Voice command auto-trigger settings |
substitutions |
object | (see below) | Word/phrase replacement map |
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable voice command detection |
delay_seconds |
number | 1.5 |
Seconds to wait after last edit before triggering |
send_words |
string[] | ["send"] |
Words that trigger auto-send when typed last |
clear_words |
string[] | ["clear"] |
Words that trigger auto-clear when typed last |
When dictating, say "send" at the end of your text. If no further edits happen for 1.5 seconds, the text (minus the command word) is automatically sent.
Phrases are replaced in real-time as you type. Useful for voice dictation where you say punctuation names out loud.
Default substitutions:
| Phrase | Replacement |
|---|---|
full stop |
. |
question mark |
? |
exclamation mark |
! |
comma |
, |
colon |
: |
semicolon |
; |
quote |
" |
new line |
newline |
new paragraph |
double newline |
{
"default_profile": "default",
"profiles": {
"default": {
"method": "type",
"port": 5123,
"use_security_token": true,
"voice_send": {
"enabled": true,
"delay_seconds": 1.5,
"send_words": ["send"],
"clear_words": ["clear"]
},
"substitutions": {
"full stop": ".",
"question mark": "?"
}
},
"quick": {
"method": "clipboard",
"port": 8080,
"use_security_token": false,
"voice_send": { "enabled": false },
"substitutions": {}
}
}
}By default, a new random token is generated each time the server starts, meaning
you need to re-scan the QR code every session. With --permanent-link, the token
is saved to the config file and reused across restarts.
./run.sh --permanent-linkOn first run, the QR code includes the token. Scan it with your phone — the token is saved to your browser's localStorage. From now on, the phone remembers the token automatically.
./run.sh --permanent-linkThe QR code now shows a clean URL (no token) — shorter and bookmarkable. Your phone loads the token from localStorage. The setup URL with the token is still printed in the terminal in case you need it on a new device.
./run.sh --permanent-link-refreshReplaces the stored token with a new one. The QR code includes the new token so you can scan it again. Use this if you suspect the token has been compromised.
The app includes a web app manifest, so you can install it on your phone's home screen for quicker access.
- Open the link from the QR code in Chrome
- Tap the three-dot menu (top right)
- Tap "Add to Home screen" or "Install app"
- Launch from the home screen icon
- Open the link from the QR code in Safari
- Tap the Share button (bottom center)
- Tap "Add to Home Screen"
- Launch from the home screen icon
- The token is stored in your browser's localStorage, so the installed app
continues to work across server restarts when using
--permanent-link. - Chrome requires HTTPS for full standalone PWA mode (no address bar). On a plain HTTP LAN setup, the app will work but may show a minimal browser bar. This does not affect functionality.
This tool is designed for use on a trusted home/private network only.
The server runs over plain HTTP (not HTTPS). This means all traffic — including the security token — is transmitted unencrypted. Anyone on the same network could intercept the token by sniffing traffic and then send arbitrary keystrokes to your machine.
The token provides basic protection against casual unauthorized access, but it is not a substitute for network-level security. Do not run this tool on public or untrusted networks (coffee shops, hotels, shared offices, etc.).
Setting use_security_token to false removes even this basic protection.
A red warning is printed at startup. Only do this on a network you fully control.
- Ubuntu 24.04+ (or any Linux with Wayland)
- Python 3.12+
- ydotool + ydotoold (for keystroke injection)
- wl-clipboard (for clipboard method)
- Phone and computer on the same local network