diff --git a/HidSharp/Platform/HidManager.cs b/HidSharp/Platform/HidManager.cs index a7d76db..9a9e3d8 100644 --- a/HidSharp/Platform/HidManager.cs +++ b/HidSharp/Platform/HidManager.cs @@ -90,6 +90,11 @@ public virtual BleDiscovery BeginBleDiscovery() throw new NotSupportedException(); } + public virtual void Stop() + { + + } + IEnumerable GetDevices(DeviceTypeInfo type) { var _deviceList = type.DeviceList; diff --git a/HidSharp/Platform/HidSelector.cs b/HidSharp/Platform/HidSelector.cs index a6a15e1..d059bd0 100644 --- a/HidSharp/Platform/HidSelector.cs +++ b/HidSharp/Platform/HidSelector.cs @@ -21,31 +21,63 @@ namespace HidSharp.Platform { sealed class HidSelector { + public static bool IsRun; public static readonly HidManager Instance; - static readonly Thread ManagerThread; + static Thread ManagerThread; static HidSelector() { foreach (var hidManager in new HidManager[] - { - new Windows.WinHidManager(), - new Linux.LinuxHidManager(), - new MacOS.MacHidManager(), - new Unsupported.UnsupportedHidManager() - }) + { + new Windows.WinHidManager(), + new Linux.LinuxHidManager(), + new MacOS.MacHidManager(), + new Unsupported.UnsupportedHidManager() + }) { if (hidManager.IsSupported) { - var readyEvent = new ManualResetEvent(false); - Instance = hidManager; Instance.InitializeEventManager(); - ManagerThread = new Thread(Instance.RunImpl) { IsBackground = true, Name = "HID Manager" }; - ManagerThread.Start(readyEvent); - readyEvent.WaitOne(); + InitManager(); break; } } } + + public static void InitManager() + { + var readyEvent = new ManualResetEvent(false); + + ManagerThread = new Thread(Instance.RunImpl) { IsBackground = true, Name = "HID Manager" }; + ManagerThread.Start(readyEvent); + readyEvent.WaitOne(); + IsRun = true; + } + + public static void Stop() + { + Instance?.Stop(); + IsRun = false; + } + } + + public static class HidSelectorManager + { + public static void Stop() + { + if (HidSelector.IsRun) + { + HidSelector.Stop(); + } + } + + public static void Start() + { + if (!HidSelector.IsRun) + { + HidSelector.InitManager(); + } + } } } diff --git a/HidSharp/Platform/Linux/LinuxHidManager.cs b/HidSharp/Platform/Linux/LinuxHidManager.cs index c8f9914..a958a44 100644 --- a/HidSharp/Platform/Linux/LinuxHidManager.cs +++ b/HidSharp/Platform/Linux/LinuxHidManager.cs @@ -25,6 +25,8 @@ namespace HidSharp.Platform.Linux { sealed class LinuxHidManager : HidManager { + private bool _isStop; + protected override SystemEvents.EventManager CreateEventManager() { return new SystemEvents.LinuxEventManager(); @@ -60,8 +62,8 @@ protected override void Run(Action readyCallback) readyCallback(); while (true) { - ret = NativeMethods.retry(() => NativeMethods.poll(ref pfd, (IntPtr)1, -1)); - if (ret < 0) { break; } + ret = NativeMethods.retry(() => NativeMethods.poll(ref pfd, (IntPtr)1, 1000)); + if (ret < 0 || _isStop) { break; } if (ret == 1) { @@ -172,6 +174,11 @@ protected override bool TryCreateSerialDevice(object key, out Device device) device = LinuxSerialDevice.TryCreate((string)key); return true; } + public override void Stop() + { + _isStop = true; + } + public override string FriendlyName { get diff --git a/HidSharp/Platform/MacOS/MacHidManager.cs b/HidSharp/Platform/MacOS/MacHidManager.cs index 955e2d8..0d1fa36 100644 --- a/HidSharp/Platform/MacOS/MacHidManager.cs +++ b/HidSharp/Platform/MacOS/MacHidManager.cs @@ -23,6 +23,8 @@ namespace HidSharp.Platform.MacOS { sealed class MacHidManager : HidManager { + private IntPtr _runLoop; + protected override SystemEvents.EventManager CreateEventManager() { return new SystemEvents.MacOSEventManager(); @@ -43,9 +45,9 @@ protected override void Run(Action readyCallback) NativeMethods.IOHIDManagerRegisterDeviceMatchingCallback(manager.Handle, devicesChangedCallback, IntPtr.Zero); NativeMethods.IOHIDManagerRegisterDeviceRemovalCallback(manager.Handle, devicesChangedCallback, IntPtr.Zero); - var runLoop = NativeMethods.CFRunLoopGetCurrent(); - NativeMethods.CFRetain(runLoop); - NativeMethods.IOHIDManagerScheduleWithRunLoop(manager, runLoop, NativeMethods.kCFRunLoopDefaultMode); + _runLoop = NativeMethods.CFRunLoopGetCurrent(); + NativeMethods.CFRetain(_runLoop); + NativeMethods.IOHIDManagerScheduleWithRunLoop(manager, _runLoop, NativeMethods.kCFRunLoopDefaultMode); try { readyCallback(); @@ -53,8 +55,8 @@ protected override void Run(Action readyCallback) } finally { - NativeMethods.IOHIDManagerUnscheduleFromRunLoop(manager, runLoop, NativeMethods.kCFRunLoopDefaultMode); - NativeMethods.CFRelease(runLoop); + NativeMethods.IOHIDManagerUnscheduleFromRunLoop(manager, _runLoop, NativeMethods.kCFRunLoopDefaultMode); + NativeMethods.CFRelease(_runLoop); } GC.KeepAlive(devicesChangedCallback); @@ -131,6 +133,14 @@ protected override bool TryCreateSerialDevice(object key, out Device device) return device != null; } + public override void Stop() + { + if (_runLoop != IntPtr.Zero) + { + NativeMethods.CFRunLoopStop(_runLoop); + } + } + public override string FriendlyName { get { return "Mac OS HID"; } diff --git a/HidSharp/Platform/Windows/NativeMethods.cs b/HidSharp/Platform/Windows/NativeMethods.cs index d191b51..e54c1b7 100644 --- a/HidSharp/Platform/Windows/NativeMethods.cs +++ b/HidSharp/Platform/Windows/NativeMethods.cs @@ -77,6 +77,7 @@ unsafe static class NativeMethods public const uint WAIT_OBJECT_1 = 1; public const uint WAIT_TIMEOUT = 258; public const uint WM_DEVICECHANGE = 537; + public const uint WM_CLOSE = 0x0010; public const uint RTS_CONTROL_DISABLE = 0; public const uint RTS_CONTROL_ENABLE = 1; @@ -1004,6 +1005,9 @@ public static extern IntPtr CreateWindowEx(uint exStyle, [DllImport("user32.dll")] public static extern int GetMessage(out MSG message, IntPtr window, uint messageMin, uint messageMax); + [DllImport("user32.dll")] + public static extern bool PostMessage(IntPtr window, uint message, IntPtr messageMin, IntPtr messageMax); + [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool TranslateMessage(ref MSG message); diff --git a/HidSharp/Platform/Windows/WinHidManager.cs b/HidSharp/Platform/Windows/WinHidManager.cs index 664f527..d09f648 100644 --- a/HidSharp/Platform/Windows/WinHidManager.cs +++ b/HidSharp/Platform/Windows/WinHidManager.cs @@ -99,6 +99,8 @@ public override int GetHashCode() bool _isSupported; bool _bleIsSupported; + IntPtr _hwnd; + //static Thread _bleDiscoveryThread; //static int _bleDiscoveryRefCount; //static volatile bool _bleDiscoveryShuttingDown; @@ -158,14 +160,14 @@ protected override void Run(Action readyCallback) var wc = new NativeMethods.WNDCLASS() { ClassName = className, WindowProc = windowProc }; RunAssert(0 != NativeMethods.RegisterClass(ref wc), "HidSharp RegisterClass failed."); - var hwnd = NativeMethods.CreateWindowEx(0, className, className, 0, + _hwnd = NativeMethods.CreateWindowEx(0, className, className, 0, NativeMethods.CW_USEDEFAULT, NativeMethods.CW_USEDEFAULT, NativeMethods.CW_USEDEFAULT, NativeMethods.CW_USEDEFAULT, NativeMethods.HWND_MESSAGE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); - RunAssert(hwnd != IntPtr.Zero, "HidSharp CreateWindow failed."); + RunAssert(_hwnd != IntPtr.Zero, "HidSharp CreateWindow failed."); - var hidNotifyHandle = RegisterDeviceNotification(hwnd, NativeMethods.HidD_GetHidGuid()); - var bleNotifyHandle = RegisterDeviceNotification(hwnd, NativeMethods.GuidForBluetoothLEDevice); + var hidNotifyHandle = RegisterDeviceNotification(_hwnd, NativeMethods.HidD_GetHidGuid()); + var bleNotifyHandle = RegisterDeviceNotification(_hwnd, NativeMethods.GuidForBluetoothLEDevice); #if BLUETOOTH_NOTIFY var bleHandles = new List(); // FIXME: We don't handle the removal of USB Bluetooth dongles here, as far as notifications go. @@ -212,8 +214,8 @@ protected override void Run(Action readyCallback) NativeMethods.MSG msg; while (true) { - int result = NativeMethods.GetMessage(out msg, hwnd, 0, 0); - if (result == 0 || result == -1) { break; } + int result = NativeMethods.GetMessage(out msg, _hwnd, 0, 0); + if (result == 0 || result == -1 || msg.Message == NativeMethods.WM_CLOSE) { break; } NativeMethods.TranslateMessage(ref msg); NativeMethods.DispatchMessage(ref msg); @@ -232,7 +234,7 @@ protected override void Run(Action readyCallback) foreach (var bleHandle in bleHandles) { UnregisterDeviceNotification(bleHandle.NotifyHandle); NativeMethods.CloseHandle(bleHandle.RadioHandle); } #endif - RunAssert(NativeMethods.DestroyWindow(hwnd), "HidSharp DestroyWindow failed."); + RunAssert(NativeMethods.DestroyWindow(_hwnd), "HidSharp DestroyWindow failed."); RunAssert(NativeMethods.UnregisterClass(className, IntPtr.Zero), "HidSharp UnregisterClass failed."); GC.KeepAlive(windowProc); } @@ -663,6 +665,14 @@ protected override bool TryCreateSerialDevice(object key, out Device device) device = WinSerialDevice.TryCreate(path.DevicePath, path.FileSystemName, path.FriendlyName); return true; } + public override void Stop() + { + if (_hwnd != IntPtr.Zero) + { + RunAssert(NativeMethods.PostMessage(_hwnd, NativeMethods.WM_CLOSE, 0, 0), "HidSharp PostMessage failed."); + } + } + public override bool AreDriversBeingInstalled { get