Xamarin.Macでリムーバブルメディアの着脱を検知する
2018年12月28日 (金) 03:33時点におけるimported>Administratorによる版
Xamarin.MacでCD-ROMやDVD-ROM、USBメモリの挿入などを検出できると何かと嬉しい。
実装例
NSWorkspace.SharedWorkspace.NotificationCenterを使うと検出できるようだ。この通知で飛んでくるのは「変化のあったデバイスのパスのみ」なので、そのパスをNSWorkspace.SharedWorkspace.GetFileSystemInfoに投げて「CD-ROMなのか」「USBメモリなのか」などを判別する。なお、GetFileSystemInfoの結果はCD-ROMやDVD-ROMの場合はディスクフォーマットごとに返ってくる値が違うようだ。どんな種類があるのか全部はまだ把握していない。
通知には種類があるようで、この例では以下を実装している。
- NSWorkspaceDidMountNotification - マウント直後
- NSWorkspaceWillUnmountNotification - アンマウント直前
NSWorkspaceDidUnmountNotification(WillではなくDid)も実装すればアンマウント直前のみならずアンマウント直後も検出できる。ただしアンマウント後なのでデバイスパスしか取得できない。アンマウント失敗時を考慮するとこちらの方が確実かもしれないが詳しくは知らない。
using System;
using Foundation;
using AppKit;
public class RemovableMediaNotificationEventArgs : EventArgs
{
public string DevicePath { get; set; }
public bool IsRemovable { get; set; }
public bool IsWritable { get; set; }
public bool IsUnmountable { get; set; }
public string Description { get; set; }
public string FileSystemType { get; set; }
}
public delegate void RemovableMediaNotificationEventHandler(object sender, RemovableMediaNotificationEventArgs args);
// 着脱を検知するクラス
public class RemovableMediaNotification : IDisposable
{
private NSObject _mountObserver;
private NSObject _unmountObserver;
public event RemovableMediaNotificationEventHandler OnMount;
public event RemovableMediaNotificationEventHandler OnUnmount;
public RemovableMediaNotification()
{
}
public void Dispose()
{
Stop();
}
public void Start()
{
var workspace = NSWorkspace.SharedWorkspace;
var notification = workspace.NotificationCenter;
// マウント直後
if (_mountObserver == null)
{
_mountObserver = notification.AddObserver(NSWorkspace.DidMountNotification, DidMount);
}
// マウント直前
if (_unmountObserver == null)
{
_unmountObserver = notification.AddObserver(NSWorkspace.WillUnmountNotification, WiilUnmount);
}
}
public void Stop()
{
var workspace = NSWorkspace.SharedWorkspace;
var notification = workspace.NotificationCenter;
if (_mountObserver != null)
{
notification.RemoveObserver(_mountObserver);
_mountObserver.Dispose();
_mountObserver = null;
}
if (_unmountObserver != null)
{
notification.RemoveObserver(_unmountObserver);
_unmountObserver.Dispose();
_unmountObserver = null;
}
}
private void DidMount(NSNotification notification)
{
if (OnUnmount != null)
{
var path = notification.UserInfo["NSDevicePath"].ToString();
var args = CreateEventArg(path);
OnMount(this, args);
}
}
private void WiilUnmount(NSNotification notification)
{
if (OnUnmount != null)
{
var path = notification.UserInfo["NSDevicePath"].ToString();
var args = CreateEventArg(path);
OnUnmount(this, args);
}
}
private RemovableMediaNotificationEventArgs CreateEventArg(string devicePath)
{
bool isRemovable;
bool isWritable;
bool isUnmountable;
string description;
string fileSystemType;
var workspace = NSWorkspace.SharedWorkspace;
workspace.GetFileSystemInfo(devicePath, out isRemovable, out isWritable, out isUnmountable, out description, out fileSystemType);
var args = new RemovableMediaNotificationEventArgs
{
DevicePath = devicePath,
IsRemovable = isRemovable,
IsWritable = isWritable,
IsUnmountable = isUnmountable,
Description = description,
FileSystemType = fileSystemType,
};
return args;
}
}