input text
會改變裝置把一段字串打進目前取得焦點的輸入欄位。
- 指令
- adb shell input text
- 指令
- 輸入與觸控
- 風險
- 會改變裝置
語法
input text <string>範例
input text 'hello world'記得加引號。單引號裡面 shell 什麼都不會動。
input text 'user@example.com'用真正的鍵盤而不是手機鍵盤來填登入欄位。
input keyevent 66之後補一個 Enter,因為 `input text` 不會打出換行。
輸出怎麼讀
什麼都沒有。字會出現在手機上,或不會出現——兩種都沒有回報,所以請看著螢幕。
輸出欄位
| 欄位 | 意義 |
|---|---|
| (no output) | 指令執行了。字有沒有進去,只有手機螢幕看得出來。 |
需要什麼權限
只要一條已授權的 `adb` 連線就夠了——不用 root、不用 `adb root`、不用 `su`,開發者選項裡除了 USB 偵錯本身也沒有東西要打開。`input` 是一行的 shell 腳本,跑的是 `cmd input "$@"`(AOSP 的 `cmds/input/input.sh`),所以字元是以 `shell` 使用者的身分注入的,而撐在後面的平台權限是 `android.permission.INJECT_EVENTS`,`com.android.shell` 在自己的資訊清單裡就有。這個授權刻意沒有給你的,是「瞄準」的能力。`runText` 只接受一個輸入來源、一個可選的 `-d <displayId>` 和那個字串,沒有別的——沒有任何參數能指名目標 app、activity 或欄位——所以字元會落在那個顯示器上、那一瞬間剛好有焦點的地方。因此在腳本裡,節奏與順序遠比存取權重要:一個在你沒看著的時候跳出來的對話框,是一個完全合法、可以讓你的密碼被打進去的地方。而且沒有任何確認可以等。`sendText` 把每個事件交給注入器之後就不再看結果,所以指令結束時並不知道下游有沒有收下任何一次按鍵;唯一誠實的確認是 `screencap`。
失敗訊息對照
| 訊息 | 意義 |
|---|---|
| java.lang.IllegalArgumentException: Argument expected after "text" | `runText` 要一個必填參數而它沒拿到,所以 `input text` 後面什麼都不接就會丟例外。這一行會出現在 `Exception occurred while executing 'text':` 這段標題底下,帶著堆疊,全部走 stderr。要注意它「不是」什麼:它不是空字串。`input text ''` 是一個合法、有加引號的空參數,它會安靜地什麼都不做。 |
| Exception occurred while executing 'text': | shell 指令處理器接到一個 `Throwable`,標題的下一行會說出它是誰。非 ASCII 的情況就結束在這裡:`KeyCharacterMap.getEvents` 的文件寫明,當目前的按鍵字元對應表產不出那串字元時它會回傳 null,而這一頁查過的原始碼直接走訪 `events.length`、沒有檢查 null,所以含 `é` 或中日文的字串會丟 `NullPointerException`,而不是打出其中一部分。有回報說舊版失敗得更安靜——見下面的注意事項——這正是這一頁寧可一開始就拒絕非 ASCII,也不去試的原因。 |
| Error: Invalid arguments for display ID. | `-d` 拿到的東西不是整數,也不是 `DEFAULT_DISPLAY` 或 `INVALID_DISPLAY`。它是在解析階段丟出來的,在送出任何一個字元之前,所以什麼都沒打。要看的是 `-d` 後面那個 token,不是你的字串。 |
| cmd: Can't find service: input | `cmd` 找不到 `input` 服務可以把子指令交出去,因為 `input.sh` 只是 `cmd input` 的包裝。裝置還在開機、`system_server` 還沒登記它的時候,這是預期中的——和 `settings` 與 `window` 服務在同一時刻給的失敗長得一樣。 |
會改變什麼,以及怎麼回頭
裝置上不會有東西被刪掉,但打出去的字會送給當下取得焦點的任何東西:聊天訊息、搜尋框、登入或密碼欄位,或是你上次看螢幕之後才跳出來的確認對話框。一旦被送出就收不回來。還沒送出的話,`input keyevent 67`(Delete)可以一個字一個字刪掉;送出表單的是 `input keyevent 66`(Enter)。輸入前先看一眼螢幕,也不要把你不想留在欄位裡的機密打進去。
版本與廠商注意事項
- 只吃 ASCII,而這是平台指令的限制,不是纜線或 shell 的限制:`input text` 最後會走到一張只有可列印 ASCII 按鍵的虛擬鍵盤字元對應表,所以中文、日文與帶重音的字母根本不會產生任何按鍵事件。桌面版 adb 一樣打不出來。
- 參數裡的 `%s` 會被 `input` 自己在鍵盤看到它之前變成一個空白,而且沒有跳脫方式——`%%s` 會變成一個百分號加一個空白。請把字串切開,讓 `%` 與 `s` 不會在同一次呼叫裡相鄰。
- 單引號帶不了單引號本身。請在那裡把字串切開,用 `input keyevent 75` 送出那個單引號;`'\''` 那種花招正是那種寫對一次、之後被抄錯的東西。
- 參數加了引號之後空白不需要 `%s`:shell 會把空白保留在同一個詞裡,鍵盤再把它對應到空白鍵。
這個我們有 UI
Android ADB Toolbox 會透過 USB 執行這個指令並解析回應——只要 Chromium 系瀏覽器,不必安裝 SDK,也不會上傳任何東西。
相關指令
和 input text 會在同一次作業裡出現的指令。
| 指令 | 做什麼 |
|---|---|
| input keyevent | 按下實體或虛擬按鍵——Home、Back、電源、音量、Enter。 |
| getevent | 直接從核心串流原始輸入事件,或列出每個輸入裝置能回報什麼。 |
| am start | 用元件或 intent 啟動 Activity——這是驗證 deep link 能不能被接走最快的方法。 |
這些行為是在撰寫 Web ADB 工具背後的解析程式時,對照 AOSP、toybox 與核心原始碼查證的。真的會因 Android 版本或廠牌而異的地方,這一頁會直接說明,而不是給你一個在半數手機上都是錯的數字。