はじめに
前回の記事では、Raspberry Pi Zero 2 W を USB マウスとして認識させ、LAN 経由から PC のマウス操作を行う方法について紹介しました。
今回は、さらに一歩進めて、2 台の Raspberry Pi Zero 2 W を使用し、1 台を送信機としてキーボード信号を送信し、もう 1 台を受信機としてその信号を受け取り、PC のマウスカーソルを動かす方法を解説します。
このシステムを利用することで、キーボード操作を通じて遠隔で PC の操作が可能になります。
関連記事
- 第0弾 Raspberry Pi OS をインストールする
- 第1弾 LAN経由でマウスを操作する
- 第2弾 USB キーボード信号の送受信とマウス操作
- 第3弾 MQTT を使用し、インターネット経由でマウスを遠隔操作
余談
当初は、マウス操作の信号をそのまま送信機から受信機へ送り、遠隔でマウスカーソルを操作することを目指していました。
しかし、マウスから発信される信号量が多く、少し動かしただけでプログラムが強制終了することが頻発しました。何度も試行錯誤を重ねたのですが、動作を安定させることが難しく、最終的にキーボードの信号を使用する方法に切り替えることにしました。
もし、マウス操作の信号を安定して送受信する方法をご存知の方がいらっしゃいましたら、ぜひご教示いただけると幸いです。
さて、今回の記事では、送信機側の Raspberry Pi Zero 2 W に接続したキーボードの信号を受信機に送り、その信号に基づいてマウスカーソルを操作する方法についてご紹介します。
受信機の設定
受信機は USB マウスとして認識される必要があります。
設定方法については、前回の記事をご確認ください。
受信側のプログラム
以下のプログラムを作成して、受信機として動作する Raspberry Pi 上で実行します。
このプログラムは送信機から送られてくるキーボード信号を受け取り、それに応じてマウスカーソルを移動させたり、クリック操作を行ったりします。
nano keyboard-rx.py
import socket
import json
import sys
import termios
import tty
HOST = '0.0.0.0'
PORT = 65432
# HIDファイルのパス
MOUSE_DEV = "/dev/hidg0"
# 初期設定
movement_amount = 10
min_movement = 1
max_movement = 127
# キーボード入力を非同期で取得するための設定
def get_key():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
# マウスの移動やクリックを送信する関数
def move_mouse(dx, dy, buttons=0):
report = bytearray([buttons, dx & 0xFF, dy & 0xFF])
with open(MOUSE_DEV, "wb") as f:
f.write(report)
# ソケットサーバーでの接続待機
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print('Waiting for a connection...')
conn, addr = s.accept()
with conn:
print(f'Connected by {addr}')
buffer = ""
while True:
data = conn.recv(1024)
if not data:
break
buffer += data.decode('utf-8')
while True:
try:
# JSONオブジェクトの境界を探す
obj, index = json.JSONDecoder().raw_decode(buffer)
buffer = buffer[index:].lstrip() # バッファから処理済み部分を削除
if obj['type'] == 1: # EV_KEY
if obj['value'] in (1, 2): # キーが押された、または押し続けられている
if obj['code'] == 103: # 上方向キー
move_mouse(0, -movement_amount)
elif obj['code'] == 108: # 下方向キー
move_mouse(0, movement_amount)
elif obj['code'] == 105: # 左方向キー
move_mouse(-movement_amount, 0)
elif obj['code'] == 106: # 右方向キー
move_mouse(movement_amount, 0)
elif obj['code'] == 44: # Zキー
movement_amount = max(min_movement, movement_amount - 4)
elif obj['code'] == 45: # Xキー
movement_amount = min(max_movement, movement_amount + 4)
elif obj['code'] == 30: # Aキーで左クリック
move_mouse(0, 0, buttons=1)
elif obj['code'] == 31: # Sキーで右クリック
move_mouse(0, 0, buttons=2)
elif obj['code'] == 16: # Qキー
print("Q key pressed. Exiting...")
conn.close()
s.close()
exit()
elif obj['value'] == 0: # キーが離されたとき、クリックを解除
if obj['code'] in (30, 31): # AキーまたはSキー
move_mouse(0, 0, buttons=0)
print(f"Received: {obj}")
except json.JSONDecodeError:
break
print("終了しました。")
プログラムの実行
以下のコマンドでプログラムを実行します。
sudo python3 keyboard-rx.py
実行すると、以下のように送信機からの接続待ち状態になります。
Waiting for a connection...
この状態で送信機が接続されると、受信機は送信機から送られたキーボード信号を受け取り、対応するマウス操作を PC 上で実行します。
送信機の設定
送信機として使用する Raspberry Pi には、USB キーボードを接続します。このキーボードからの信号を受信機に送信することで、遠隔での操作が可能になります。
送信側のプログラム
以下のプログラムを作成して、送信機として動作する Raspberry Pi 上で実行します。
このプログラムは、接続されたキーボードの信号を読み取り、それを受信機に送信します。
送信側のプログラム
nano keyboard-tx.py
import evdev
import socket
import json
# 送信先のホスト名とポート番号
HOST = 'zero-2.local' # 受信側のRaspberry Piのホスト名またはIPアドレス
PORT = 65432
# デバイスのevent番号を指定(キーボードのイベントデバイス)
device = evdev.InputDevice('/dev/input/event0')
# ソケットを作成し接続
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.connect((HOST, PORT))
print(f"Connected to {HOST}:{PORT}")
# キーボードイベントの読み取りと送信
for event in device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
# データの送信 (JSON + 改行)
data = json.dumps({'type': event.type, 'code': event.code, 'value': event.value})
s.sendall((data + '\n').encode('utf-8'))
print(f"Sent: {data}") # 送信したデータを表示
except BrokenPipeError:
print("Connection lost. Exiting.")
except Exception as e:
print(f"An error occurred: {e}")
プログラムの実行
以下のコマンドでプログラムを実行します。
nano keyboard-tx.py
プログラムが正常に動作すると、送信機は接続されたキーボードの入力を検知し、その信号を受信機に送信します。
受信機側でこの信号を受け取り、対応するマウス操作が実行されます。