Implementing key repeat support.
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 }