Giving up on proper bring to foreground functionality as it need uiAccess.
authorStephaneLenclud
Thu, 19 Mar 2015 17:07:09 +0100
changeset 1319262041d1320
parent 130 c8d81bfa5fff
child 132 f9e6c13eea9c
Giving up on proper bring to foreground functionality as it need uiAccess.
Using uiAccess will require another deployment tool than ClickOnce.
.editorconfig
Server/MainForm.Hid.cs
Server/SharpDisplayManager.csproj
     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>