// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using SharpDX.Multimedia;
using SharpDX.Win32;
namespace SharpDX.RawInput
{
///
/// Provides access to RawInput methods.
///
public partial class Device
{
private static RawInputMessageFilter rawInputMessageFilter;
///
/// Occurs when [keyboard input].
///
public static event EventHandler KeyboardInput;
///
/// Occurs when [mouse input].
///
public static event EventHandler MouseInput;
///
/// Occurs when [raw input].
///
public static event EventHandler RawInput;
///
/// Gets the devices.
///
///
public static unsafe List GetDevices()
{
// Get the number of input device
int deviceCount = 0;
RawInputFunctions.GetRawInputDeviceList(null, ref deviceCount, Utilities.SizeOf());
if (deviceCount == 0)
return null;
// Get the raw input device list
var rawInputDeviceList = new RawInputDevicelist[deviceCount];
RawInputFunctions.GetRawInputDeviceList(rawInputDeviceList, ref deviceCount, Utilities.SizeOf());
var deviceInfoList = new List();
// Iterate on all input device
for (int i = 0; i < deviceCount; i++)
{
var deviceHandle = rawInputDeviceList[i].Device;
// Get the DeviceName
int countDeviceNameChars = 0;
RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceName, IntPtr.Zero, ref countDeviceNameChars);
char* deviceNamePtr = stackalloc char[countDeviceNameChars];
RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceName, (IntPtr)deviceNamePtr, ref countDeviceNameChars);
var nullCharIndex = 0;
while (nullCharIndex <= countDeviceNameChars && deviceNamePtr[nullCharIndex++] != '\0') ;
var deviceName = new string(deviceNamePtr, 0, nullCharIndex == 0 ? 0 : nullCharIndex - 1);
// Get the DeviceInfo
int sizeOfDeviceInfo = 0;
RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceInfo, IntPtr.Zero, ref sizeOfDeviceInfo);
byte* deviceInfoPtr = stackalloc byte[sizeOfDeviceInfo];
RawInputFunctions.GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.DeviceInfo, (IntPtr)deviceInfoPtr, ref sizeOfDeviceInfo);
deviceInfoList.Add(DeviceInfo.Convert(ref *(RawDeviceInformation*)deviceInfoPtr, deviceName, deviceHandle));
}
return deviceInfoList;
}
///
/// Registers the devices that supply the raw input data.
///
/// The usage page.
/// The usage id.
/// The flags.
public static void RegisterDevice(UsagePage usagePage, UsageId usageId, DeviceFlags flags)
{
RegisterDevice(usagePage, usageId, flags, IntPtr.Zero);
}
///
/// Registers the devices that supply the raw input data.
///
/// The usage page.
/// The usage id.
/// The flags.
/// The target.
/// The options.
public static void RegisterDevice(UsagePage usagePage, UsageId usageId, DeviceFlags flags, IntPtr target, RegisterDeviceOptions options = RegisterDeviceOptions.Default)
{
var rawInputDevices = new RawInputDevice[1];
rawInputDevices[0].UsagePage = (short)usagePage;
rawInputDevices[0].Usage = (short)usageId;
rawInputDevices[0].Flags = (int)flags;
rawInputDevices[0].Target = target;
// Register this device
RawInputFunctions.RegisterRawInputDevices(rawInputDevices, 1, Utilities.SizeOf());
if (options != RegisterDeviceOptions.NoFiltering && rawInputMessageFilter == null)
{
rawInputMessageFilter = new RawInputMessageFilter();
if (options == RegisterDeviceOptions.Default)
{
Application.AddMessageFilter(rawInputMessageFilter);
}
else
{
MessageFilterHook.AddMessageFilter(target, rawInputMessageFilter);
}
}
}
///
/// Handles a RawInput message manually.
///
/// A pointer to a RawInput message.
/// The handle of the window that received the RawInput message.
///
/// This method can be used directly when handling RawInput messages from non-WinForms application.
///
public static void HandleMessage(IntPtr rawInputMessagePointer, IntPtr hwnd)
{
unsafe
{
// Get the size of the RawInput structure
int sizeOfRawInputData = 0;
RawInputFunctions.GetRawInputData(rawInputMessagePointer, RawInputDataType.Input, IntPtr.Zero, ref sizeOfRawInputData, Utilities.SizeOf());
if (sizeOfRawInputData == 0)
return;
// Get the RawInput data structure
var rawInputDataPtr = stackalloc byte[sizeOfRawInputData];
RawInputFunctions.GetRawInputData(rawInputMessagePointer, RawInputDataType.Input, (IntPtr)rawInputDataPtr, ref sizeOfRawInputData, Utilities.SizeOf());
var rawInput = (RawInput*)rawInputDataPtr;
switch (rawInput->Header.Type)
{
case DeviceType.HumanInputDevice:
if (RawInput != null)
RawInput(null, new HidInputEventArgs(ref *rawInput, hwnd));
break;
case DeviceType.Keyboard:
if (KeyboardInput != null)
KeyboardInput(null, new KeyboardInputEventArgs(ref *rawInput, hwnd));
break;
case DeviceType.Mouse:
if (MouseInput != null)
MouseInput(null, new MouseInputEventArgs(ref *rawInput, hwnd));
break;
}
}
}
///
/// Internal RawInput message filtering
///
internal class RawInputMessageFilter : IMessageFilter
{
///
/// WM_INPUT
///
private const int WmInput = 0x00FF;
public virtual bool PreFilterMessage(ref Message m)
{
// Handle only WM_INPUT messages
if (m.Msg == WmInput)
HandleMessage(m.LParam, m.HWnd);
return false;
}
}
}
}