[Win] Raw input parsing moved to input drivers

This commit is contained in:
thefiddler 2014-07-31 15:44:11 +02:00
parent a51a85c517
commit 3fee0bd8d0
4 changed files with 231 additions and 200 deletions

View file

@ -94,30 +94,28 @@ namespace OpenTK.Platform.Windows
switch (message) switch (message)
{ {
case WindowMessage.INPUT: case WindowMessage.INPUT:
int size = BlittableValueType<RawInput>.Stride;
RawInput data;
//RawInput data;
// Read the actual raw input structure
if (size == Functions.GetRawInputData(lParam, GetRawInputDataEnum.INPUT,
out data, ref size, API.RawInputHeaderSize))
{ {
switch (data.Header.Type) // Retrieve the raw input data buffer
RawInputHeader header;
if (Functions.GetRawInputData(lParam, out header) == RawInputHeader.SizeInBytes)
{ {
case RawInputDeviceType.KEYBOARD: switch (header.Type)
if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref data)) {
return IntPtr.Zero; case RawInputDeviceType.KEYBOARD:
break; if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(lParam))
return IntPtr.Zero;
break;
case RawInputDeviceType.MOUSE: case RawInputDeviceType.MOUSE:
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref data)) if (((WinRawMouse)MouseDriver).ProcessMouseEvent(lParam))
return IntPtr.Zero; return IntPtr.Zero;
break; break;
case RawInputDeviceType.HID: case RawInputDeviceType.HID:
if (((WinRawJoystick)JoystickDriver).ProcessEvent(ref data)) if (((WinRawJoystick)JoystickDriver).ProcessEvent(lParam))
return IntPtr.Zero; return IntPtr.Zero;
break; break;
}
} }
} }
break; break;

View file

@ -137,6 +137,7 @@ namespace OpenTK.Platform.Windows
readonly object UpdateLock = new object(); readonly object UpdateLock = new object();
readonly DeviceCollection<Device> Devices = new DeviceCollection<Device>(); readonly DeviceCollection<Device> Devices = new DeviceCollection<Device>();
byte[] HIDData = new byte[1024];
byte[] PreparsedData = new byte[1024]; byte[] PreparsedData = new byte[1024];
HidProtocolValueCaps[] AxisCaps = new HidProtocolValueCaps[4]; HidProtocolValueCaps[] AxisCaps = new HidProtocolValueCaps[4];
HidProtocolButtonCaps[] ButtonCaps = new HidProtocolButtonCaps[4]; HidProtocolButtonCaps[] ButtonCaps = new HidProtocolButtonCaps[4];
@ -153,8 +154,8 @@ namespace OpenTK.Platform.Windows
Window = window; Window = window;
DeviceTypes = new RawInputDevice[] DeviceTypes = new RawInputDevice[]
{ {
new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.INPUTSINK, window), new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.DEVNOTIFY | RawInputDeviceFlags.EXINPUTSINK, window),
new RawInputDevice(HIDUsageGD.GamePad, RawInputDeviceFlags.INPUTSINK, window), new RawInputDevice(HIDUsageGD.GamePad, RawInputDeviceFlags.DEVNOTIFY | RawInputDeviceFlags.EXINPUTSINK, window),
}; };
if (!Functions.RegisterRawInputDevices(DeviceTypes, DeviceTypes.Length, API.RawInputDeviceSize)) if (!Functions.RegisterRawInputDevices(DeviceTypes, DeviceTypes.Length, API.RawInputDeviceSize))
@ -192,7 +193,8 @@ namespace OpenTK.Platform.Windows
IntPtr handle = dev.Device; IntPtr handle = dev.Device;
Guid guid = GetDeviceGuid(handle); Guid guid = GetDeviceGuid(handle);
long hardware_id = guid.GetHashCode(); //long hardware_id = guid.GetHashCode();
long hardware_id = handle.ToInt64();
Device device = Devices.FromHardwareId(hardware_id); Device device = Devices.FromHardwareId(hardware_id);
if (device != null) if (device != null)
@ -215,64 +217,80 @@ namespace OpenTK.Platform.Windows
} }
} }
public unsafe bool ProcessEvent(ref RawInput rin) public unsafe bool ProcessEvent(IntPtr raw)
{ {
IntPtr handle = rin.Header.Device; // Query the size of the raw HID data buffer
Device stick = GetDevice(handle); int size = 0;
if (stick == null) Functions.GetRawInputData(raw, GetRawInputDataEnum.INPUT, IntPtr.Zero, ref size, RawInputHeader.SizeInBytes);
if (size > HIDData.Length)
{ {
Debug.Print("[WinRawJoystick] Unknown device {0}", handle); Array.Resize(ref HIDData, size);
return false;
} }
if (!GetPreparsedData(handle, ref PreparsedData)) // Retrieve the raw HID data buffer
if (Functions.GetRawInputData(raw, HIDData) > 0)
{ {
return false; fixed (byte* pdata = HIDData)
}
// Detect which axes / buttons are contained in this report
HidProtocolCaps caps;
int axis_caps_count;
int button_caps_count;
if (!GetDeviceCaps(PreparsedData, out caps,
ref AxisCaps, out axis_caps_count,
ref ButtonCaps, out button_caps_count))
{
return false;
}
// Query current state
// Allocate enough storage to hold the data of the current report
int size = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, PreparsedData);
if (size == 0)
{
Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
Marshal.GetLastWin32Error());
return false;
}
// Fill the data buffer
if (DataBuffer.Length < size)
{
Array.Resize(ref DataBuffer, size);
}
fixed (void* pdata = &rin.Data.HID.RawData)
{
if (HidProtocol.GetData(HidProtocolReportType.Input,
DataBuffer, ref size, PreparsedData,
(IntPtr)pdata, rin.Data.HID.Size) != HidProtocolStatus.Success)
{ {
Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}", RawInput* rin = (RawInput*)pdata;
Marshal.GetLastWin32Error());
return false; IntPtr handle = rin->Header.Device;
Device stick = GetDevice(handle);
if (stick == null)
{
Debug.Print("[WinRawJoystick] Unknown device {0}", handle);
return false;
}
if (!GetPreparsedData(handle, ref PreparsedData))
{
return false;
}
// Detect which axes / buttons are contained in this report
HidProtocolCaps caps;
int axis_caps_count;
int button_caps_count;
if (!GetDeviceCaps(PreparsedData, out caps,
ref AxisCaps, out axis_caps_count,
ref ButtonCaps, out button_caps_count))
{
return false;
}
// Query current state
// Allocate enough storage to hold the data of the current report
int report_count = HidProtocol.MaxDataListLength(HidProtocolReportType.Input, PreparsedData);
if (report_count == 0)
{
Debug.Print("[WinRawJoystick] HidProtocol.MaxDataListLength() failed with {0}",
Marshal.GetLastWin32Error());
return false;
}
// Fill the data buffer
if (DataBuffer.Length < report_count)
{
Array.Resize(ref DataBuffer, report_count);
}
if (HidProtocol.GetData(HidProtocolReportType.Input,
DataBuffer, ref size, PreparsedData,
new IntPtr((void*)&rin->Data.HID.RawData),
rin->Data.HID.Size) != HidProtocolStatus.Success)
{
Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
Marshal.GetLastWin32Error());
return false;
}
UpdateAxes(stick, caps, AxisCaps, axis_caps_count, DataBuffer);
UpdateButtons(stick, caps, ButtonCaps, button_caps_count, DataBuffer);
return true;
} }
} }
UpdateAxes(stick, caps, AxisCaps, axis_caps_count, DataBuffer); return false;
UpdateButtons(stick, caps, ButtonCaps, button_caps_count, DataBuffer);
return true;
} }
#endregion #endregion

View file

@ -153,51 +153,57 @@ namespace OpenTK.Platform.Windows
} }
} }
public bool ProcessKeyboardEvent(ref RawInput rin) public bool ProcessKeyboardEvent(IntPtr raw)
{ {
bool processed = false; bool processed = false;
bool pressed = RawInput rin;
rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN || if (Functions.GetRawInputData(raw, out rin) > 0)
rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN;
var scancode = rin.Data.Keyboard.MakeCode;
var vkey = rin.Data.Keyboard.VKey;
bool extended0 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E0) != 0;
bool extended1 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E1) != 0;
bool is_valid = true;
ContextHandle handle = new ContextHandle(rin.Header.Device);
KeyboardState keyboard;
if (!rawids.ContainsKey(handle))
{ {
RefreshDevices(); bool pressed =
rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN ||
rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN;
var scancode = rin.Data.Keyboard.MakeCode;
var vkey = rin.Data.Keyboard.VKey;
bool extended0 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E0) != 0;
bool extended1 = (int)(rin.Data.Keyboard.Flags & RawInputKeyboardDataFlags.E1) != 0;
bool is_valid = true;
ContextHandle handle = new ContextHandle(rin.Header.Device);
KeyboardState keyboard;
if (!rawids.ContainsKey(handle))
{
RefreshDevices();
}
if (keyboards.Count == 0)
return false;
// Note:For some reason, my Microsoft Digital 3000 keyboard reports 0
// as rin.Header.Device for the "zoom-in/zoom-out" buttons.
// That's problematic, because no device has a "0" id.
// As a workaround, we'll add those buttons to the first device (if any).
int keyboard_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
keyboard = keyboards[keyboard_handle];
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended0, extended1, out is_valid);
if (is_valid)
{
keyboard.SetKeyState(key, pressed);
processed = true;
}
lock (UpdateLock)
{
keyboards[keyboard_handle] = keyboard;
processed = true;
}
} }
if (keyboards.Count == 0) return processed;
return false;
// Note:For some reason, my Microsoft Digital 3000 keyboard reports 0
// as rin.Header.Device for the "zoom-in/zoom-out" buttons.
// That's problematic, because no device has a "0" id.
// As a workaround, we'll add those buttons to the first device (if any).
int keyboard_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
keyboard = keyboards[keyboard_handle];
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended0, extended1, out is_valid);
if (is_valid)
{
keyboard.SetKeyState(key, pressed);
processed = true;
}
lock (UpdateLock)
{
keyboards[keyboard_handle] = keyboard;
return processed;
}
} }
#endregion #endregion

View file

@ -149,100 +149,109 @@ namespace OpenTK.Platform.Windows
} }
} }
public bool ProcessMouseEvent(ref RawInput rin) public bool ProcessMouseEvent(IntPtr raw_buffer)
{ {
RawMouse raw = rin.Data.Mouse; bool processed = false;
ContextHandle handle = new ContextHandle(rin.Header.Device);
MouseState mouse; RawInput rin;
if (!rawids.ContainsKey(handle)) if (Functions.GetRawInputData(raw_buffer, out rin) > 0)
{ {
RefreshDevices(); RawMouse raw = rin.Data.Mouse;
ContextHandle handle = new ContextHandle(rin.Header.Device);
MouseState mouse;
if (!rawids.ContainsKey(handle))
{
RefreshDevices();
}
if (mice.Count == 0)
return false;
// Note:For some reason, my Microsoft Digital 3000 keyboard reports 0
// as rin.Header.Device for the "zoom-in/zoom-out" buttons.
// That's problematic, because no device has a "0" id.
// As a workaround, we'll add those buttons to the first device (if any).
int mouse_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
mouse = mice[mouse_handle];
// Set and release capture of the mouse to fix http://www.opentk.com/node/2133, Patch by Artfunkel
if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Left);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Left);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Right);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Right);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Middle);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Middle);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Button1);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Button1);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Button2);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Button2);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
mouse.SetScrollRelative(0, (short)raw.ButtonData / 120.0f);
if ((raw.ButtonFlags & RawInputMouseState.HWHEEL) != 0)
mouse.SetScrollRelative((short)raw.ButtonData / 120.0f, 0);
if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
{
mouse.X = raw.LastX;
mouse.Y = raw.LastY;
}
else
{ // Seems like MOUSE_MOVE_RELATIVE is the default, unless otherwise noted.
mouse.X += raw.LastX;
mouse.Y += raw.LastY;
}
lock (UpdateLock)
{
mice[mouse_handle] = mouse;
processed = true;
}
} }
if (mice.Count == 0) return processed;
return false;
// Note:For some reason, my Microsoft Digital 3000 keyboard reports 0
// as rin.Header.Device for the "zoom-in/zoom-out" buttons.
// That's problematic, because no device has a "0" id.
// As a workaround, we'll add those buttons to the first device (if any).
int mouse_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0;
mouse = mice[mouse_handle];
// Set and release capture of the mouse to fix http://www.opentk.com/node/2133, Patch by Artfunkel
if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_DOWN) != 0){
mouse.EnableBit((int)MouseButton.Left);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.LEFT_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Left);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Right);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.RIGHT_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Right);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Middle);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.MIDDLE_BUTTON_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Middle);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Button1);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_4_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Button1);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_DOWN) != 0)
{
mouse.EnableBit((int)MouseButton.Button2);
Functions.SetCapture(Window);
}
if ((raw.ButtonFlags & RawInputMouseState.BUTTON_5_UP) != 0)
{
mouse.DisableBit((int)MouseButton.Button2);
Functions.ReleaseCapture();
}
if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
mouse.SetScrollRelative(0, (short)raw.ButtonData / 120.0f);
if ((raw.ButtonFlags & RawInputMouseState.HWHEEL) != 0)
mouse.SetScrollRelative((short)raw.ButtonData / 120.0f, 0);
if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
{
mouse.X = raw.LastX;
mouse.Y = raw.LastY;
}
else
{ // Seems like MOUSE_MOVE_RELATIVE is the default, unless otherwise noted.
mouse.X += raw.LastX;
mouse.Y += raw.LastY;
}
lock (UpdateLock)
{
mice[mouse_handle] = mouse;
return true;
}
} }
#endregion #endregion