Server/MainForm.Hid.cs
author StephaneLenclud
Fri, 19 Jun 2015 17:12:06 +0200
changeset 141 6f1da2b5c2ec
parent 131 9262041d1320
child 150 728fe28168e2
permissions -rw-r--r--
Prevents switching clients too often.
     1 using System;
     2 using System.IO;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 using System.Diagnostics;
     8 using System.Runtime.InteropServices;
     9 using System.Windows.Forms;
    10 //
    11 using Hid = SharpLib.Hid;
    12 using SharpLib.Win32;
    13 
    14 namespace SharpDisplayManager
    15 {
    16     /// <summary>
    17     /// Implement handling of HID input reports notably to be able to launch an application using the Green Start button from IR remotes.
    18     /// </summary>
    19     [System.ComponentModel.DesignerCategory("Code")]
    20     public class MainFormHid : Form
    21     {
    22         [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SwitchToThisWindow")]
    23         public static extern void SwitchToThisWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hwnd, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool fUnknown);
    24         //
    25         public delegate void OnHidEventDelegate(object aSender, Hid.Event aHidEvent);
    26 
    27         /// <summary>
    28         /// Use notably to handle green start key from IR remote control
    29         /// </summary>
    30         private Hid.Handler iHidHandler;
    31 
    32         /// <summary>
    33         /// Register HID devices so that we receive corresponding WM_INPUT messages.
    34         /// </summary>
    35         protected void RegisterHidDevices()
    36         {
    37             // Register the input device to receive the commands from the
    38             // remote device. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/remote_control.asp
    39             // for the vendor defined usage page.
    40 
    41             RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[5];
    42 
    43             int i = 0;
    44             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.WindowsMediaCenterRemoteControl;
    45             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.WindowsMediaCenter.WindowsMediaCenterRemoteControl;
    46             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
    47             rid[i].hwndTarget = Handle;
    48 
    49             i++;
    50             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
    51             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.ConsumerControl;
    52             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
    53             rid[i].hwndTarget = Handle;
    54 
    55             i++;
    56             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.Consumer;
    57             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.Consumer.Selection;
    58             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
    59             rid[i].hwndTarget = Handle;
    60 
    61             i++;
    62             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
    63             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.SystemControl;
    64             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
    65             rid[i].hwndTarget = Handle;
    66 
    67             i++;
    68             rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
    69             rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.GamePad;
    70             rid[i].dwFlags = Const.RIDEV_INPUTSINK;
    71             rid[i].hwndTarget = Handle;
    72 
    73             //i++;
    74             //rid[i].usUsagePage = (ushort)SharpLib.Hid.UsagePage.GenericDesktopControls;
    75             //rid[i].usUsage = (ushort)SharpLib.Hid.UsageCollection.GenericDesktop.Keyboard;
    76             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
    77             //rid[i].hwndTarget = Handle;
    78 
    79             //i++;
    80             //rid[i].usUsagePage = (ushort)Hid.UsagePage.GenericDesktopControls;
    81             //rid[i].usUsage = (ushort)Hid.UsageCollection.GenericDesktop.Mouse;
    82             //rid[i].dwFlags = Const.RIDEV_EXINPUTSINK;
    83             //rid[i].hwndTarget = aHWND;
    84 
    85 
    86             iHidHandler = new SharpLib.Hid.Handler(rid);
    87             if (!iHidHandler.IsRegistered)
    88             {
    89                 Debug.WriteLine("Failed to register raw input devices: " + Marshal.GetLastWin32Error().ToString());
    90             }
    91             iHidHandler.OnHidEvent += HandleHidEventThreadSafe;
    92         }
    93 
    94         /// <summary>
    95         /// Here we receive HID events from our HID library.
    96         /// </summary>
    97         /// <param name="aSender"></param>
    98         /// <param name="aHidEvent"></param>
    99         public void HandleHidEventThreadSafe(object aSender, SharpLib.Hid.Event aHidEvent)
   100         {
   101             if (aHidEvent.IsStray)
   102             {
   103                 //Stray event just ignore it
   104                 return;
   105             }
   106 
   107             if (this.InvokeRequired)
   108             {
   109                 //Not in the proper thread, invoke ourselves
   110                 OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
   111                 this.Invoke(d, new object[] { aSender, aHidEvent });
   112             }
   113             else
   114             {
   115                 //We are in the proper thread
   116                 if (aHidEvent.Usages.Count > 0
   117                     && aHidEvent.UsagePage == (ushort)Hid.UsagePage.WindowsMediaCenterRemoteControl
   118                     && aHidEvent.Usages[0] == (ushort)Hid.Usage.WindowsMediaCenterRemoteControl.GreenStart)
   119                 //&& aHidEvent.UsagePage == (ushort)Hid.UsagePage.Consumer
   120                 //&& aHidEvent.Usages[0] == (ushort)Hid.Usage.ConsumerControl.ThinkPadFullscreenMagnifier)
   121                 {
   122                     //First check if the process we want to launch already exists
   123                     string procName = Path.GetFileNameWithoutExtension(Properties.Settings.Default.StartFileName);
   124                     Process[] existingProcesses = Process.GetProcessesByName(procName);
   125                     if (existingProcesses == null || existingProcesses.Length == 0)
   126                     {
   127                         // Process do not exists just try to launch it
   128                         ProcessStartInfo start = new ProcessStartInfo();
   129                         // Enter in the command line arguments, everything you would enter after the executable name itself
   130                         //start.Arguments = arguments; 
   131                         // Enter the executable to run, including the complete path
   132                         start.FileName = Properties.Settings.Default.StartFileName;
   133                         start.WindowStyle = ProcessWindowStyle.Normal;
   134                         start.CreateNoWindow = true;
   135                         start.UseShellExecute = true;
   136                         // Run the external process & wait for it to finish
   137                         Process proc = Process.Start(start);
   138 
   139                         //SL: We could have used that too
   140                         //Shell32.Shell shell = new Shell32.Shell();
   141                         //shell.ShellExecute(Properties.Settings.Default.StartFileName);
   142                     }
   143                     else
   144                     {
   145                         //This won't work properly until we have a manifest that enables uiAccess.
   146                         //However uiAccess just won't work with ClickOnce so we will have to use a different deployment system.
   147                         SwitchToThisWindow(existingProcesses[0].MainWindowHandle, true);
   148                     }
   149                 }
   150             }
   151         }
   152 
   153         /// <summary>
   154         /// We need to handle WM_INPUT.
   155         /// </summary>
   156         /// <param name="message"></param>
   157         protected override void WndProc(ref Message message)
   158         {
   159             switch (message.Msg)
   160             {
   161                 case Const.WM_INPUT:
   162                     //Returning zero means we processed that message.
   163                     message.Result = new IntPtr(0);
   164                     iHidHandler.ProcessInput(ref message);
   165                     break;
   166             }
   167             //Is that needed? Check the docs.
   168             base.WndProc(ref message);
   169         }
   170     }
   171 }