Server/MainForm.Hid.cs
changeset 131 9262041d1320
parent 130 c8d81bfa5fff
child 138 426cc984fd18
     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  }