Synergy を利用して、PC を操作しているマウス、キーボードを使ってAndroidスマートフォンもいじれるようにした。

少し前の記事で VNC を利用して余ったスマートフォンをPCのサブディスプレイにしてみたわけだが、PC 側の負荷が大きくなることや、その割にはウィンドウを共有できない等欠点が多く、しっくりこなかった。

今回は Synerygy を使ったことにより、 PC には PC の画面を表示し、スマートフォンにはスマートフォンの画面を表示しつつも、 マウス、キーボードだけがPCからスマートフォンへ出張する形になる。 PC、スマートフォンのリソースを無駄無く活用しながら、共通のデバイスで操作できるようになる。

今回やったことを酷く単純に言うと Synergy を利用しただけなのだが、 動作させるにはなかなか苦労したので本記事でその記録を書いておきたいと思う。

  1. この記事: Synergy サーバーの起動
  2. Synergy クライアントの起動 Galaxy s7 権限ルート取得編
  3. Synergyクライアント起動 SELinux編

まず結論を言うと、Synergy は購入が必要である。徐々に値上げしているようで、 2019/3/5 時点では Basic プランで $29 だった。 ちょっと高いが開発者へのお布施と考えたらよいだろう。 なお動かなければ返金対応はできる模様。

Android スマートフォンの root 権限も必須である。 さらに SELinux のポリシーを設定できる必要もある。 SELinux 編でなんとかする。

1. システム構成

Synergy では、マウス、キーボードが繋っている PC 上に Synergy サーバーを起動する。 マウス、キーボードを共有される側では Synergy クライアントを起動することになる。

今回、ノート PC をサーバー、Android スマートフォンをクライアントとした。

サーバー:

  • Think Pad
  • Fedora 29
  • Ethernet 192.168.0.8
$ uname -a
Linux localhost.localdomain 4.20.12-200.fc29.x86_64 #1 SMP Mon Feb 25 16:16:18 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

クライアント:

  • Galaxy s7 スマートフォン (SM-G930FD)
  • Android 8.0.0
  • Wi-Fi 192.168.0.9

2. Synergy について

Synergy は、冒頭から何度も書いているが、複数の PC 間でマウス、キーボードを共有するシステムである。

母艦 PC の画面上に表示されているマウスポインタを画面端へ持っていくと、 隣の PC にポインタが移動し、そのままマウスで移動先の PC を操作することができる。 キーボード入力も母艦 PC から各 PC へ共有することができる。

マルチプラットフォーム対応しており、公式ページでは Linux、Windows、mac OS の間で共有できると謳っている。他にも Raspberry Pi との共有も可能らしい。

加えて実は、公式ページには掲載されていないものの Andorid 版アプリもある:

あまり熱心にメンテナンスされているわけでは無さそうだが、 Synergy クライアント (マウス、キーボードを共有される側) として一通りの機能は実装されているようだ。 ただし軽く見た感じ、クリップボードの共有機能は無い。 個人的には結構欲しいので自分で作ってみちゃうかもしれない。

3. Synergy のインストール

DNF でインストールすることができる。 2019/3/6 時点で、DNF では 2.0.0 が配布されている。 なお quicksynergy というパッケージもあるがこれは必要無い。

$ sudo dnf install synergy

公式ページから RPM を持ってきてインストールすることもできる。 2.0.0 の RPM も取得できるが、現時点では 1.X がまだ優先的にまだ配布されている。

$ sudo dnf install synergy_1.10.1-91.stable.8941241e.centos.el7.x86_64.rpm

またソースコードも公開されているので自分でビルドすることも可能。 私は接続がうまくいかなかったので、デバッグログを仕込むため自分でビルドした。

ビルド方法については後述。

4. Firewall の設定

忘れないうちに Firewall の設定をしておく。 Synergy は 24800 番ポートを利用する。

firewalld の設定を見たら Synergy 向けのファイルが既に入っていた。 DNF でインストールしたときに作成されたのだろうか:

$ cat /lib/firewalld/services/synergy.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Synergy</short>
  <description>Synergy lets you easily share your mouse and keyboard between multiple computers, where each computer has its own display. No special hardware is required, all you need is a local area network. Synergy is supported on Windows, Mac OS X and Linux. Redirecting the mouse and keyboard is as simple as moving the mouse off the edge of your screen.</description>
  <port protocol="tcp" port="24800"/>
</service>

24800 番ポートを開放するように firewalld を設定し、反映する:

$ sudo firewall-cmd --permanent --add-service=synergy
$ sudo firewall-cmd --reload

5. Synergy の起動

DNF, RPM からインストールした場合には synergy コマンドが使えるようになっている。 操作 UI が使えるのでわかり易い:

$ synergy

もしくは、ソースビルドした場合など、CUI のツールが使える;

$ synergy-core --server -c ~/synergy.conf -d ログレベル -l server.log

ログレベルは普通のやつ (ERROR, WARN, …, DEBUG 等) に加え、 DEBUG1, DEBUG2 を指定できる。 うまく動かないうちは DEBUG1, DEBUG2 を指定してもよいだろう。

synergy.conf は設定ファイルである。例えば以下のような感じになる。

サーバーの Think pad が localhost.localdomain で、 クライアントの Galaxy s7 が fg-galaxy である。 localhost.localdomain の左端と fg-galaxy の右端が繋がっているように見える。

$ cat ~/synergy.conf 
section: screens
	fg-galaxy:
		halfDuplexCapsLock = false
		halfDuplexNumLock = false
		halfDuplexScrollLock = false
		xtestIsXineramaUnaware = false
		switchCorners = none 
		switchCornerSize = 0
	localhost.localdomain:
		halfDuplexCapsLock = false
		halfDuplexNumLock = false
		halfDuplexScrollLock = false
		xtestIsXineramaUnaware = false
		switchCorners = none 
		switchCornerSize = 0
end

section: aliases
end

section: links
	fg-galaxy:
		right = localhost.localdomain
	localhost.localdomain:
		left = fg-galaxy
end

section: options
	relativeMouseMoves = true
	screenSaverSync = true
	win32KeepForeground = false
	clipboardSharing = true
	switchCorners = none 
	switchCornerSize = 0
end

Synergy は有料アプリだけあって、基本的にちゃんと動く(ような雰囲気がある)。 例えばメジャーな環境、Windows-mac OS とかだったら難しいことを考えずに動く(んだろうなーという雰囲気がある)。

しかし、私の環境、Linux-Android間ではそのままではうまくいかなかった。 なんとなく Synergy は起動してログは出力しているし、 マウス操作に反応してそれっぽいログを書き出しているように見える。 だが、スマートフォン側にマウスカーソルが一瞬たりとも表示されなかった。

サーバー側、クライアント側の両方で問題があったのだが、 この記事ではサーバー側の対処と調査時の記録を書く。

6. Synergy サーバー解析

結論を先に言ってしまうと、サーバーで起動していた X2VNC を終了したら少し進んだ。 can't leave screen エラーが出なくなった。

X2VNC は前回の記事、余ったスマートフォンをPCのサブディスプレイに、にて導入したもので、 Android 端末に表示した VNC の画面へ、PC からマウスカーソルを出張させることができるやつ。

VNC を使った場合にしろ、Synergy を使った場合にしろ、 別の画面に偽マウスカーソルを表示させたりするにはマウス、キーボード入力の監視が必要らしい。

それら入力を監視するためには、Xorg においては Grab する必要がある。 X2VNC も Synergy もマウス、キーボード入力をそれぞれ Grab している。

同時に複数のプログラムから同一の入力デバイスを Grab することは出来ないため、 X2VNC が先に起動済みだと、Synergy からはマウス、キーボードの情報を取得することができない。

$ sudo systemctl stop x2vnc@:1.service

x2vnc@.service は私が書いたサービスファイルなので、 上記コマンドは私以外使うことは無いはず。

7. 調査の思い出

調査時の記録を残しておく。 うまく Synergy を利用できない人の助けになるかもしれない。

7.1. Wayland 無効化

Fedora25 以降では Xorg に代わり Wayland がデフォルトで採用されている。 現時点で Synergy は Wayland をサポートしていないため、Xorg で起動していなければ 利用することができない。

https://github.com/symless/synergy-core/wiki/Core-User-FAQ#ive-updated-to-fedora-25-and-synergy-no-longer-works

上記リンクで書かれているように GDM の設定ファイルで Wayland を無効化してみた。

# grep WaylandEnable -B2 /etc/gdm/custom.conf
[daemon]
# Uncomment the line below to force the login screen to use Xorg
WaylandEnable=false

本当に効いたかどうかはわからない。

ちなみに Synergy 2.1 からは Wayland もサポートされる予定らしい:

Wayland support for Linux client and server · Issue #4090 · symless/synergy-core

Coming soon in 2.1.

7.2. Synergy

もちろん Wayland 無効化だけではうまくいかなかった。

ログを見ていると以下のように出ているのが気になった。

WARN: cat't leave screen

Synergy サーバーとクライアントを起動し、接続した状態でマウスカーソルを 画面外に出そうとするとこのログが出るようだ。

クライアント側にマウス、キーボードを出張させるタイミングで何かエラー的なことが起き、 そのために制御イベントを飛ばせていないと推測された。

先述の通り、Synergy サーバーはソースコードが公開されている:

先程のログ出力は Server.cpp で見つけられた。

src/lib/server/Server.cpp:

// leave active screen
if (!m_active->leave()) {
        // cannot leave screen
        LOG((CLOG_WARN "can't leave screen"));
        return;
}

さらにログレベルを DEBUG2 に設定すると、次のようなログも見つかった。

DEBUG2: waiting to grab keyboard
DEBUG2: waiting to grab keyboard
DEBUG2: waiting to grab keyboard
DEBUG2: grab keyboard timed out

このログを出力するコードは XWindowsScreen.cpp にあった。

src/lib/platform/XWindowsScreen.cpp:

result = XGrabKeyboard(m_display, m_window, True,
                       GrabModeAsync, GrabModeAsync, CurrentTime);
assert(result != GrabNotViewable);

if (result != GrabSuccess) {
        LOG((CLOG_DEBUG2 "waiting to grab keyboard"));
        ARCH->sleep(0.05);
        if (timer.getTime() >= s_timeout) {
                LOG((CLOG_DEBUG2 "grab keyboard timed out"));
                return false;
        }
}

何やら XGrabKeyboard で失敗しているようだ。 Grab を何度か実行した結果、GrabSuccess にならないのでタイムアウトしているっぽい。

XGrabKeyboard の説明を以下のページで見つけた。

どうもエラーの場合には GrabSuccess 以外のコードが応答されるようだ。 今のコードだと失敗したことはわかっても、何故失敗したのかわからない。

そこで、次のようにデバッグコードを仕込んで実験することにした。

src/lib/platform/XWindowsScreen.cpp (modified):

result = XGrabKeyboard(m_display, m_window, True,
                       GrabModeAsync, GrabModeAsync, CurrentTime);
assert(result != GrabNotViewable);

// Added to debug
if (result == AlreadyGrabbed) {
        LOG((CLOG_WARN "keyboard already grabbed"));
}
if (result == GrabFrozen) {
        LOG((CLOG_WARN "keyboard frozen"));
}
if (result == GrabInvalidTime) {
        LOG((CLOG_WARN "failed to grab keyboard by invalid time"));
}
if (result == BadValue) {
        LOG((CLOG_WARN "failed to grab keyboard by bad value"));
}
if (result == BadWindow) {
        LOG((CLOG_WARN "failed to grab keyboard by bad window"));
}

if (result != GrabSuccess) {
        LOG((CLOG_DEBUG2 "waiting to grab keyboard"));
        ARCH->sleep(0.05);
        if (timer.getTime() >= s_timeout) {
                LOG((CLOG_DEBUG2 "grab keyboard timed out"));
                return false;
        }
}

以下はビルド手順である。特に面白い点は無く、普通にビルドしただけ。

XTest のインストール:

$ sudo dnf install libXtst-devel 

Synergy-core のビルド:

$ mkdir build
$ cmake ..
$ make

なぜか XTest を見つけてくれない状態に陥った。 いろいろ悩んだ末、build ディレクトリを消して cmake やり直したらうまくいった;

$ rm -r *
$ cmake ..
$ make

ビルド成功したらサーバーを起動する;

$ synergy-core --server -c ~/synergy.conf -d DEBUG2 -l server.log

結果のログ:

WARN: keyboard already grabbed
DEBUG2: waiting to grab keyboard
WARN: keyboard already grabbed
DEBUG2: waiting to grab keyboard
WARN: keyboard already grabbed
DEBUG2: waiting to grab keyboard
DEBUG2: grab keyboard timed out

何者かが Synergy よりも先にキーボードを Grab している?

しばらく苦悩したのち、結局、自分のせいであることに気付いた。 ps -ef してプロセスを眺めてたら気付いた。

少し前に設定した X2VNC が Grab していたようだ。

VNC と Synergy は普通に衝突しそうなので、VNC 系サービスは落としてしまう。

$ sudo systemctl stop vncserver@:1
$ sudo systemctl stop x2vnc@:1

結果、接続できるようになった。

[2019-03-05T02:22:07] DEBUG2: find neighbor on left of "localhost.localdomain"
[2019-03-05T02:22:07] DEBUG2: "fg-galaxy" is on left of "localhost.localdomain" at 0.584145
[2019-03-05T02:22:07] DEBUG1: try to leave "localhost.localdomain" on left
[2019-03-05T02:22:07] DEBUG2: mapping state: 0
[2019-03-05T02:22:07] INFO: switch from "localhost.localdomain" to "fg-galaxy" at 1439,1495
[2019-03-05T02:22:07] INFO: leaving screen
[2019-03-05T02:22:07] DEBUG2: grabbed keyboard
[2019-03-05T02:22:07] DEBUG1: grabbed pointer and keyboard
[2019-03-05T02:22:07] DEBUG2: warped to 971,1464
[2019-03-05T02:22:07] DEBUG2: mapping state: 0
[2019-03-05T02:22:07] DEBUG1: modifiers on update: 0x0000
[2019-03-05T02:22:07] DEBUG: open clipboard 0
[2019-03-05T02:22:07] DEBUG1: locked motif clipboard
[2019-03-05T02:22:07] DEBUG2: can't read property 593 on window 0x0000015f
[2019-03-05T02:22:07] DEBUG1: motif does not own clipboard
[2019-03-05T02:22:07] DEBUG1: unlocked motif clipboard

少し怪しいログも出ているけどね。

しかしまだスマートフォン側にマウスポインタは表示されていないし、 キーボード入力しても何も起きない。

こんな感じでキーは届いているみたいだが…。

以下は Android アプリのログ:

03-05 02:21:50.399 26667 26727 I Synergy : [Data] Key Down:106:0:44:org.synergy.base.Log:149
03-05 02:21:51.204 26667 26727 I Synergy : [Data] Key Down:107:0:45:org.synergy.base.Log:149
03-05 02:21:52.665 26667 26727 I Synergy : [Data] Key Down:106:0:44:org.synergy.base.Log:149
03-05 02:21:53.663 26667 26727 I Synergy : [Data] Key Down:106:0:44:org.synergy.base.Log:149
03-05 02:21:54.081 26667 26727 I Synergy : [Data] Key Down:116:0:28:org.synergy.base.Log:149
03-05 02:21:54.106 26667 26727 I Synergy : [Data] Key Down:104:0:43:org.synergy.base.Log:149
03-05 02:21:54.193 26667 26727 I Synergy : [Data] Key Down:105:0:31:org.synergy.base.Log:149

root 権限取得編 に続く。

8. おまけ

Synergy を systemd に登録するために、次のようにサービスファイルを書いた。

# cat /etc/systemd/system/synergy.service
[Unit]
Description=Synergy service
After=syslog.target network.target

[Service]
Type=simple
User=synergy
Group=synergy
ExecStart=/usr/local/bin/synergy-core --server -c /home/synergy/synergy.conf -d DEBUG -l /var/log/synergy.log --no-daemon
Restart=always

[Install]
WantedBy=multi-user.target

Synergy サービス設定の反映:

# systemctl daemon-reload

Synergy の起動:

# systemctl start synergy

Synergy の終了:

# synergy stop synergy

9. 参考

Synergy

Xorg