Kaynağa Gözat

WIP: macOS port
- Fixing mouse input

Marko Pintera 7 yıl önce
ebeveyn
işleme
dd6bc560e8

+ 54 - 35
Source/BansheeCore/Private/MacOS/BsMacOSInput.cpp

@@ -212,6 +212,7 @@ namespace bs
 
 		HIDDevice newDevice;
 		newDevice.ref = device;
+		bs_zero_out(newDevice.gamepadAxisTimestamps);
 
 		// Parse device name
 		CFTypeRef propertyRef = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
@@ -368,6 +369,30 @@ namespace bs
 		return (INT32)(normalizedRange * targetRange) + min;
 	}
 
+	/** Callback triggered when an input value changes. */
+	static void HIDValueChangedCallback(void* context, IOReturn result, void* sender, IOHIDValueRef valueRef)
+	{
+		auto data = (HIDData*)context;
+
+		IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
+		auto usage = (UINT32) IOHIDElementGetUsage(elementRef);
+		auto axisValue = (INT32)IOHIDValueGetIntegerValue(valueRef);
+		switch (usage)
+		{
+		case kHIDUsage_GD_X:
+			data->mouseAxisValues[0] += axisValue;
+			break;
+		case kHIDUsage_GD_Y:
+			data->mouseAxisValues[1] += axisValue;
+			break;
+		case kHIDUsage_GD_Z:
+			data->mouseAxisValues[2] += axisValue;
+			break;
+		default:
+			break;
+		}
+	}
+
 	/** Converts a keyboard scan key (as reported by the HID manager) into engine's ButtonCode. */
 	static ButtonCode scanCodeToKeyCode(UINT32 scanCode)
 	{
@@ -525,6 +550,7 @@ namespace bs
 	{
 		mData.type = type;
 		mData.owner = input;
+		bs_zero_out(mData.mouseAxisValues);
 
 		mHIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
 		if(mHIDManager == nullptr)
@@ -560,6 +586,10 @@ namespace bs
 		IOHIDManagerRegisterDeviceMatchingCallback(mHIDManager, HIDDeviceAddedCallback, &mData);
 		IOHIDManagerRegisterDeviceRemovalCallback(mHIDManager, HIDDeviceRemovedCallback, &mData);
 
+		// We only care about input callbacks for mice, so we can accumulate all axis movement
+		if(type == HIDType::Mouse)
+			IOHIDManagerRegisterInputValueCallback(mHIDManager, HIDValueChangedCallback, &mData);
+
 		CFStringRef runLoopMode = getRunLoopMode(type);
 		IOHIDManagerScheduleWithRunLoop(mHIDManager, CFRunLoopGetCurrent(), runLoopMode);
 
@@ -592,6 +622,9 @@ namespace bs
 
 	void HIDManager::capture(IOHIDDeviceRef device, bool ignoreEvents)
 	{
+		if(mData.type == HIDType::Mouse)
+			bs_zero_out(mData.mouseAxisValues);
+
 		// First trigger any callbacks
 		CFStringRef runLoopMode = getRunLoopMode(mData.type);
 		while(CFRunLoopRunInMode(runLoopMode, 0, TRUE) == kCFRunLoopRunHandledSource)
@@ -603,18 +636,16 @@ namespace bs
 				continue;
 
 			// Read non-queued elements
+			// These are generally gamepad axes for which we only care about the latest absolute values
 			if(!ignoreEvents)
 			{
-				INT32 relX, relY, relZ;
-				relX = relY = relZ = 0;
-
 				struct AxisState
 				{
 					bool moved;
 					INT32 value;
 				};
 
-				AxisState axisValues[24];
+				AxisState axisValues[HID_NUM_GAMEPAD_AXES];
 				bs_zero_out(axisValues);
 
 				for (auto& axis : entry.axes)
@@ -670,45 +701,26 @@ namespace bs
 							break;
 						}
 
-						if((INT32)axisType < 24)
+						if((INT32)axisType < HID_NUM_GAMEPAD_AXES)
 						{
+							IOHIDValueRef valueRef;
+							if(IOHIDDeviceGetValue(device, axis.ref, &valueRef) != kIOReturnSuccess)
+								continue;
+
+							// Ignore if axis value didn't change since last query
+							UINT64 timestamp = IOHIDValueGetTimeStamp(valueRef);
+							if(timestamp == entry.gamepadAxisTimestamps[(INT32)axisType])
+								continue;
+
 							axisValues[(INT32)axisType].moved = true;
 							axisValues[(INT32)axisType].value = axisValue;
-						}
 
-					}
-					else if (mData.type == HIDType::Mouse)
-					{
-						INT32 axisValue = HIDGetElementValue(entry, axis);
-						switch (axis.usage)
-						{
-						case kHIDUsage_GD_X:
-							axisType = InputAxis::MouseX;
-							relX += axisValue;
-							break;
-						case kHIDUsage_GD_Y:
-							axisType = InputAxis::MouseY;
-							relY += axisValue;
-							break;
-						case kHIDUsage_GD_Z:
-							axisType = InputAxis::MouseZ;
-							relZ += axisValue;
-							break;
-						default:
-							break;
+							entry.gamepadAxisTimestamps[(INT32)axisType] = timestamp;
 						}
 					}
 				}
 
-				static int dbgi = 0;
-				if(relX != 0 || relY != 0 || relZ != 0)
-				{
-					LOGWRN("Mouse move " + toString(relX) + " " + toString(relY) + " " + toString(relZ) + " " +
-						toString(dbgi++));
-					mData.owner->_notifyMouseMoved(relX, relY, relZ);
-				}
-
-				for(UINT32 i = 0; i < 24; i++)
+				for(UINT32 i = 0; i < HID_NUM_GAMEPAD_AXES; i++)
 				{
 					if(axisValues[i].moved)
 						mData.owner->_notifyAxisMoved(entry.id, (UINT32)i, axisValues[i].value);
@@ -825,6 +837,13 @@ namespace bs
 				CFRelease(valueRef);
 			}
 		}
+
+		// Report mouse axes
+		if (mData.type == HIDType::Mouse)
+		{
+			if (mData.mouseAxisValues[0] != 0 || mData.mouseAxisValues[1] != 0 || mData.mouseAxisValues[2] != 0)
+				mData.owner->_notifyMouseMoved(mData.mouseAxisValues[0], mData.mouseAxisValues[1], mData.mouseAxisValues[2]);
+		}
 	}
 
 	void Input::initRawInput()

+ 7 - 0
Source/BansheeCore/Private/MacOS/BsMacOSInput.h

@@ -7,6 +7,9 @@
 
 namespace bs
 {
+	static constexpr UINT32 HID_NUM_MOUSE_AXES = 3;
+	static constexpr UINT32 HID_NUM_GAMEPAD_AXES = 24;
+
 	/** Available types of devices supported by the HIDManager. */
 	enum class HIDType
 	{
@@ -41,6 +44,8 @@ namespace bs
 		Vector<HIDElement> axes;
 		Vector<HIDElement> buttons;
 		Vector<HIDElement> hats;
+
+		UINT64 gamepadAxisTimestamps[HID_NUM_GAMEPAD_AXES];
 	};
 
 	/** Contains information about all enumerated input devices for a specific HIDManager. */
@@ -49,6 +54,8 @@ namespace bs
 		Vector<HIDDevice> devices;
 		HIDType type;
 		Input* owner = nullptr;
+
+		INT32 mouseAxisValues[HID_NUM_MOUSE_AXES];
 	};
 
 	/**