1.1 --- a/Server/MainForm.Hid.cs Thu Mar 19 10:17:56 2015 +0100
1.2 +++ b/Server/MainForm.Hid.cs Thu Mar 19 17:07:09 2015 +0100
1.3 @@ -13,217 +13,156 @@
1.4
1.5 namespace SharpDisplayManager
1.6 {
1.7 - [System.ComponentModel.DesignerCategory("Code")]
1.8 - public class MainFormHid : Form
1.9 - {
1.10 + [System.ComponentModel.DesignerCategory("Code")]
1.11 + public class MainFormHid : Form
1.12 + {
1.13 + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
1.14 + public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
1.15 + //
1.16 + public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
1.17
1.18 - [DllImport("USER32.DLL")]
1.19 - public static extern bool SetForegroundWindow(IntPtr hWnd);
1.20 + /// <summary>
1.21 + /// Use notably to handle green start key from IR remote control
1.22 + /// </summary>
1.23 + private Hid.Handler iHidHandler;
1.24
1.25 - [DllImport("USER32.DLL")]
1.26 - public static extern IntPtr GetForegroundWindow();
1.27 + /// <summary>
1.28 + /// Register HID devices so that we receive corresponding WM_INPUT messages.
1.29 + /// </summary>
1.30 + protected void RegisterHidDevices()
1.31 + {
1.32 + // Register the input device to receive the commands from the
1.33 + // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
1.34 + // for the vendor defined usage page.
1.35
1.36 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
1.37 - public static extern uint GetWindowThreadProcessId([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, System.IntPtr lpdwProcessId);
1.38 + RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
1.39
1.40 - [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetCurrentThreadId")]
1.41 - public static extern uint GetCurrentThreadId();
1.42 + int i = 0;
1.43 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
1.44 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
1.45 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.46 + rid[i].hwndTarget = Handle;
1.47
1.48 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "AttachThreadInput")]
1.49 - [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
1.50 - public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fAttach);
1.51 + i++;
1.52 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
1.53 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
1.54 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.55 + rid[i].hwndTarget = Handle;
1.56
1.57 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
1.58 - public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
1.59 - //
1.60 - public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
1.61 + i++;
1.62 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
1.63 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
1.64 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.65 + rid[i].hwndTarget = Handle;
1.66
1.67 - /// <summary>
1.68 - /// Use notably to handle green start key from IR remote control
1.69 - /// </summary>
1.70 - private Hid.Handler iHidHandler;
1.71 + i++;
1.72 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.73 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
1.74 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.75 + rid[i].hwndTarget = Handle;
1.76
1.77 - /// <summary>
1.78 - /// Register HID devices so that we receive corresponding WM_INPUT messages.
1.79 - /// </summary>
1.80 - protected void RegisterHidDevices()
1.81 - {
1.82 - // Register the input device to receive the commands from the
1.83 - // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
1.84 - // for the vendor defined usage page.
1.85 + i++;
1.86 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.87 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
1.88 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.89 + rid[i].hwndTarget = Handle;
1.90
1.91 - RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
1.92 + //i++;
1.93 + //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.94 + //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
1.95 + //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
1.96 + //rid[i].hwndTarget = Handle;
1.97
1.98 - int i = 0;
1.99 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
1.100 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
1.101 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.102 - rid[i].hwndTarget = Handle;
1.103 + //i++;
1.104 + //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
1.105 + //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
1.106 + //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
1.107 + //rid[i].hwndTarget = aHWND;
1.108
1.109 - i++;
1.110 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
1.111 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
1.112 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.113 - rid[i].hwndTarget = Handle;
1.114
1.115 - i++;
1.116 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
1.117 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
1.118 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.119 - rid[i].hwndTarget = Handle;
1.120 + iHidHandler = new SharpLib.Hid.Handler(rid);
1.121 + if (!iHidHandler.IsRegistered)
1.122 + {
1.123 + Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
1.124 + }
1.125 + iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
1.126 + }
1.127
1.128 - i++;
1.129 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.130 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
1.131 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.132 - rid[i].hwndTarget = Handle;
1.133 + /// <summary>
1.134 + /// Here we receive HID events from our HID library.
1.135 + /// </summary>
1.136 + /// <param name="aSender"></param>
1.137 + /// <param name="aHidEvent"></param>
1.138 + public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
1.139 + {
1.140 + if (aHidEvent.IsStray)
1.141 + {
1.142 + //Stray event just ignore it
1.143 + return;
1.144 + }
1.145
1.146 - i++;
1.147 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.148 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
1.149 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
1.150 - rid[i].hwndTarget = Handle;
1.151 + if (this.InvokeRequired)
1.152 + {
1.153 + //Not in the proper thread, invoke ourselves
1.154 + OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
1.155 + this.Invoke(d, new object[] { aSender, aHidEvent });
1.156 + }
1.157 + else
1.158 + {
1.159 + //We are in the proper thread
1.160 + if (aHidEvent.Usages.Count > 0
1.161 + && aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
1.162 + && aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
1.163 + //&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
1.164 + //&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
1.165 + {
1.166 + //First check if the process we want to launch already exists
1.167 + string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
1.168 + Process[] existingProcesses = Process.GetProcessesByName(procName);
1.169 + if (existingProcesses == null || existingProcesses.Length == 0)
1.170 + {
1.171 + // Process do not exists just try to launch it
1.172 + ProcessStartInfo start = new ProcessStartInfo();
1.173 + // Enter in the command line arguments, everything you would enter after the executable name itself
1.174 + //start.Arguments = arguments;
1.175 + // Enter the executable to run, including the complete path
1.176 + start.FileName = Properties.Settings.Default.StartFileName;
1.177 + start.WindowStyle = ProcessWindowStyle.Normal;
1.178 + start.CreateNoWindow = true;
1.179 + start.UseShellExecute = true;
1.180 + // Run the external process & wait for it to finish
1.181 + Process proc = Process.Start(start);
1.182
1.183 - //i++;
1.184 - //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
1.185 - //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
1.186 - //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
1.187 - //rid[i].hwndTarget = Handle;
1.188 + //SL: We could have used that too
1.189 + //Shell32.Shell shell = new Shell32.Shell();
1.190 + //shell.ShellExecute(Properties.Settings.Default.StartFileName);
1.191 + }
1.192 + else
1.193 + {
1.194 + //This won't work properly until we have a manifest that enables uiAccess.
1.195 + //However uiAccess just won't work with ClickOnce so we will have to use a different deployment system.
1.196 + SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
1.197 + }
1.198 + }
1.199 + }
1.200 + }
1.201
1.202 - //i++;
1.203 - //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
1.204 - //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
1.205 - //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
1.206 - //rid[i].hwndTarget = aHWND;
1.207 -
1.208 -
1.209 - iHidHandler = new SharpLib.Hid.Handler(rid);
1.210 - if (!iHidHandler.IsRegistered)
1.211 - {
1.212 - Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
1.213 - }
1.214 - iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
1.215 - }
1.216 -
1.217 - /// <summary>
1.218 - /// Here we receive HID events from our HID library.
1.219 - /// </summary>
1.220 - /// <param name="aSender"></param>
1.221 - /// <param name="aHidEvent"></param>
1.222 - public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
1.223 - {
1.224 - if (aHidEvent.IsStray)
1.225 - {
1.226 - //Stray event just ignore it
1.227 - return;
1.228 - }
1.229 -
1.230 - if (this.InvokeRequired)
1.231 - {
1.232 - //Not in the proper thread, invoke ourselves
1.233 - OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
1.234 - this.Invoke(d, new object[] { aSender, aHidEvent });
1.235 - }
1.236 - else
1.237 - {
1.238 - //We are in the proper thread
1.239 - if (aHidEvent.Usages.Count > 0
1.240 - && aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
1.241 - && aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
1.242 - //&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
1.243 - //&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
1.244 - {
1.245 - //First check if the process we want to launch already exists
1.246 - string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
1.247 - Process[] existingProcesses = Process.GetProcessesByName(procName);
1.248 - if (existingProcesses == null || existingProcesses.Length == 0)
1.249 - {
1.250 - // Process do not exists just try to launch it
1.251 - ProcessStartInfo start = new ProcessStartInfo();
1.252 - // Enter in the command line arguments, everything you would enter after the executable name itself
1.253 - //start.Arguments = arguments;
1.254 - // Enter the executable to run, including the complete path
1.255 - start.FileName = Properties.Settings.Default.StartFileName;
1.256 - start.WindowStyle = ProcessWindowStyle.Normal;
1.257 - start.CreateNoWindow = true;
1.258 - start.UseShellExecute = true;
1.259 - // Run the external process & wait for it to finish
1.260 - Process proc = Process.Start(start);
1.261 -
1.262 - //SL: We could have used that too
1.263 - //Shell32.Shell shell = new Shell32.Shell();
1.264 - //shell.ShellExecute(Properties.Settings.Default.StartFileName);
1.265 - }
1.266 - else
1.267 - {
1.268 - //ForceForegroundWindow(existingProcesses[0].MainWindowHandle);
1.269 - SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
1.270 - }
1.271 - }
1.272 - }
1.273 - }
1.274 -
1.275 -
1.276 - /// <summary>
1.277 - /// For the Window with the given handle to the foreground no matter what.
1.278 - /// That works around flashing Window issues.
1.279 - /// As seen on http://www.asyncop.com/MTnPDirEnum.aspx?treeviewPath=[o]+Open-Source\WinModules\Infrastructure\SystemAPI.cpp
1.280 - /// </summary>
1.281 - /// <param name="hTo"></param>
1.282 - /// <returns></returns>
1.283 - IntPtr ForceForegroundWindow(IntPtr hTo)
1.284 - {
1.285 - if (hTo == IntPtr.Zero)
1.286 - {
1.287 - return IntPtr.Zero;
1.288 - }
1.289 - IntPtr hFrom = GetForegroundWindow();
1.290 -
1.291 - if (hFrom != IntPtr.Zero)
1.292 - {
1.293 - SetForegroundWindow(hTo);
1.294 - return IntPtr.Zero;
1.295 - }
1.296 - if (hTo == hFrom)
1.297 - {
1.298 - return IntPtr.Zero;
1.299 - }
1.300 -
1.301 - uint pid = GetWindowThreadProcessId(hFrom, IntPtr.Zero);
1.302 - uint tid = GetCurrentThreadId();
1.303 - if (tid == pid)
1.304 - {
1.305 - SetForegroundWindow(hTo);
1.306 - return (hFrom);
1.307 - }
1.308 - if (pid != 0)
1.309 - {
1.310 - if (!AttachThreadInput(tid, pid, true))
1.311 - {
1.312 - return IntPtr.Zero;
1.313 - }
1.314 - SetForegroundWindow(hTo);
1.315 - AttachThreadInput(tid, pid, false);
1.316 - }
1.317 - return (hFrom);
1.318 - }
1.319 -
1.320 - /// <summary>
1.321 - /// We need to handle WM_INPUT.
1.322 - /// </summary>
1.323 - /// <param name="message"></param>
1.324 - protected override void WndProc(ref Message message)
1.325 - {
1.326 - switch (message.Msg)
1.327 - {
1.328 - case Const.WM_INPUT:
1.329 - //Returning zero means we processed that message.
1.330 - message.Result = new IntPtr(0);
1.331 - iHidHandler.ProcessInput(ref message);
1.332 - break;
1.333 - }
1.334 - //Is that needed? Check the docs.
1.335 - base.WndProc(ref message);
1.336 - }
1.337 - }
1.338 + /// <summary>
1.339 + /// We need to handle WM_INPUT.
1.340 + /// </summary>
1.341 + /// <param name="message"></param>
1.342 + protected override void WndProc(ref Message message)
1.343 + {
1.344 + switch (message.Msg)
1.345 + {
1.346 + case Const.WM_INPUT:
1.347 + //Returning zero means we processed that message.
1.348 + message.Result = new IntPtr(0);
1.349 + iHidHandler.ProcessInput(ref message);
1.350 + break;
1.351 + }
1.352 + //Is that needed? Check the docs.
1.353 + base.WndProc(ref message);
1.354 + }
1.355 + }
1.356 }