Xamarin.Mac/スクリーンセーバーを終了させる

提供: MonoBook
ナビゲーションに移動 検索に移動

Mac OS Xにおいてアプリに何か発生したときにスクリーンセーバーを終了させたい。

実装1[編集 | ソースを編集]

失敗1[編集 | ソースを編集]

ディスプレイのスリープを解除する方法ではスクリーンセーバーは終了しない。 どちらも似たようなものだと思うのだが通用しないようである。

失敗2[編集 | ソースを編集]

そこで.NET FrameworkでおなじみのSystem.Diagnostics.Processを使い、スクリーンセーバーらしきプロセスが存在するか調べ、そのプロセスを終了させてみた。 だが、こちらもダメであった。 プロセスに対してCloseやKillを送信しても一瞬画面がブラックアウトするが、すぐさまMac OS Xがスクリーンセーバーを再起動してしまっているようだ。

なお、Xamarin.MacとSystem.Diagnostics.Processでプロセス名を取得すると最大15文字となっているようだ。 すごいハマりどころなので注意する必要がある。

成功1[編集 | ソースを編集]

そこでプロセスに対してCloseやKillを送信するのではなく、キーボードを操作した風を装ってみたキーコードの送信には影響が少なさそうな「左矢印キー」を使った。 これは上手くいった。

しかし、このキーボードの入力をシミュレートする方法では、スクリーンセーバーは終了するが、ディスプレイのスリープを解除することはできなかった。両方が同時に走っている場合も多く、基本的には組み合わせて利用する必要がありそうだ。

using System;
using AppKit;
using CoreGraphics;

namespace LeaveScreenSaver
{
    static class MainClass
    {
        static void Main(string[] args)
        {
            NSApplication.Init();

            // デバッグ用のウエイト
            for (int wait = 10; 0 < wait; wait--)
            {
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine(wait);
            }

            // ScreenSaverらしきプロセスを取得する。
            // Xamarin.MacではProcessNameが最大15文字に切り詰められるようだ。
            // そのため「ScreenSaverEngi」となっている。
            var ps = System.Diagnostics.Process.GetProcessesByName("ScreenSaverEngi");

            // ScreenSaverらしきプロセスがあればキーボードを操作した風を装って終了させる。
            if (0 < ps.Length)
            {
                // キーボードの「←キー」を送信
                PostKeyWithModifiers(123);
            }
        }

        static void PostKeyWithModifiers(ushort keycode, CGEventFlags modifiers = 0)
        {
            using (var source = new CGEventSource(CGEventSourceStateID.CombinedSession))
            using (var keydown = new CGEvent(source, keycode, keyDown: true))
            using (var keyup = new CGEvent(source, keycode, keyDown: false))
            {
                keydown.Flags = modifiers;

                // 送信
                CGEvent.Post(keydown, CGEventTapLocation.AnnotatedSession);
                CGEvent.Post(keyup  , CGEventTapLocation.AnnotatedSession);
            }
        }
    }
}

関連項目[編集 | ソースを編集]

参考文献[編集 | ソースを編集]