diff --git a/3rdparty/libossia b/3rdparty/libossia index dbbf02defb..e8d84aaa46 160000 --- a/3rdparty/libossia +++ b/3rdparty/libossia @@ -1 +1 @@ -Subproject commit dbbf02defbcf580abef3ffeb43597ffd65acae43 +Subproject commit e8d84aaa46e859599cc8cb15cd3c25a5004c0657 diff --git a/src/app/Info.plist.in b/src/app/Info.plist.in index d1f0344f9c..7c6a82a106 100644 --- a/src/app/Info.plist.in +++ b/src/app/Info.plist.in @@ -43,6 +43,9 @@ NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} + NSAppleEventsUsageDescription + ossia score needs assistive access for MIDI keyboard input and minimap movement + NSMicrophoneUsageDescription ossia score needs microphone permission for audio input. diff --git a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIDevice.cpp b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIDevice.cpp index 07a194f134..cc4e9fd40f 100644 --- a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIDevice.cpp +++ b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIDevice.cpp @@ -8,6 +8,8 @@ #include +#include +#include #include #include @@ -29,48 +31,11 @@ #include // clang-format on -#include +#include +#include namespace Protocols { -class MidiKeyboardEventFilter : public QObject -{ -public: - libremidi::kbd_input_configuration::scancode_callback press, release; - MidiKeyboardEventFilter( - libremidi::kbd_input_configuration::scancode_callback press, - libremidi::kbd_input_configuration::scancode_callback release) - : press{std::move(press)} - , release{std::move(release)} - , target{score::GUIAppContext().mainWindow} - { - // X11 quirk - if(qApp->platformName() == "xcb") - scanCodeOffset = -8; - } - - bool eventFilter(QObject* object, QEvent* event) - { - if(object == target) - { - if(event->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(event); - if(!keyEvent->isAutoRepeat()) - press(keyEvent->nativeScanCode() + scanCodeOffset); - } - else if(event->type() == QEvent::KeyRelease) - { - QKeyEvent* keyEvent = static_cast(event); - if(!keyEvent->isAutoRepeat()) - release(keyEvent->nativeScanCode() + scanCodeOffset); - } - } - return false; - } - QObject* target{}; - int scanCodeOffset{0}; -}; MIDIDevice::MIDIDevice( const Device::DeviceSettings& settings, const ossia::net::network_context_ptr& ctx) @@ -119,7 +84,7 @@ bool MIDIDevice::reconnect() case libremidi::API::ALSA_SEQ: { conf.timestamps = libremidi::timestamp_mode::AudioFrame; - auto ptr = std::any_cast(&api_conf); + auto ptr = std::get_if(&api_conf); SCORE_ASSERT(ptr); ptr->client_name = "ossia score"; break; @@ -133,11 +98,13 @@ bool MIDIDevice::reconnect() break; } case libremidi::API::KEYBOARD: { - auto ptr = std::any_cast(&api_conf); + auto ptr = std::get_if(&api_conf); SCORE_ASSERT(ptr); ptr->set_input_scancode_callbacks = [this](auto keypress, auto keyrelease) { m_kbdfilter = new MidiKeyboardEventFilter{keypress, keyrelease}; +#if !defined(__APPLE__) qApp->installEventFilter(m_kbdfilter); +#endif }; break; } diff --git a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.linux.hpp b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.linux.hpp new file mode 100644 index 0000000000..0b5343ef26 --- /dev/null +++ b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.linux.hpp @@ -0,0 +1,62 @@ +#pragma once +#if !defined(__APPLE__) +#include + +#include +#include +#include +#include + +#include + +namespace Protocols +{ +class MidiKeyboardEventFilter : public QObject +{ +public: + libremidi::kbd_input_configuration::scancode_callback press, release; + MidiKeyboardEventFilter( + libremidi::kbd_input_configuration::scancode_callback press, + libremidi::kbd_input_configuration::scancode_callback release) + : press{std::move(press)} + , release{std::move(release)} + , target{score::GUIAppContext().mainWindow} + { + } + + bool eventFilter(QObject* object, QEvent* event) + { + if(object == target) + { + if(event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + if(!keyEvent->isAutoRepeat()) + press(key(*keyEvent)); + } + else if(event->type() == QEvent::KeyRelease) + { + QKeyEvent* keyEvent = static_cast(event); + if(!keyEvent->isAutoRepeat()) + release(key(*keyEvent)); + } + } + return false; + } + + inline uint32_t key(QKeyEvent& e) + { +#if defined(__linux__) + // X11 quirk + static const int scanCodeOffset = (qApp->platformName() == "xcb") ? -8 : 0; + return e.nativeScanCode() - scanCodeOffset; +#elif defined(__APPLE__) + return e.nativeVirtualKey(); +#else + return e.nativeScanCode(); +#endif + } + QObject* target{}; +}; +} +#endif diff --git a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.macos.hpp b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.macos.hpp new file mode 100644 index 0000000000..95cdcc6667 --- /dev/null +++ b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIKeyboardEventFilter.macos.hpp @@ -0,0 +1,53 @@ +#pragma once +#if defined(__APPLE__) +#include +#include + +#include +#include + +namespace Protocols +{ +class MidiKeyboardEventFilter : public QObject +{ +public: + libremidi::kbd_input_configuration::scancode_callback press, release; + MidiKeyboardEventFilter( + libremidi::kbd_input_configuration::scancode_callback press, + libremidi::kbd_input_configuration::scancode_callback release) + : press{std::move(press)} + , release{std::move(release)} + { + CGEventMask mask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) + | CGEventMaskBit(kCGEventScrollWheel) + | CGEventMaskBit(kCGEventLeftMouseDown) + | CGEventMaskBit(kCGEventRightMouseDown); + auto eventTap = CGEventTapCreate( + kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, mask, + [](CGEventTapProxy, CGEventType type, CGEventRef event, void* ctx) { + auto& self = *decltype(this)(ctx); + switch(type) + { + case kCGEventKeyDown: + self.press(CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)); + break; + case kCGEventKeyUp: + self.release(CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)); + break; + } + return event; + }, this); + if(eventTap == nullptr) + return; + + CFRunLoopAddSource( + CFRunLoopGetCurrent(), + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0), + kCFRunLoopCommonModes); + // Enable the event tap. + CGEventTapEnable(eventTap, true); + } +}; +} + +#endif diff --git a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIProtocolFactory.cpp b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIProtocolFactory.cpp index a78b4feb92..7449a0d601 100644 --- a/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIProtocolFactory.cpp +++ b/src/plugins/score-plugin-protocols/Protocols/MIDI/MIDIProtocolFactory.cpp @@ -21,8 +21,10 @@ #include #include -#include +// clang-format off #include +#include +// clang-format on namespace Device { class DeviceInterface; @@ -71,7 +73,7 @@ template class MidiEnumerator : public Device::DeviceEnumerator { libremidi::API m_api = getCurrentAPI(); - std::any m_observer_conf = [this] { + libremidi::observer_api_configuration m_observer_conf = [this] { auto api_conf = libremidi::observer_configuration_for(m_api); libremidi::midi_any::for_observer_configuration([&](auto& conf) { diff --git a/src/plugins/score-plugin-protocols/Protocols/MIDIUtils.hpp b/src/plugins/score-plugin-protocols/Protocols/MIDIUtils.hpp index b2ba43f9e8..fb4a18c88a 100644 --- a/src/plugins/score-plugin-protocols/Protocols/MIDIUtils.hpp +++ b/src/plugins/score-plugin-protocols/Protocols/MIDIUtils.hpp @@ -4,8 +4,7 @@ #include -#include -#include +#include namespace Protocols { inline libremidi::API getCurrentAPI()