# HG changeset patch
# User sl
# Date 1419372323 -3600
# Node ID dd603eba46ca6c7dcd7949da8f6e402e6acae98f
# Parent  b3e1770628490dff05cfb8461fa6a8820208ae43
Implementing key repeat support.
diff -r b3e177062849 -r dd603eba46ca HidEvent.cs
--- a/HidEvent.cs	Tue Dec 23 21:17:17 2014 +0100
+++ b/HidEvent.cs	Tue Dec 23 23:05:23 2014 +0100
@@ -6,6 +6,7 @@
 using Microsoft.Win32.SafeHandles;
 using Win32;
 using System.Collections.Generic;
+using System.Timers;
 
 
 namespace Hid
@@ -13,7 +14,7 @@
     /// 
     /// Represent a HID event.
     /// 
-    public class HidEvent
+    public class HidEvent: IDisposable
     {
         public bool IsValid { get; private set; }
         public bool IsForeground { get; private set; }
@@ -29,20 +30,33 @@
         public ushort UsagePage { get; private set; }
         public ushort UsageCollection { get; private set; }
         public uint UsageId { get { return ((uint)UsagePage << 16 | (uint)UsageCollection); } }
-        public List Usages { get; private set; }
+        public List Usages { get; private set; }        
+        public delegate void HidEventRepeatDelegate(HidEvent aHidEvent);
+        public event HidEventRepeatDelegate OnHidEventRepeat;
 
+        private System.Timers.Timer Timer { get; set; }
+
+
+        public void Dispose()
+        {
+            Timer.Enabled = false;
+            Timer.Dispose();
+            Timer = null;
+        }
 
         /// 
         /// Initialize an HidEvent from a WM_INPUT message
         /// 
         /// Device Handle as provided by RAWINPUTHEADER.hDevice, typically accessed as rawinput.header.hDevice
-        public HidEvent(Message aMessage)
+        public HidEvent(Message aMessage, HidEventRepeatDelegate aRepeatDelegate)
         {
             IsValid = false;
             IsKeyboard = false;
             IsGeneric = false;
 
+            Timer = new System.Timers.Timer();
             Usages = new List();
+            OnHidEventRepeat += aRepeatDelegate;
 
             if (aMessage.Msg != Const.WM_INPUT)
             {
@@ -175,6 +189,11 @@
                 Marshal.FreeHGlobal(preParsedData);
             }
 
+            if (Usages[0]!=0)
+            {
+                StartRepeatTimer(SystemInformation.KeyboardDelay*250+250);
+            }
+            
             IsValid = true;
         }
 
@@ -226,7 +245,24 @@
                 }
         }
 
+        public void StartRepeatTimer(double aInterval)
+        {
+            if (Timer == null)
+            {
+                return;
+            }
+            Timer.Enabled = false;
+            Timer.AutoReset = false;
+            Timer.Interval = aInterval;
+            Timer.Elapsed += (sender, e) => OnRepeatTimerElapsed(sender, e, this);            
+            Timer.Enabled = true;
+        }
 
+        private void OnRepeatTimerElapsed(object sender, ElapsedEventArgs e, HidEvent aHidEvent)
+        {
+            StartRepeatTimer(1000/(SystemInformation.KeyboardSpeed+2.5));            
+            OnHidEventRepeat(aHidEvent);
+        }
 
     }
 
diff -r b3e177062849 -r dd603eba46ca HidHandler.cs
--- a/HidHandler.cs	Tue Dec 23 21:17:17 2014 +0100
+++ b/HidHandler.cs	Tue Dec 23 23:05:23 2014 +0100
@@ -19,18 +19,20 @@
     {
         public delegate void HidEventHandler(object aSender, HidEvent aHidEvent);
         public event HidEventHandler OnHidEvent;
+        List iHidEvents;
+
 
         public bool IsRegistered { get; private set; }
 
         public HidHandler(RAWINPUTDEVICE[] aRawInputDevices)
         {
+            iHidEvents=new List();
             IsRegistered = Function.RegisterRawInputDevices(aRawInputDevices, (uint)aRawInputDevices.Length, (uint)Marshal.SizeOf(aRawInputDevices[0]));
         }
 
-
         public void ProcessInput(Message aMessage)
         {
-            Hid.HidEvent hidEvent = new Hid.HidEvent(aMessage);
+            Hid.HidEvent hidEvent = new Hid.HidEvent(aMessage, OnHidEventRepeat);
             hidEvent.DebugWrite();
 
             if (!hidEvent.IsValid || !hidEvent.IsGeneric)
@@ -39,10 +41,36 @@
                 return;
             }
 
+            //
+            if (hidEvent.Usages[0] == 0)
+            {
+                //This is a key up event
+                //We need to discard any events belonging to the same page and collection
+                for (int i = (iHidEvents.Count-1); i >= 0; i--)
+                {
+                    if (iHidEvents[i].UsageId == hidEvent.UsageId)
+                    {
+                        iHidEvents[i].Dispose();
+                        iHidEvents.RemoveAt(i);
+                    }
+                }
+            }
+            else
+            {
+                //Keep that event until we get a key up message
+                iHidEvents.Add(hidEvent);
+            }
+
             //Broadcast our events
             OnHidEvent(this, hidEvent);    
         }
 
+        public void OnHidEventRepeat(HidEvent aHidEvent)
+        {
+            //Broadcast our events
+            OnHidEvent(this, aHidEvent);    
+        }
+
     }
 
 }
\ No newline at end of file
diff -r b3e177062849 -r dd603eba46ca MainForm.cs
--- a/MainForm.cs	Tue Dec 23 21:17:17 2014 +0100
+++ b/MainForm.cs	Tue Dec 23 23:05:23 2014 +0100
@@ -26,6 +26,8 @@
         private ColumnHeader columnHeaderUsageCollection;
 		private Timer _timer;
 
+        public delegate void OnHidEventDelegate(object aSender, Hid.HidEvent aHidEvent);
+
 		public MainForm()
 		{
 			//
@@ -152,12 +154,22 @@
 		{
             _remote = new RemoteControlDevice(this.Handle);
             _remote.ButtonPressed += new Devices.RemoteControl.RemoteControlDevice.RemoteControlDeviceEventHandler(_remote_ButtonPressed);
-            _remote.iHidHandler.OnHidEvent += HandleHidEvent;             
+            _remote.iHidHandler.OnHidEvent += HandleHidEventThreadSafe;             
 		}
 
-        void HandleHidEvent(object aSender, Hid.HidEvent aHidEvent)
+        public void HandleHidEventThreadSafe(object aSender, Hid.HidEvent aHidEvent)
         {
-            listViewEvents.Items.Insert(0, aHidEvent.ListViewItem);
+            if (this.InvokeRequired)
+            {
+                //Not in the proper thread, invoke ourselves
+                OnHidEventDelegate d = new OnHidEventDelegate(HandleHidEventThreadSafe);
+                this.Invoke(d, new object[] { aSender, aHidEvent });
+            }
+            else
+            {
+                //We are in the proper thread
+                listViewEvents.Items.Insert(0, aHidEvent.ListViewItem);
+            }
         }
 
 		protected override void WndProc(ref Message message)
@@ -171,22 +183,24 @@
 
 		private bool _remote_ButtonPressed(object sender, RemoteControlEventArgs e)
 		{
+            //Set text from here was disabled because of threading issues
+            //That whole thing should be removed anyway
             bool processed = false;
 			_timer.Enabled = false;
             if (e.Button != RemoteControlButton.Unknown)
             {
-                labelButtonName.Text = e.Button.ToString();
+                //labelButtonName.Text = e.Button.ToString();
                 processed = true;
             }
             else if (e.MceButton != Hid.UsageTables.WindowsMediaCenterRemoteControl.Null)
             {
                 //Display MCE button name
-                labelButtonName.Text = e.MceButton.ToString();
+                //labelButtonName.Text = e.MceButton.ToString();
                 //Check if this is an HP extension
                 if (Enum.IsDefined(typeof(Hid.UsageTables.HpWindowsMediaCenterRemoteControl), (ushort)e.MceButton))
                 {
                     //Also display HP button name
-                    labelButtonName.Text += " / HP:" + ((Hid.UsageTables.HpWindowsMediaCenterRemoteControl)e.MceButton).ToString();
+                    //labelButtonName.Text += " / HP:" + ((Hid.UsageTables.HpWindowsMediaCenterRemoteControl)e.MceButton).ToString();
                 }
 
                 processed = true;                
@@ -194,14 +208,14 @@
             else if (e.ConsumerControl != Hid.UsageTables.ConsumerControl.Null)
             {
                 //Display consumer control name
-                labelButtonName.Text = e.ConsumerControl.ToString();
+                //labelButtonName.Text = e.ConsumerControl.ToString();
                 processed = true;
             }
             else
             {
-                labelButtonName.Text = "Unknown";
+                //labelButtonName.Text = "Unknown";
             }
-			labelDeviceName.Text = e.Device.ToString();
+			//labelDeviceName.Text = e.Device.ToString();
 			_timer.Enabled = true;
             return processed;
 		}