Implementing key repeat support.
authorsl
Tue, 23 Dec 2014 23:05:23 +0100
changeset 41dd603eba46ca
parent 40 b3e177062849
child 42 219e9a418456
Implementing key repeat support.
HidEvent.cs
HidHandler.cs
MainForm.cs
     1.1 --- a/HidEvent.cs	Tue Dec 23 21:17:17 2014 +0100
     1.2 +++ b/HidEvent.cs	Tue Dec 23 23:05:23 2014 +0100
     1.3 @@ -6,6 +6,7 @@
     1.4  using Microsoft.Win32.SafeHandles;
     1.5  using Win32;
     1.6  using System.Collections.Generic;
     1.7 +using System.Timers;
     1.8  
     1.9  
    1.10  namespace Hid
    1.11 @@ -13,7 +14,7 @@
    1.12      /// <summary>
    1.13      /// Represent a HID event.
    1.14      /// </summary>
    1.15 -    public class HidEvent
    1.16 +    public class HidEvent: IDisposable
    1.17      {
    1.18          public bool IsValid { get; private set; }
    1.19          public bool IsForeground { get; private set; }
    1.20 @@ -29,20 +30,33 @@
    1.21          public ushort UsagePage { get; private set; }
    1.22          public ushort UsageCollection { get; private set; }
    1.23          public uint UsageId { get { return ((uint)UsagePage << 16 | (uint)UsageCollection); } }
    1.24 -        public List<ushort> Usages { get; private set; }
    1.25 +        public List<ushort> Usages { get; private set; }        
    1.26 +        public delegate void HidEventRepeatDelegate(HidEvent aHidEvent);
    1.27 +        public event HidEventRepeatDelegate OnHidEventRepeat;
    1.28  
    1.29 +        private System.Timers.Timer Timer { get; set; }
    1.30 +
    1.31 +
    1.32 +        public void Dispose()
    1.33 +        {
    1.34 +            Timer.Enabled = false;
    1.35 +            Timer.Dispose();
    1.36 +            Timer = null;
    1.37 +        }
    1.38  
    1.39          /// <summary>
    1.40          /// Initialize an HidEvent from a WM_INPUT message
    1.41          /// </summary>
    1.42          /// <param name="hRawInputDevice">Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice</param>
    1.43 -        public HidEvent(Message aMessage)
    1.44 +        public HidEvent(Message aMessage, HidEventRepeatDelegate aRepeatDelegate)
    1.45          {
    1.46              IsValid = false;
    1.47              IsKeyboard = false;
    1.48              IsGeneric = false;
    1.49  
    1.50 +            Timer = new System.Timers.Timer();
    1.51              Usages = new List<ushort>();
    1.52 +            OnHidEventRepeat += aRepeatDelegate;
    1.53  
    1.54              if (aMessage.Msg != Const.WM_INPUT)
    1.55              {
    1.56 @@ -175,6 +189,11 @@
    1.57                  Marshal.FreeHGlobal(preParsedData);
    1.58              }
    1.59  
    1.60 +            if (Usages[0]!=0)
    1.61 +            {
    1.62 +                StartRepeatTimer(SystemInformation.KeyboardDelay*250+250);
    1.63 +            }
    1.64 +            
    1.65              IsValid = true;
    1.66          }
    1.67  
    1.68 @@ -226,7 +245,24 @@
    1.69                  }
    1.70          }
    1.71  
    1.72 +        public void StartRepeatTimer(double aInterval)
    1.73 +        {
    1.74 +            if (Timer == null)
    1.75 +            {
    1.76 +                return;
    1.77 +            }
    1.78 +            Timer.Enabled = false;
    1.79 +            Timer.AutoReset = false;
    1.80 +            Timer.Interval = aInterval;
    1.81 +            Timer.Elapsed += (sender, e) => OnRepeatTimerElapsed(sender, e, this);            
    1.82 +            Timer.Enabled = true;
    1.83 +        }
    1.84  
    1.85 +        private void OnRepeatTimerElapsed(object sender, ElapsedEventArgs e, HidEvent aHidEvent)
    1.86 +        {
    1.87 +            StartRepeatTimer(1000/(SystemInformation.KeyboardSpeed+2.5));            
    1.88 +            OnHidEventRepeat(aHidEvent);
    1.89 +        }
    1.90  
    1.91      }
    1.92  
     2.1 --- a/HidHandler.cs	Tue Dec 23 21:17:17 2014 +0100
     2.2 +++ b/HidHandler.cs	Tue Dec 23 23:05:23 2014 +0100
     2.3 @@ -19,18 +19,20 @@
     2.4      {
     2.5          public delegate void HidEventHandler(object aSender, HidEvent aHidEvent);
     2.6          public event HidEventHandler OnHidEvent;
     2.7 +        List<HidEvent> iHidEvents;
     2.8 +
     2.9  
    2.10          public bool IsRegistered { get; private set; }
    2.11  
    2.12          public HidHandler(RAWINPUTDEVICE[] aRawInputDevices)
    2.13          {
    2.14 +            iHidEvents=new List<HidEvent>();
    2.15              IsRegistered = Function.RegisterRawInputDevices(aRawInputDevices, (uint)aRawInputDevices.Length, (uint)Marshal.SizeOf(aRawInputDevices[0]));
    2.16          }
    2.17  
    2.18 -
    2.19          public void ProcessInput(Message aMessage)
    2.20          {
    2.21 -            Hid.HidEvent hidEvent = new Hid.HidEvent(aMessage);
    2.22 +            Hid.HidEvent hidEvent = new Hid.HidEvent(aMessage, OnHidEventRepeat);
    2.23              hidEvent.DebugWrite();
    2.24  
    2.25              if (!hidEvent.IsValid || !hidEvent.IsGeneric)
    2.26 @@ -39,10 +41,36 @@
    2.27                  return;
    2.28              }
    2.29  
    2.30 +            //
    2.31 +            if (hidEvent.Usages[0] == 0)
    2.32 +            {
    2.33 +                //This is a key up event
    2.34 +                //We need to discard any events belonging to the same page and collection
    2.35 +                for (int i = (iHidEvents.Count-1); i >= 0; i--)
    2.36 +                {
    2.37 +                    if (iHidEvents[i].UsageId == hidEvent.UsageId)
    2.38 +                    {
    2.39 +                        iHidEvents[i].Dispose();
    2.40 +                        iHidEvents.RemoveAt(i);
    2.41 +                    }
    2.42 +                }
    2.43 +            }
    2.44 +            else
    2.45 +            {
    2.46 +                //Keep that event until we get a key up message
    2.47 +                iHidEvents.Add(hidEvent);
    2.48 +            }
    2.49 +
    2.50              //Broadcast our events
    2.51              OnHidEvent(this, hidEvent);    
    2.52          }
    2.53  
    2.54 +        public void OnHidEventRepeat(HidEvent aHidEvent)
    2.55 +        {
    2.56 +            //Broadcast our events
    2.57 +            OnHidEvent(this, aHidEvent);    
    2.58 +        }
    2.59 +
    2.60      }
    2.61  
    2.62  }
    2.63 \ No newline at end of file
     3.1 --- a/MainForm.cs	Tue Dec 23 21:17:17 2014 +0100
     3.2 +++ b/MainForm.cs	Tue Dec 23 23:05:23 2014 +0100
     3.3 @@ -26,6 +26,8 @@
     3.4          private ColumnHeader columnHeaderUsageCollection;
     3.5  		private Timer _timer;
     3.6  
     3.7 +        public delegate void OnHidEventDelegate(object aSender, Hid.HidEvent aHidEvent);
     3.8 +
     3.9  		public MainForm()
    3.10  		{
    3.11  			//
    3.12 @@ -152,12 +154,22 @@
    3.13  		{
    3.14              _remote = new RemoteControlDevice(this.Handle);
    3.15              _remote.ButtonPressed += new Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed);
    3.16 -            _remote.iHidHandler.OnHidEvent += HandleHidEvent;             
    3.17 +            _remote.iHidHandler.OnHidEvent += HandleHidEventThreadSafe;             
    3.18  		}
    3.19  
    3.20 -        void HandleHidEvent(object aSender, Hid.HidEvent aHidEvent)
    3.21 +        public void HandleHidEventThreadSafe(object aSender, Hid.HidEvent aHidEvent)
    3.22          {
    3.23 -            listViewEvents.Items.Insert(0, aHidEvent.ListViewItem);
    3.24 +            if (this.InvokeRequired)
    3.25 +            {
    3.26 +                //Not in the proper thread, invoke ourselves
    3.27 +                OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
    3.28 +                this.Invoke(d, new object[] { aSender, aHidEvent });
    3.29 +            }
    3.30 +            else
    3.31 +            {
    3.32 +                //We are in the proper thread
    3.33 +                listViewEvents.Items.Insert(0, aHidEvent.ListViewItem);
    3.34 +            }
    3.35          }
    3.36  
    3.37  		protected override void WndProc(ref Message message)
    3.38 @@ -171,22 +183,24 @@
    3.39  
    3.40  		private bool _remote_ButtonPressed(object sender, RemoteControlEventArgs e)
    3.41  		{
    3.42 +            //Set text from here was disabled because of threading issues
    3.43 +            //That whole thing should be removed anyway
    3.44              bool processed = false;
    3.45  			_timer.Enabled = false;
    3.46              if (e.Button != RemoteControlButton.Unknown)
    3.47              {
    3.48 -                labelButtonName.Text = e.Button.ToString();
    3.49 +                //labelButtonName.Text = e.Button.ToString();
    3.50                  processed = true;
    3.51              }
    3.52              else if (e.MceButton != Hid.UsageTables.WindowsMediaCenterRemoteControl.Null)
    3.53              {
    3.54                  //Display MCE button name
    3.55 -                labelButtonName.Text = e.MceButton.ToString();
    3.56 +                //labelButtonName.Text = e.MceButton.ToString();
    3.57                  //Check if this is an HP extension
    3.58                  if (Enum.IsDefined(typeof(Hid.UsageTables.HpWindowsMediaCenterRemoteControl), (ushort)e.MceButton))
    3.59                  {
    3.60                      //Also display HP button name
    3.61 -                    labelButtonName.Text += " / HP:" + ((Hid.UsageTables.HpWindowsMediaCenterRemoteControl)e.MceButton).ToString();
    3.62 +                    //labelButtonName.Text += " / HP:" + ((Hid.UsageTables.HpWindowsMediaCenterRemoteControl)e.MceButton).ToString();
    3.63                  }
    3.64  
    3.65                  processed = true;                
    3.66 @@ -194,14 +208,14 @@
    3.67              else if (e.ConsumerControl != Hid.UsageTables.ConsumerControl.Null)
    3.68              {
    3.69                  //Display consumer control name
    3.70 -                labelButtonName.Text = e.ConsumerControl.ToString();
    3.71 +                //labelButtonName.Text = e.ConsumerControl.ToString();
    3.72                  processed = true;
    3.73              }
    3.74              else
    3.75              {
    3.76 -                labelButtonName.Text = "Unknown";
    3.77 +                //labelButtonName.Text = "Unknown";
    3.78              }
    3.79 -			labelDeviceName.Text = e.Device.ToString();
    3.80 +			//labelDeviceName.Text = e.Device.ToString();
    3.81  			_timer.Enabled = true;
    3.82              return processed;
    3.83  		}