[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)
{
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:
if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(ref data))
return IntPtr.Zero;
break;
switch (header.Type)
{
case RawInputDeviceType.KEYBOARD:
if (((WinRawKeyboard)KeyboardDriver).ProcessKeyboardEvent(lParam))
return IntPtr.Zero;
break;
case RawInputDeviceType.MOUSE:
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(ref data))
return IntPtr.Zero;
break;
case RawInputDeviceType.MOUSE:
if (((WinRawMouse)MouseDriver).ProcessMouseEvent(lParam))
return IntPtr.Zero;
break;
case RawInputDeviceType.HID:
if (((WinRawJoystick)JoystickDriver).ProcessEvent(ref data))
return IntPtr.Zero;
break;
case RawInputDeviceType.HID:
if (((WinRawJoystick)JoystickDriver).ProcessEvent(lParam))
return IntPtr.Zero;
break;
}
}
}
break;

View file

@ -137,6 +137,7 @@ namespace OpenTK.Platform.Windows
readonly object UpdateLock = new object();
readonly DeviceCollection<Device> Devices = new DeviceCollection<Device>();
byte[] HIDData = new byte[1024];
byte[] PreparsedData = new byte[1024];
HidProtocolValueCaps[] AxisCaps = new HidProtocolValueCaps[4];
HidProtocolButtonCaps[] ButtonCaps = new HidProtocolButtonCaps[4];
@ -153,8 +154,8 @@ namespace OpenTK.Platform.Windows
Window = window;
DeviceTypes = new RawInputDevice[]
{
new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.INPUTSINK, window),
new RawInputDevice(HIDUsageGD.GamePad, RawInputDeviceFlags.INPUTSINK, window),
new RawInputDevice(HIDUsageGD.Joystick, RawInputDeviceFlags.DEVNOTIFY | RawInputDeviceFlags.EXINPUTSINK, window),
new RawInputDevice(HIDUsageGD.GamePad, RawInputDeviceFlags.DEVNOTIFY | RawInputDeviceFlags.EXINPUTSINK, window),
};
if (!Functions.RegisterRawInputDevices(DeviceTypes, DeviceTypes.Length, API.RawInputDeviceSize))
@ -192,7 +193,8 @@ namespace OpenTK.Platform.Windows
IntPtr handle = dev.Device;
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);
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;
Device stick = GetDevice(handle);
if (stick == null)
// Query the size of the raw HID data buffer
int size = 0;
Functions.GetRawInputData(raw, GetRawInputDataEnum.INPUT, IntPtr.Zero, ref size, RawInputHeader.SizeInBytes);
if (size > HIDData.Length)
{
Debug.Print("[WinRawJoystick] Unknown device {0}", handle);
return false;
Array.Resize(ref HIDData, size);
}
if (!GetPreparsedData(handle, ref PreparsedData))
// Retrieve the raw HID data buffer
if (Functions.GetRawInputData(raw, HIDData) > 0)
{
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 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)
fixed (byte* pdata = HIDData)
{
Debug.Print("[WinRawJoystick] HidProtocol.GetData() failed with {0}",
Marshal.GetLastWin32Error());
return false;
RawInput* rin = (RawInput*)pdata;
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);
UpdateButtons(stick, caps, ButtonCaps, button_caps_count, DataBuffer);
return true;
return false;
}
#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 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))
RawInput rin;
if (Functions.GetRawInputData(raw, out rin) > 0)
{
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 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;
}
return processed;
}
#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;
ContextHandle handle = new ContextHandle(rin.Header.Device);
bool processed = false;
MouseState mouse;
if (!rawids.ContainsKey(handle))
RawInput rin;
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 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;
}
return processed;
}
#endregion