Giving up on proper bring to foreground functionality as it need uiAccess.
Using uiAccess will require another deployment tool than ClickOnce.
1.1 --- a/.editorconfig Thu Mar 19 10:17:56 2015 +0100
1.2 +++ b/.editorconfig Thu Mar 19 17:07:09 2015 +0100
1.3 @@ -7,6 +7,6 @@
1.4
1.5 ; 4-column tab indentation
1.6 [*.cs]
1.7 -indent_style = tab
1.8 +indent_style = space
1.9 indent_size = 4
1.10
2.1 --- a/Server/MainForm.Hid.cs Thu Mar 19 10:17:56 2015 +0100
2.2 +++ b/Server/MainForm.Hid.cs Thu Mar 19 17:07:09 2015 +0100
2.3 @@ -13,217 +13,156 @@
2.4
2.5 namespace SharpDisplayManager
2.6 {
2.7 - [System.ComponentModel.DesignerCategory("Code")]
2.8 - public class MainFormHid : Form
2.9 - {
2.10 + [System.ComponentModel.DesignerCategory("Code")]
2.11 + public class MainFormHid : Form
2.12 + {
2.13 + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
2.14 + public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
2.15 + //
2.16 + public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
2.17
2.18 - [DllImport("USER32.DLL")]
2.19 - public static extern bool SetForegroundWindow(IntPtr hWnd);
2.20 + /// <summary>
2.21 + /// Use notably to handle green start key from IR remote control
2.22 + /// </summary>
2.23 + private Hid.Handler iHidHandler;
2.24
2.25 - [DllImport("USER32.DLL")]
2.26 - public static extern IntPtr GetForegroundWindow();
2.27 + /// <summary>
2.28 + /// Register HID devices so that we receive corresponding WM_INPUT messages.
2.29 + /// </summary>
2.30 + protected void RegisterHidDevices()
2.31 + {
2.32 + // Register the input device to receive the commands from the
2.33 + // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
2.34 + // for the vendor defined usage page.
2.35
2.36 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetWindowThreadProcessId")]
2.37 - public static extern uint GetWindowThreadProcessId([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, System.IntPtr lpdwProcessId);
2.38 + RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
2.39
2.40 - [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetCurrentThreadId")]
2.41 - public static extern uint GetCurrentThreadId();
2.42 + int i = 0;
2.43 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
2.44 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
2.45 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.46 + rid[i].hwndTarget = Handle;
2.47
2.48 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "AttachThreadInput")]
2.49 - [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
2.50 - public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fAttach);
2.51 + i++;
2.52 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
2.53 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
2.54 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.55 + rid[i].hwndTarget = Handle;
2.56
2.57 - [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
2.58 - public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
2.59 - //
2.60 - public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
2.61 + i++;
2.62 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
2.63 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
2.64 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.65 + rid[i].hwndTarget = Handle;
2.66
2.67 - /// <summary>
2.68 - /// Use notably to handle green start key from IR remote control
2.69 - /// </summary>
2.70 - private Hid.Handler iHidHandler;
2.71 + i++;
2.72 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.73 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
2.74 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.75 + rid[i].hwndTarget = Handle;
2.76
2.77 - /// <summary>
2.78 - /// Register HID devices so that we receive corresponding WM_INPUT messages.
2.79 - /// </summary>
2.80 - protected void RegisterHidDevices()
2.81 - {
2.82 - // Register the input device to receive the commands from the
2.83 - // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
2.84 - // for the vendor defined usage page.
2.85 + i++;
2.86 + rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.87 + rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
2.88 + rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.89 + rid[i].hwndTarget = Handle;
2.90
2.91 - RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
2.92 + //i++;
2.93 + //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.94 + //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
2.95 + //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
2.96 + //rid[i].hwndTarget = Handle;
2.97
2.98 - int i = 0;
2.99 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
2.100 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
2.101 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.102 - rid[i].hwndTarget = Handle;
2.103 + //i++;
2.104 + //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
2.105 + //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
2.106 + //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
2.107 + //rid[i].hwndTarget = aHWND;
2.108
2.109 - i++;
2.110 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
2.111 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
2.112 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.113 - rid[i].hwndTarget = Handle;
2.114
2.115 - i++;
2.116 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
2.117 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
2.118 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.119 - rid[i].hwndTarget = Handle;
2.120 + iHidHandler = new SharpLib.Hid.Handler(rid);
2.121 + if (!iHidHandler.IsRegistered)
2.122 + {
2.123 + Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
2.124 + }
2.125 + iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
2.126 + }
2.127
2.128 - i++;
2.129 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.130 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
2.131 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.132 - rid[i].hwndTarget = Handle;
2.133 + /// <summary>
2.134 + /// Here we receive HID events from our HID library.
2.135 + /// </summary>
2.136 + /// <param name="aSender"></param>
2.137 + /// <param name="aHidEvent"></param>
2.138 + public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
2.139 + {
2.140 + if (aHidEvent.IsStray)
2.141 + {
2.142 + //Stray event just ignore it
2.143 + return;
2.144 + }
2.145
2.146 - i++;
2.147 - rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.148 - rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
2.149 - rid[i].dwFlags = Const.RIDEV_INPUTSINK;
2.150 - rid[i].hwndTarget = Handle;
2.151 + if (this.InvokeRequired)
2.152 + {
2.153 + //Not in the proper thread, invoke ourselves
2.154 + OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
2.155 + this.Invoke(d, new object[] { aSender, aHidEvent });
2.156 + }
2.157 + else
2.158 + {
2.159 + //We are in the proper thread
2.160 + if (aHidEvent.Usages.Count > 0
2.161 + && aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
2.162 + && aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
2.163 + //&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
2.164 + //&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
2.165 + {
2.166 + //First check if the process we want to launch already exists
2.167 + string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
2.168 + Process[] existingProcesses = Process.GetProcessesByName(procName);
2.169 + if (existingProcesses == null || existingProcesses.Length == 0)
2.170 + {
2.171 + // Process do not exists just try to launch it
2.172 + ProcessStartInfo start = new ProcessStartInfo();
2.173 + // Enter in the command line arguments, everything you would enter after the executable name itself
2.174 + //start.Arguments = arguments;
2.175 + // Enter the executable to run, including the complete path
2.176 + start.FileName = Properties.Settings.Default.StartFileName;
2.177 + start.WindowStyle = ProcessWindowStyle.Normal;
2.178 + start.CreateNoWindow = true;
2.179 + start.UseShellExecute = true;
2.180 + // Run the external process & wait for it to finish
2.181 + Process proc = Process.Start(start);
2.182
2.183 - //i++;
2.184 - //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
2.185 - //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
2.186 - //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
2.187 - //rid[i].hwndTarget = Handle;
2.188 + //SL: We could have used that too
2.189 + //Shell32.Shell shell = new Shell32.Shell();
2.190 + //shell.ShellExecute(Properties.Settings.Default.StartFileName);
2.191 + }
2.192 + else
2.193 + {
2.194 + //This won't work properly until we have a manifest that enables uiAccess.
2.195 + //However uiAccess just won't work with ClickOnce so we will have to use a different deployment system.
2.196 + SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
2.197 + }
2.198 + }
2.199 + }
2.200 + }
2.201
2.202 - //i++;
2.203 - //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
2.204 - //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
2.205 - //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
2.206 - //rid[i].hwndTarget = aHWND;
2.207 -
2.208 -
2.209 - iHidHandler = new SharpLib.Hid.Handler(rid);
2.210 - if (!iHidHandler.IsRegistered)
2.211 - {
2.212 - Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
2.213 - }
2.214 - iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
2.215 - }
2.216 -
2.217 - /// <summary>
2.218 - /// Here we receive HID events from our HID library.
2.219 - /// </summary>
2.220 - /// <param name="aSender"></param>
2.221 - /// <param name="aHidEvent"></param>
2.222 - public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
2.223 - {
2.224 - if (aHidEvent.IsStray)
2.225 - {
2.226 - //Stray event just ignore it
2.227 - return;
2.228 - }
2.229 -
2.230 - if (this.InvokeRequired)
2.231 - {
2.232 - //Not in the proper thread, invoke ourselves
2.233 - OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
2.234 - this.Invoke(d, new object[] { aSender, aHidEvent });
2.235 - }
2.236 - else
2.237 - {
2.238 - //We are in the proper thread
2.239 - if (aHidEvent.Usages.Count > 0
2.240 - && aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
2.241 - && aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
2.242 - //&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
2.243 - //&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
2.244 - {
2.245 - //First check if the process we want to launch already exists
2.246 - string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
2.247 - Process[] existingProcesses = Process.GetProcessesByName(procName);
2.248 - if (existingProcesses == null || existingProcesses.Length == 0)
2.249 - {
2.250 - // Process do not exists just try to launch it
2.251 - ProcessStartInfo start = new ProcessStartInfo();
2.252 - // Enter in the command line arguments, everything you would enter after the executable name itself
2.253 - //start.Arguments = arguments;
2.254 - // Enter the executable to run, including the complete path
2.255 - start.FileName = Properties.Settings.Default.StartFileName;
2.256 - start.WindowStyle = ProcessWindowStyle.Normal;
2.257 - start.CreateNoWindow = true;
2.258 - start.UseShellExecute = true;
2.259 - // Run the external process & wait for it to finish
2.260 - Process proc = Process.Start(start);
2.261 -
2.262 - //SL: We could have used that too
2.263 - //Shell32.Shell shell = new Shell32.Shell();
2.264 - //shell.ShellExecute(Properties.Settings.Default.StartFileName);
2.265 - }
2.266 - else
2.267 - {
2.268 - //ForceForegroundWindow(existingProcesses[0].MainWindowHandle);
2.269 - SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
2.270 - }
2.271 - }
2.272 - }
2.273 - }
2.274 -
2.275 -
2.276 - /// <summary>
2.277 - /// For the Window with the given handle to the foreground no matter what.
2.278 - /// That works around flashing Window issues.
2.279 - /// As seen on http://www.asyncop.com/MTnPDirEnum.aspx?treeviewPath=[o]+Open-Source\WinModules\Infrastructure\SystemAPI.cpp
2.280 - /// </summary>
2.281 - /// <param name="hTo"></param>
2.282 - /// <returns></returns>
2.283 - IntPtr ForceForegroundWindow(IntPtr hTo)
2.284 - {
2.285 - if (hTo == IntPtr.Zero)
2.286 - {
2.287 - return IntPtr.Zero;
2.288 - }
2.289 - IntPtr hFrom = GetForegroundWindow();
2.290 -
2.291 - if (hFrom != IntPtr.Zero)
2.292 - {
2.293 - SetForegroundWindow(hTo);
2.294 - return IntPtr.Zero;
2.295 - }
2.296 - if (hTo == hFrom)
2.297 - {
2.298 - return IntPtr.Zero;
2.299 - }
2.300 -
2.301 - uint pid = GetWindowThreadProcessId(hFrom, IntPtr.Zero);
2.302 - uint tid = GetCurrentThreadId();
2.303 - if (tid == pid)
2.304 - {
2.305 - SetForegroundWindow(hTo);
2.306 - return (hFrom);
2.307 - }
2.308 - if (pid != 0)
2.309 - {
2.310 - if (!AttachThreadInput(tid, pid, true))
2.311 - {
2.312 - return IntPtr.Zero;
2.313 - }
2.314 - SetForegroundWindow(hTo);
2.315 - AttachThreadInput(tid, pid, false);
2.316 - }
2.317 - return (hFrom);
2.318 - }
2.319 -
2.320 - /// <summary>
2.321 - /// We need to handle WM_INPUT.
2.322 - /// </summary>
2.323 - /// <param name="message"></param>
2.324 - protected override void WndProc(ref Message message)
2.325 - {
2.326 - switch (message.Msg)
2.327 - {
2.328 - case Const.WM_INPUT:
2.329 - //Returning zero means we processed that message.
2.330 - message.Result = new IntPtr(0);
2.331 - iHidHandler.ProcessInput(ref message);
2.332 - break;
2.333 - }
2.334 - //Is that needed? Check the docs.
2.335 - base.WndProc(ref message);
2.336 - }
2.337 - }
2.338 + /// <summary>
2.339 + /// We need to handle WM_INPUT.
2.340 + /// </summary>
2.341 + /// <param name="message"></param>
2.342 + protected override void WndProc(ref Message message)
2.343 + {
2.344 + switch (message.Msg)
2.345 + {
2.346 + case Const.WM_INPUT:
2.347 + //Returning zero means we processed that message.
2.348 + message.Result = new IntPtr(0);
2.349 + iHidHandler.ProcessInput(ref message);
2.350 + break;
2.351 + }
2.352 + //Is that needed? Check the docs.
2.353 + base.WndProc(ref message);
2.354 + }
2.355 + }
2.356 }
3.1 --- a/Server/SharpDisplayManager.csproj Thu Mar 19 10:17:56 2015 +0100
3.2 +++ b/Server/SharpDisplayManager.csproj Thu Mar 19 17:07:09 2015 +0100
3.3 @@ -31,8 +31,8 @@
3.4 <CreateWebPageOnPublish>true</CreateWebPageOnPublish>
3.5 <WebPage>index.htm</WebPage>
3.6 <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
3.7 - <ApplicationRevision>4</ApplicationRevision>
3.8 - <ApplicationVersion>0.3.2.%2a</ApplicationVersion>
3.9 + <ApplicationRevision>2</ApplicationRevision>
3.10 + <ApplicationVersion>0.3.3.%2a</ApplicationVersion>
3.11 <UseApplicationTrust>false</UseApplicationTrust>
3.12 <CreateDesktopShortcut>true</CreateDesktopShortcut>
3.13 <PublishWizardCompleted>true</PublishWizardCompleted>