不想離開沙發,只好自己寫一個電腦遙控器了

今天這篇文沒有什麼太高深的技術,只是想跟大家分享一下我的 Side Project 的實作過程,放輕鬆看就好了~

事情是這樣的,筆者我身為一個專業的沙發馬鈴薯,在家時常常會把電腦螢幕投影到電視上,不管是追劇、上 Youtube 還是看線上課程,通通都是躺在沙發上看,邊看邊想著「人生至樂,莫過於此」

但問題來了,有時看到一半會突然有訊息需要回,或是線上課程上到一半聽到不懂的東西會想查一下,那就得先 離開沙發 走到電腦前把影片暫停,等事情忙完再繼續

因此,我決定做一個電腦遙控器,讓我可以坐在沙發上用手機遙控電腦。而今天文章的內容,就是講我這個電腦遙控器的進化史XD

先上 Demo

這是最後完成的電腦遙控器,螢幕是電視的畫面、右上角的小視窗則是我手機的

一開始我會先啟動 API server,手機掃了 QRCode 之後,就可以開始用手機操作電腦了,不論是 暫停、播放、快轉、調大小聲 都可以躺在沙發上用手機操作超爽 der

看完 Demo 接著就是實作時間了~其實難度不高,應該大家都能看懂

初代電腦遙控器 Ver 1.0

因為 Youtube 可以按 空白鍵 暫停/繼續 播放影片,所以我一開始只有想著怎麼用手機操控電腦按空白鍵。循著這個念頭,我找到 robotjs 這個 library,他讓我可以透過 Node.js 來操作鍵盤

RobotJS

那手機該怎麼跟電腦溝通呢?簡單,在電腦上架一個 server 就好了!這邊我用 Express 在我的電腦上架一個 HTTP server,當 server 收到來自前端網頁的請求之後,就幫我按下空白鍵,簡單粗暴,幾行扣就搞定了

用 Express 架的 API server

前端頁面則是長這樣,其實就是個很醜的標題跟按鈕而已XD。當我躺在沙發上用手機按下按鈕時,前端會用 Axios 發一個請求到後端,電腦就會幫我按下空白鍵,好開心~

只有 開始/暫停 按鈕的遙控器

電腦遙控器 Ver 1.1

用了幾天之後,我發現只有空白鍵根本不夠用啊!有時候想跳過片頭所以 需要快轉、或是有時老師講太快我 想倒轉回去 再聽一次,那我就又要 起身回到電腦前,調整完再躺回沙發,這未免也太麻煩,怎麼能夠容許這種事發生呢???

於是我又在後端新增了兩隻 API 用來按左鍵右鍵,真的覺得 robotjs 用起來很直覺,寫起來輕輕鬆鬆

新增了按左右鍵的 API

前端部分也是加兩個按鈕,寫法跟先前的空白鍵一樣,這樣就可以躺在沙發上快轉、倒轉囉~

加上左右鍵的前端頁面

電腦遙控器 Ver 1.2

就這樣用了一陣子,又開始覺得不太好用(這人毛怎麼這麼多)。因為片頭曲通常有一分多鐘,但 Youtube 每次按右鍵只會前進五秒,所以要跳過片頭曲的話就得一直點右鍵按鈕,點到手很痠

為了解決這問題,我開始想怎麼讓左右鍵支援按住的功能,只要我一直按著,他就會一直往前快轉,不用一直點一直點

說到要連續觸發某個事件,我馬上就想到處理 非同步、長時間事件流 的強大 library — RxJS

下圖是前端的程式碼,一開始宣告的 leftDownleftUprightDownrightUp 四個變數分別對應到左按鈕跟右按鈕的 touchstarttouchend 事件。接著在每次 touchstart 觸發時開始計時,每 350 毫秒發送一個請求,就這樣一直到 touchend 事件發生

如果把整個流程畫成 RxJS 的彈珠圖的話,每次 touchstart 發生時都會開一個新的分支,在那個分支上每 350 ms 會發送一次請求,而 touchend 發生時則是把分支結束掉,這樣按住按鈕的期間就可以不斷發送請求。

前端 RxJS 流程圖

電腦遙控器 Ver 2.0

就這樣又開心用了一陣子,邊用邊想著電腦遙控器真的好方便啊,結果有一天他就突然爆開了,執行 node index.js 時噴出了奇怪的錯誤訊息

啟動 server 時爆開了

啊原來是我把 Node 更新到 14 的關係,因為 robotjs 牽涉到比較底層的操作,大部分的扣都是 C/C++ 寫成的(下圖),當時還沒支援最新的 Node 版本,所以啟動時就爆了,我自己跑 npm rebuild 也是跑不起來

robotjs language

雖然只要降回 Node 12 就可以恢復正常,但我其他專案已經開始用 Node 14 才支援的 Optional Chaining,所以我決定打掉重練,直接換到編譯式語言,這樣只要 編譯完生出執行檔就可以一直用,不會像 Node 受到 runtime 版本的影響

就這樣我查到一個 Rust 的 library 叫 Enigo,原以為他應該也有很大一部分是用 C/C++ 寫的,但想不到 100% 都是 Rust,加上他的範例看起來也很簡單,所以就直接用了XD

Enigo language

下圖是我用 Rust 的框架 Actix Web 寫出來的 HTTP server,左邊是程式的進入點 main(),定義了有哪些 endpoint 並且監聽 port 3000;右邊則是各個 endpoint 的實作,分別是按空白鍵、左鍵、右鍵,有 Enigo 的幫忙寫起來超簡單

另外,因為我覺得原本的 UI 滿醜的,所以在這個版本我也順便用上 Semantic UI 的按鈕跟圖示,把前端做得漂亮一點

用 Semantic UI 做的前端頁面

這個 2.0 版本沒有增加任何功能,就是把後端改成用 Rust 寫,然後美化一下前端而已XD

電腦遙控器 Ver 2.1

換到 Rust 後,我就開始想怎麼讓手機更快連到電腦的 server,因為我在啟動 server 前都要先查電腦在內網的 IP,假如得到 192.168.31.142,那我的手機才能用 192.168.31.142:3000 連到遙控器,但因為 IP 位址並不固定,所以每次都要手動查很麻煩。

就在某一天我洗澡時,我的腦袋突然靈光一閃:「可以直接讓手機掃 QRCode 啊!」

於是我用 local_ip 來取得目前我的內網 IP,取得後再用 qr2term 把 IP 位址轉成 QRCode 輸出在終端機上。這樣電腦上的 server 啟動時,我就可以直接掃 QRCode 連到我的電腦遙控器了~

有 QRCode 可以掃囉

掃上面這個 QRCode 真的可以連到 192.168.31.142:3000 哦~

電腦遙控器 Ver 2.2

用著用著,某一天我又突然想到(到底哪來這麼多想到?),是不是可以加個 調整音量 的功能。因為我常常放著電腦播音樂,然後就坐到沙發上看書,如果看了一會覺得音樂太大聲就又要到電腦前調整,真的很煩

但 Mac 鍵盤上的 F1 到 F12 是有特殊功能的按鍵,如果直接叫 Enigo 幫我按 F12 的話,他呈現會是按 Fn + F12 的效果,而不是增大音量。

所以我就開始查有沒有什麼 command 是可以用來調整 Mac 的音量,然後就發現 AppleScript 可以做到,所以我就開始研究 AppleScript 了~

註:AppleScript 是 Apple 開發的程式語言,可用來控制跑在 Mac 上的程式

在 Mac 上,可以用這兩個指令來 取得、設置音量,換句話說,有了這兩個指令之後,就可以用程式化的方式來控制音量囉~

在 API server 裡面我把指令包裝成 get_volumeset_volume 兩個 function,當他們被執行時,就會啟動另一個 process 去跑寫好的 AppleScript,跑完之後再回傳結果

有了 get_volumeset_volume 兩個 function 之後,就可以把他們包裝成兩支 API,左邊是 main() 裡面新增的 endpoint,右邊是這兩個功能的實作

至於為什麼每次是調整音量是加 7 減 7 呢?因為我算了算 Mac 的音量總共有 16 格,而音量的最大值是 100,所以一格的音量就差不多是 7 啦

實作的部分就到這邊,現在的肥宅電腦遙控器已經有 開始、暫停、前進、後退、調整音量 的功能,用起來很棒,希望不要再突然想到新的問題了XD

Demo

如果看完文章還想再看一次 Demo 的話,這邊再放一次XD

總結

今天的文章就到這邊結束,很高興能跟大家分享我的 side project,其實做的過程還滿簡單的,沒有太深的技術,但用起來真的很方便。有了這個電腦遙控器之後,總算是可以一直躺在沙發上了XDD

另外,如果你也有相同需求的話,我的程式碼都放在 Github 上了~只要 git clone 下來跑 cargo run --release,就可以掃 QRCode 用開始手機控制電腦了~

後記

雖然從 Node 換到 Rust 後不會再受到 runtime 版本的影響,但因為我這個專案總共有兩百多個不同的 dependencies,所以從頭開始編譯的時間真的很久。不過那也只有第一次要這麼久,之後有 build cache 的情況下編譯時間都還可以接受

另外,從 Node 換到 Rust 後也可以發現記憶體用量大幅下降,Rust 在記憶體管理方面確實很有一套,但也因此讓他的語法變得比較難學,只能說語言本來就各有優缺,沒有最好的語言,選擇最符合自己需求的就好了!

延伸閱讀

--

--

一群技術人想要寫出一些好文章所建立的技術專欄。每週二一篇原創文章、一封電子報,歡迎大家訂閱!主網站: https://weekly.starbugs.dev/。

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Larry Lu

Larry Lu

2.5K Followers

我是 Larry 盧承億,傳說中的 0.1 倍工程師。我熱愛技術、喜歡與人分享,專長是 JS 跟 Go,平常會寫寫技術文章還有參加各種技術活動,歡迎大家來找我聊聊~