Files
kaizen/lib/source/gainput/mouse/GainputInputDeviceMouseMac.mm
Simone 4e42229bdd Squashed 'external/gainput/' content from commit 2be0a50
git-subtree-dir: external/gainput
git-subtree-split: 2be0a50089eafcc6fccb66142180082e48f27f4c
2024-01-22 08:51:55 +01:00

167 lines
5.1 KiB
Plaintext

#include <gainput/gainput.h>
#ifdef GAINPUT_PLATFORM_MAC
#include "GainputInputDeviceMouseMac.h"
#include <gainput/GainputInputDeltaState.h>
#include <gainput/GainputHelpers.h>
#include <gainput/GainputLog.h>
#import <AppKit/AppKit.h>
#import <Carbon/Carbon.h>
namespace {
static float theoreticalTitleBarHeight()
{
NSRect frame = NSMakeRect (0, 0, 100, 100);
NSRect contentRect = [NSWindow contentRectForFrameRect:frame
styleMask:NSTitledWindowMask];
return (frame.size.height - contentRect.size.height);
}
CGEventRef MouseTap(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* user)
{
gainput::InputDeviceMouseImplMac* device = reinterpret_cast<gainput::InputDeviceMouseImplMac*>(user);
GAINPUT_ASSERT(device->previousState_);
if (type == kCGEventTapDisabledByTimeout
|| type == kCGEventTapDisabledByUserInput)
{
// Probably timeout, re-enable!
CGEventTapEnable(reinterpret_cast<CFMachPortRef>(device->eventTap_), true);
}
gainput::InputManager& manager = device->manager_;
NSApplication* app = [NSApplication sharedApplication];
NSWindow* window = app.keyWindow;
if (window)
{
CGPoint theLocation = CGEventGetUnflippedLocation(event);
NSRect rect = NSMakeRect(theLocation.x, theLocation.y, 0, 0);
NSRect rect2 = [window convertRectFromScreen:rect];
float titleBarHeight = (window.styleMask & NSFullScreenWindowMask) ? 0.0f : theoreticalTitleBarHeight();
const float x = rect2.origin.x / window.frame.size.width;
const float y = 1.0f - (rect2.origin.y / (window.frame.size.height - titleBarHeight));
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, gainput::MouseAxisX, x);
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, gainput::MouseAxisY, y);
if (type == kCGEventLeftMouseDown || type == kCGEventLeftMouseUp)
{
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, gainput::MouseButton0, type == kCGEventLeftMouseDown);
}
else if (type == kCGEventRightMouseDown || type == kCGEventRightMouseUp)
{
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, gainput::MouseButton2, type == kCGEventRightMouseDown);
}
else if (type == kCGEventOtherMouseDown || type == kCGEventOtherMouseUp)
{
int buttonNum = CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber);
gainput::DeviceButtonId buttonId = gainput::MouseButton1;
if (buttonNum > kCGMouseButtonCenter)
{
buttonId = gainput::MouseButton3 + buttonNum - kCGMouseButtonCenter;
}
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, buttonId, type == kCGEventOtherMouseDown);
}
else if (type == kCGEventScrollWheel)
{
int const deltaAxis = CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1);
if (deltaAxis != 0)
{
manager.EnqueueConcurrentChange(
device->device_,
device->nextState_,
device->delta_,
deltaAxis > 0 ? gainput::MouseButtonWheelDown : gainput::MouseButtonWheelUp,
true);
}
}
}
else
{
// Window was unfocused.
for (unsigned i = gainput::MouseButton0; i < gainput::MouseButtonCount; ++ i)
{
gainput::HandleButton(device->device_, device->nextState_, device->delta_, i, false);
}
}
return event;
}
}
namespace gainput
{
InputDeviceMouseImplMac::InputDeviceMouseImplMac(InputManager& manager, InputDevice& device, InputState& state, InputState& previousState) :
manager_(manager),
device_(device),
state_(&state),
previousState_(&previousState),
nextState_(manager.GetAllocator(), MouseButtonCount + MouseAxisCount),
delta_(0)
{
CGEventMask eventMask =
CGEventMaskBit(kCGEventLeftMouseDown)
| CGEventMaskBit(kCGEventLeftMouseUp)
| CGEventMaskBit(kCGEventRightMouseDown)
| CGEventMaskBit(kCGEventRightMouseUp)
| CGEventMaskBit(kCGEventOtherMouseDown)
| CGEventMaskBit(kCGEventOtherMouseUp)
| CGEventMaskBit(kCGEventMouseMoved)
| CGEventMaskBit(kCGEventLeftMouseDragged)
| CGEventMaskBit(kCGEventRightMouseDragged)
| CGEventMaskBit(kCGEventOtherMouseDragged)
| CGEventMaskBit(kCGEventScrollWheel)
;
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
eventMask,
MouseTap,
this);
if (!eventTap)
{
GAINPUT_ASSERT(false);
return;
}
eventTap_ = eventTap;
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
}
InputDeviceMouseImplMac::~InputDeviceMouseImplMac()
{
CFRelease(reinterpret_cast<CFMachPortRef>(eventTap_));
}
void InputDeviceMouseImplMac::Update(InputDeltaState* delta)
{
delta_ = delta;
// Reset mouse wheel buttons
HandleButton(device_, nextState_, delta_, MouseButtonWheelUp, false);
HandleButton(device_, nextState_, delta_, MouseButtonWheelDown, false);
*state_ = nextState_;
}
}
#endif