diff --git a/ruby/input/mouse/quartz.cpp b/ruby/input/mouse/quartz.cpp new file mode 100644 index 00000000..7c66c8ba --- /dev/null +++ b/ruby/input/mouse/quartz.cpp @@ -0,0 +1,82 @@ +#pragma once + +struct InputMouseQuartz { + Input& input; + InputMouseQuartz(Input& input) : input(input) {} + + shared_pointer hid{new HID::Mouse}; + + bool mouseAcquired = false; + + auto acquire() -> bool { + if(!mouseAcquired) { + CGError error = CGAssociateMouseAndMouseCursorPosition(NO); + if(error != kCGErrorSuccess) return false; + [NSCursor hide]; + + mouseAcquired = true; + } + return true; + } + + auto acquired() -> bool { + return mouseAcquired; + } + + auto release() -> bool { + if(mouseAcquired) { + CGError error = CGAssociateMouseAndMouseCursorPosition(YES); + if(error != kCGErrorSuccess) return false; + [NSCursor unhide]; + + mouseAcquired = false; + } + return true; + } + + auto assign(uint groupID, uint inputID, int16_t value) -> void { + auto& group = hid->group(groupID); + if(group.input(inputID).value() == value) return; + input.doChange(hid, groupID, inputID, group.input(inputID).value(), value); + group.input(inputID).setValue(value); + } + + auto poll(vector>& devices) -> void { + int deltaX, deltaY; + CGGetLastMouseDelta(&deltaX, &deltaY); + + assign(HID::Mouse::GroupID::Axis, 0, deltaX); + assign(HID::Mouse::GroupID::Axis, 1, deltaY); + + NSUInteger buttons = [NSEvent pressedMouseButtons]; + + assign(HID::Mouse::GroupID::Button, 0, !!(buttons & (1 << 0))); + assign(HID::Mouse::GroupID::Button, 2, !!(buttons & (1 << 1))); + assign(HID::Mouse::GroupID::Button, 1, !!(buttons & (1 << 2))); + assign(HID::Mouse::GroupID::Button, 4, !!(buttons & (1 << 3))); + assign(HID::Mouse::GroupID::Button, 3, !!(buttons & (1 << 4))); + + devices.append(hid); + } + + auto initialize() -> bool { + hid->setVendorID(HID::Mouse::GenericVendorID); + hid->setProductID(HID::Mouse::GenericProductID); + hid->setPathID(0); + + hid->axes().append("X"); + hid->axes().append("Y"); + + hid->buttons().append("Left"); + hid->buttons().append("Middle"); + hid->buttons().append("Right"); + hid->buttons().append("Up"); + hid->buttons().append("Down"); + + return true; + } + + auto terminate() -> void { + release(); + } +}; diff --git a/ruby/input/quartz.cpp b/ruby/input/quartz.cpp index 2c07a5b7..781dd85b 100644 --- a/ruby/input/quartz.cpp +++ b/ruby/input/quartz.cpp @@ -1,9 +1,10 @@ #include "keyboard/quartz.cpp" +#include "mouse/quartz.cpp" #include "joypad/iokit.cpp" struct InputQuartz : InputDriver { InputQuartz& self = *this; - InputQuartz(Input& super) : InputDriver(super), keyboard(super), joypad(super) {} + InputQuartz(Input& super) : InputDriver(super), keyboard(super), mouse(super), joypad(super) {} ~InputQuartz() { terminate(); } auto create() -> bool override { @@ -13,13 +14,14 @@ struct InputQuartz : InputDriver { auto driver() -> string override { return "Quartz"; } auto ready() -> bool override { return isReady; } - auto acquired() -> bool override { return false; } - auto acquire() -> bool override { return false; } - auto release() -> bool override { return false; } + auto acquired() -> bool override { return mouse.acquired(); } + auto acquire() -> bool override { return mouse.acquire(); } + auto release() -> bool override { return mouse.release(); } auto poll() -> vector> override { vector> devices; keyboard.poll(devices); + mouse.poll(devices); joypad.poll(devices); return devices; } @@ -32,6 +34,7 @@ private: auto initialize() -> bool { terminate(); if(!keyboard.initialize()) return false; + if(!mouse.initialize()) return false; if(!joypad.initialize()) return false; return isReady = true; } @@ -39,10 +42,12 @@ private: auto terminate() -> void { isReady = false; keyboard.terminate(); + mouse.terminate(); joypad.terminate(); } bool isReady = false; InputKeyboardQuartz keyboard; + InputMouseQuartz mouse; InputJoypadIOKit joypad; };