diff --git a/doc/newsfragments/keystrokes-on-active-screen-only.feature b/doc/newsfragments/keystrokes-on-active-screen-only.feature new file mode 100644 index 00000000..4553029f --- /dev/null +++ b/doc/newsfragments/keystrokes-on-active-screen-only.feature @@ -0,0 +1,12 @@ +Added the ability to perform keystroke actions on a specific screen only, by adding the flag `activeScreenOnly` to the action (after the screens parameter) e.g. + +`keystroke(Control) = keystroke(Super,Mac-Mini,activeScreenOnly)` + +This works for both server and clients, with the exception being for keystroke actions intended for the server where the keystroke matches the condition (for instance, adding a custom action on a client, but preserving the original keystroke on the server) e.g. + +`keystroke(Control) = keystroke(Super,Mac-Mini,activeScreenOnly), keystroke(Alt,Server,activeScreenOnly)` // This works +`keystroke(Control) = keystroke(Super,Mac-Mini,activeScreenOnly), keystroke(Control,Server,activeScreenOnly)` // This does not work + +Since Barrier registers a hotkey for the keystroke condition on the server, this prevents the ability to specify the original keystroke as an action for the server. For this, a new option for the condition allows disabling hotkey registration. This allows the original keystroke to be performed on the primary when it is in focus i.e. + +`keystroke(Control,disableGlobalHotkeyRegister) = keystroke(Super,Rajveer-Mac-Mini,activeScreenOnly)` // This allows the original keystroke to perform on the server diff --git a/src/lib/barrier/IKeyState.cpp b/src/lib/barrier/IKeyState.cpp index e89c0e9d..f4766073 100644 --- a/src/lib/barrier/IKeyState.cpp +++ b/src/lib/barrier/IKeyState.cpp @@ -43,6 +43,7 @@ IKeyState::KeyInfo::alloc(KeyID id, info->m_mask = mask; info->m_button = button; info->m_count = count; + info->m_activeScreenOnly = false; info->m_screens = NULL; info->m_screensBuffer[0] = '\0'; return info; @@ -51,7 +52,7 @@ IKeyState::KeyInfo::alloc(KeyID id, IKeyState::KeyInfo* IKeyState::KeyInfo::alloc(KeyID id, KeyModifierMask mask, KeyButton button, SInt32 count, - const std::set& destinations) + const std::set& destinations, bool activeScreenOnly) { String screens = join(destinations); @@ -61,6 +62,7 @@ IKeyState::KeyInfo::alloc(KeyID id, info->m_mask = mask; info->m_button = button; info->m_count = count; + info->m_activeScreenOnly = activeScreenOnly; info->m_screens = info->m_screensBuffer; strcpy(info->m_screensBuffer, screens.c_str()); return info; @@ -75,6 +77,7 @@ IKeyState::KeyInfo::alloc(const KeyInfo& x) info->m_mask = x.m_mask; info->m_button = x.m_button; info->m_count = x.m_count; + info->m_activeScreenOnly = x.m_activeScreenOnly; info->m_screens = x.m_screens ? info->m_screensBuffer : NULL; strcpy(info->m_screensBuffer, x.m_screensBuffer); return info; diff --git a/src/lib/barrier/IKeyState.h b/src/lib/barrier/IKeyState.h index e7f88fa9..0f5bc70f 100644 --- a/src/lib/barrier/IKeyState.h +++ b/src/lib/barrier/IKeyState.h @@ -44,7 +44,7 @@ public: public: static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count, - const std::set& destinations); + const std::set& destinations, bool activeScreenOnly); static KeyInfo* alloc(const KeyInfo&); static bool isDefault(const char* screens); @@ -58,6 +58,7 @@ public: KeyModifierMask m_mask; KeyButton m_button; SInt32 m_count; + bool m_activeScreenOnly; char* m_screens; char m_screensBuffer[1]; }; diff --git a/src/lib/barrier/IPlatformScreen.h b/src/lib/barrier/IPlatformScreen.h index 995ff733..65e1522a 100644 --- a/src/lib/barrier/IPlatformScreen.h +++ b/src/lib/barrier/IPlatformScreen.h @@ -155,8 +155,8 @@ public: // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0; - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; - virtual void unregisterHotKey(UInt32 id) = 0; + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) = 0; + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) = 0; virtual void fakeInputBegin() = 0; virtual void fakeInputEnd() = 0; virtual SInt32 getJumpZoneSize() const = 0; diff --git a/src/lib/barrier/IPrimaryScreen.h b/src/lib/barrier/IPrimaryScreen.h index 0cf3688a..b0dda2eb 100644 --- a/src/lib/barrier/IPrimaryScreen.h +++ b/src/lib/barrier/IPrimaryScreen.h @@ -111,13 +111,13 @@ public: the modifiers in any order or to require the user to press the given key last. */ - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) = 0; //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ - virtual void unregisterHotKey(UInt32 id) = 0; + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) = 0; //! Prepare to synthesize input on primary screen /*! diff --git a/src/lib/barrier/PlatformScreen.h b/src/lib/barrier/PlatformScreen.h index 19a3da10..a6fec7fb 100644 --- a/src/lib/barrier/PlatformScreen.h +++ b/src/lib/barrier/PlatformScreen.h @@ -44,8 +44,8 @@ public: virtual void reconfigure(UInt32 activeSides) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual UInt32 registerHotKey(KeyID key, - KeyModifierMask mask) = 0; - virtual void unregisterHotKey(UInt32 id) = 0; + KeyModifierMask mask, bool registerGlobalHotkey) = 0; + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) = 0; virtual void fakeInputBegin() = 0; virtual void fakeInputEnd() = 0; virtual SInt32 getJumpZoneSize() const = 0; diff --git a/src/lib/barrier/Screen.cpp b/src/lib/barrier/Screen.cpp index 2a2c8776..2011e9c5 100644 --- a/src/lib/barrier/Screen.cpp +++ b/src/lib/barrier/Screen.cpp @@ -330,15 +330,15 @@ Screen::setSequenceNumber(UInt32 seqNum) } UInt32 -Screen::registerHotKey(KeyID key, KeyModifierMask mask) +Screen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) { - return m_screen->registerHotKey(key, mask); + return m_screen->registerHotKey(key, mask, registerGlobalHotkey); } void -Screen::unregisterHotKey(UInt32 id) +Screen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) { - m_screen->unregisterHotKey(id); + m_screen->unregisterHotKey(id, unregisterGlobalHotkey); } void diff --git a/src/lib/barrier/Screen.h b/src/lib/barrier/Screen.h index 1c8e7dec..9b94a9e6 100644 --- a/src/lib/barrier/Screen.h +++ b/src/lib/barrier/Screen.h @@ -198,13 +198,13 @@ public: Registers a system-wide hotkey for key \p key with modifiers \p mask. Returns an id used to unregister the hotkey. */ - UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey); //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ - void unregisterHotKey(UInt32 id); + void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey); //! Prepare to synthesize input on primary screen /*! diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index c995a40d..d51f2b5f 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -548,7 +548,7 @@ void MSWindowsScreen::saveMousePosition(SInt32 x, SInt32 y) { } UInt32 -MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) +MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) { // only allow certain modifiers if ((mask & ~(KeyModifierShift | KeyModifierControl | @@ -599,12 +599,12 @@ MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) } // if this hot key has modifiers only then we'll handle it specially - bool err; + bool err = false; if (key == kKeyNone) { // check if already registered err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0); } - else { + else if (registerGlobalHotkey) { // register with OS err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); } @@ -625,7 +625,7 @@ MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) } void -MSWindowsScreen::unregisterHotKey(UInt32 id) +MSWindowsScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); @@ -634,13 +634,10 @@ MSWindowsScreen::unregisterHotKey(UInt32 id) } // unregister with OS - bool err; - if (i->second.getVirtualKey() != 0) { + bool err = false; + if (unregisterGlobalHotkey && i->second.getVirtualKey() != 0) { err = !UnregisterHotKey(NULL, id); } - else { - err = false; - } if (err) { LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); } diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index eaa7b88a..c7d3944e 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -80,8 +80,8 @@ public: virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); virtual UInt32 registerHotKey(KeyID key, - KeyModifierMask mask); - virtual void unregisterHotKey(UInt32 id); + KeyModifierMask mask, bool registerGlobalHotkey); + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h index 691b74c4..b32a6faf 100644 --- a/src/lib/platform/OSXScreen.h +++ b/src/lib/platform/OSXScreen.h @@ -68,8 +68,8 @@ public: // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); - virtual void unregisterHotKey(UInt32 id); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey); + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index d41e321b..839b8876 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -315,7 +315,7 @@ OSXScreen::getCursorCenter(SInt32& x, SInt32& y) const } UInt32 -OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) +OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) { // get mac virtual key and modifier mask matching barrier key and mask UInt32 macKey, macMask; @@ -336,7 +336,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) // if this hot key has modifiers only then we'll handle it specially EventHotKeyRef ref = NULL; - bool okay; + bool okay = true; if (key == kKeyNone) { if (m_modifierHotKeys.count(mask) > 0) { // already registered @@ -348,11 +348,13 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) } } else { - EventHotKeyID hkid = { 'SNRG', (UInt32)id }; - OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, - GetApplicationEventTarget(), 0, - &ref); - okay = (status == noErr); + if (registerGlobalHotkey) { + EventHotKeyID hkid = { 'SNRG', (UInt32)id }; + OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, + GetApplicationEventTarget(), 0, + &ref); + okay = (status == noErr); + } m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id; } @@ -370,7 +372,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) } void -OSXScreen::unregisterHotKey(UInt32 id) +OSXScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); @@ -379,9 +381,11 @@ OSXScreen::unregisterHotKey(UInt32 id) } // unregister with OS - bool okay; + bool okay = true; if (i->second.getRef() != NULL) { - okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); + if (unregisterGlobalHotkey) { + okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); + } } else { okay = false; diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index 7f8ce655..e3747c73 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -524,7 +524,7 @@ XWindowsScreen::warpCursor(SInt32 x, SInt32 y) } UInt32 -XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) +XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) { // only allow certain modifiers if ((mask & ~(KeyModifierShift | KeyModifierControl | @@ -642,8 +642,10 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) { KeyCode code = modifiermap[k]; if (modifiermap[k] != 0) { - m_impl->XGrabKey(m_display, code, modifiers2, m_root, - False, GrabModeAsync, GrabModeAsync); + if (registerGlobalHotkey) { + m_impl->XGrabKey(m_display, code, modifiers2, m_root, + False, GrabModeAsync, GrabModeAsync); + } if (!err) { hotKeys.push_back(std::make_pair(code, modifiers2)); m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id; @@ -689,8 +691,10 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) } // add grab - m_impl->XGrabKey(m_display, *j, tmpModifiers, m_root, - False, GrabModeAsync, GrabModeAsync); + if (registerGlobalHotkey) { + m_impl->XGrabKey(m_display, *j, tmpModifiers, m_root, + False, GrabModeAsync, GrabModeAsync); + } if (!err) { hotKeys.push_back(std::make_pair(*j, tmpModifiers)); m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id; @@ -719,7 +723,7 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) } void -XWindowsScreen::unregisterHotKey(UInt32 id) +XWindowsScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); @@ -734,7 +738,9 @@ XWindowsScreen::unregisterHotKey(UInt32 id) HotKeyList& hotKeys = i->second; for (HotKeyList::iterator j = hotKeys.begin(); j != hotKeys.end(); ++j) { - m_impl->XUngrabKey(m_display, j->first, j->second, m_root); + if (unregisterGlobalHotkey) { + m_impl->XUngrabKey(m_display, j->first, j->second, m_root); + } m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); } } diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h index 581e91ff..8bf7902f 100644 --- a/src/lib/platform/XWindowsScreen.h +++ b/src/lib/platform/XWindowsScreen.h @@ -53,8 +53,8 @@ public: // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); - virtual void unregisterHotKey(UInt32 id); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey); + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; diff --git a/src/lib/server/Config.cpp b/src/lib/server/Config.cpp index bcdb88cd..22a5f187 100644 --- a/src/lib/server/Config.cpp +++ b/src/lib/server/Config.cpp @@ -1029,13 +1029,19 @@ InputFilter::Condition* Config::parseCondition(ConfigReadContext& s, const std:: const std::vector& args) { if (name == "keystroke") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)"); + if (args.size() < 1 || args.size() > 2) { + throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key[,options])"); } IPlatformScreen::KeyInfo* keyInfo = s.parseKeystroke(args[0]); + bool disableGlobalHotkeyRegister = false; - return new InputFilter::KeystrokeCondition(m_events, keyInfo); + if (args.size() > 1) + { + parseKeystrokeConditionOptions(s, args[1], disableGlobalHotkeyRegister); + } + + return new InputFilter::KeystrokeCondition(m_events, keyInfo, disableGlobalHotkeyRegister); } if (name == "mousebutton") { @@ -1074,8 +1080,8 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name, InputFilter::Action* action; if (name == "keystroke" || name == "keyDown" || name == "keyUp") { - if (args.size() < 1 || args.size() > 2) { - throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens])"); + if (args.size() < 1 || args.size() > 3) { + throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens[,options]])"); } IPlatformScreen::KeyInfo* keyInfo; @@ -1085,7 +1091,12 @@ void Config::parseAction(ConfigReadContext& s, const std::string& name, else { std::set screens; parseScreens(s, args[1], screens); - keyInfo = s.parseKeystroke(args[0], screens); + bool activeScreenOnly = false; + if (args.size() > 2) + { + parseKeystrokeActionOptions(s, args[2], activeScreenOnly); + } + keyInfo = s.parseKeystroke(args[0], screens, activeScreenOnly); } if (name == "keystroke") { @@ -1288,6 +1299,32 @@ void Config::parseScreens(ConfigReadContext& c, const std::string& s, } } +void Config::parseKeystrokeConditionOptions(ConfigReadContext& c, const std::string& s, + bool& disableGlobalHotkeyRegister) const +{ + if (s == "disableGlobalHotkeyRegister") + { + disableGlobalHotkeyRegister = true; + } + else + { + disableGlobalHotkeyRegister = false; + } +} + +void Config::parseKeystrokeActionOptions(ConfigReadContext& c, const std::string& s, + bool& activeScreenOnly) const +{ + if (s == "activeScreenOnly") + { + activeScreenOnly = true; + } + else + { + activeScreenOnly = false; + } +} + const char* Config::getOptionName(OptionID id) { @@ -2184,6 +2221,13 @@ IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const std::string& k IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const std::string& keystroke, const std::set& screens) const +{ + return parseKeystroke(keystroke, screens, false); +} + +IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const std::string& keystroke, + const std::set& screens, + const bool& activeScreenOnly) const { std::string s = keystroke; @@ -2201,7 +2245,7 @@ IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const std::string& k throw XConfigRead(*this, "missing key and/or modifiers in keystroke"); } - return IPlatformScreen::KeyInfo::alloc(key, mask, 0, 0, screens); + return IPlatformScreen::KeyInfo::alloc(key, mask, 0, 0, screens, activeScreenOnly); } IPlatformScreen::ButtonInfo* diff --git a/src/lib/server/Config.h b/src/lib/server/Config.h index 17756a0a..4fb0453a 100644 --- a/src/lib/server/Config.h +++ b/src/lib/server/Config.h @@ -453,6 +453,9 @@ private: void parseScreens(ConfigReadContext&, const std::string&, std::set& screens) const; + void parseKeystrokeConditionOptions(ConfigReadContext& c, const std::string& s, bool& activeScreenOnly) const; + void parseKeystrokeActionOptions(ConfigReadContext& c, const std::string& s, bool& activeScreenOnly) const; + static const char* getOptionName(OptionID); static std::string getOptionValue(OptionID, OptionValue); @@ -497,6 +500,9 @@ public: IPlatformScreen::KeyInfo* parseKeystroke(const std::string& keystroke) const; IPlatformScreen::KeyInfo* parseKeystroke(const std::string& keystroke, const std::set& screens) const; + IPlatformScreen::KeyInfo* parseKeystroke(const std::string& keystroke, + const std::set& screens, + const bool& activeScreenOnly) const; IPlatformScreen::ButtonInfo* parseMouse(const std::string& mouse) const; KeyModifierMask parseModifier(const std::string& modifiers) const; diff --git a/src/lib/server/InputFilter.cpp b/src/lib/server/InputFilter.cpp index a0dce17c..72123c4e 100644 --- a/src/lib/server/InputFilter.cpp +++ b/src/lib/server/InputFilter.cpp @@ -53,21 +53,23 @@ InputFilter::Condition::disablePrimary(PrimaryClient*) } InputFilter::KeystrokeCondition::KeystrokeCondition( - IEventQueue* events, IPlatformScreen::KeyInfo* info) : + IEventQueue* events, IPlatformScreen::KeyInfo* info, bool disableGlobalHotkeyRegister) : m_id(0), m_key(info->m_key), m_mask(info->m_mask), - m_events(events) + m_events(events), + m_disableGlobalHotkeyRegister(disableGlobalHotkeyRegister) { free(info); } InputFilter::KeystrokeCondition::KeystrokeCondition( - IEventQueue* events, KeyID key, KeyModifierMask mask) : + IEventQueue* events, KeyID key, KeyModifierMask mask, bool disableGlobalHotkeyRegister) : m_id(0), m_key(key), m_mask(mask), - m_events(events) + m_events(events), + m_disableGlobalHotkeyRegister(disableGlobalHotkeyRegister) { // do nothing } @@ -92,7 +94,7 @@ InputFilter::KeystrokeCondition::getMask() const InputFilter::Condition* InputFilter::KeystrokeCondition::clone() const { - return new KeystrokeCondition(m_events, m_key, m_mask); + return new KeystrokeCondition(m_events, m_key, m_mask, m_disableGlobalHotkeyRegister); } std::string InputFilter::KeystrokeCondition::format() const @@ -131,13 +133,13 @@ InputFilter::KeystrokeCondition::match(const Event& event) void InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient* primary) { - m_id = primary->registerHotKey(m_key, m_mask); + m_id = primary->registerHotKey(m_key, m_mask, !m_disableGlobalHotkeyRegister); } void InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient* primary) { - primary->unregisterHotKey(m_id); + primary->unregisterHotKey(m_id, !m_disableGlobalHotkeyRegister); m_id = 0; } diff --git a/src/lib/server/InputFilter.h b/src/lib/server/InputFilter.h index 5e6ef9cf..38c10abf 100644 --- a/src/lib/server/InputFilter.h +++ b/src/lib/server/InputFilter.h @@ -57,8 +57,8 @@ public: // KeystrokeCondition class KeystrokeCondition : public Condition { public: - KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*); - KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask); + KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*, bool disableGlobalHotkeyRegister); + KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask, bool disableGlobalHotkeyRegister); virtual ~KeystrokeCondition(); KeyID getKey() const; @@ -76,6 +76,7 @@ public: KeyID m_key; KeyModifierMask m_mask; IEventQueue* m_events; + bool m_disableGlobalHotkeyRegister; }; // MouseButtonCondition diff --git a/src/lib/server/PrimaryClient.cpp b/src/lib/server/PrimaryClient.cpp index 6583e5d2..46e78612 100644 --- a/src/lib/server/PrimaryClient.cpp +++ b/src/lib/server/PrimaryClient.cpp @@ -49,15 +49,15 @@ PrimaryClient::reconfigure(UInt32 activeSides) } UInt32 -PrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask) +PrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) { - return m_screen->registerHotKey(key, mask); + return m_screen->registerHotKey(key, mask, registerGlobalHotkey); } void -PrimaryClient::unregisterHotKey(UInt32 id) +PrimaryClient::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) { - m_screen->unregisterHotKey(id); + m_screen->unregisterHotKey(id, unregisterGlobalHotkey); } void @@ -187,11 +187,7 @@ void PrimaryClient::keyDown(KeyID key, KeyModifierMask mask, KeyButton button) { if (m_fakeInputCount > 0) { -// XXX -- don't forward keystrokes to primary screen for now - (void)key; - (void)mask; - (void)button; -// m_screen->keyDown(key, mask, button); + m_screen->keyDown(key, mask, button); } } @@ -205,11 +201,7 @@ void PrimaryClient::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { if (m_fakeInputCount > 0) { -// XXX -- don't forward keystrokes to primary screen for now - (void)key; - (void)mask; - (void)button; -// m_screen->keyUp(key, mask, button); + m_screen->keyUp(key, mask, button); } } diff --git a/src/lib/server/PrimaryClient.h b/src/lib/server/PrimaryClient.h index 13be8389..a38ffb18 100644 --- a/src/lib/server/PrimaryClient.h +++ b/src/lib/server/PrimaryClient.h @@ -55,13 +55,13 @@ public: Registers a system-wide hotkey for key \p key with modifiers \p mask. Returns an id used to unregister the hotkey. */ - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey); //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ - virtual void unregisterHotKey(UInt32 id); + virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey); //! Prepare to synthesize input on primary screen /*! diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index a169db16..835e2536 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -293,7 +293,7 @@ Server::setConfig(const Config& config) if (!m_config->hasLockToScreenAction()) { IPlatformScreen::KeyInfo* key = IPlatformScreen::KeyInfo::alloc(kKeyScrollLock, 0, 0, 0); - InputFilter::Rule rule(new InputFilter::KeystrokeCondition(m_events, key)); + InputFilter::Rule rule(new InputFilter::KeystrokeCondition(m_events, key, true)); rule.adoptAction(new InputFilter::LockCursorToScreenAction(m_events), true); m_inputFilter->addFilterRule(rule); } @@ -1285,7 +1285,9 @@ Server::handleKeyDownEvent(const Event& event, void*) { IPlatformScreen::KeyInfo* info = static_cast(event.getData()); - onKeyDown(info->m_key, info->m_mask, info->m_button, info->m_screens); + onKeyDown(info->m_key, info->m_mask, info->m_button, + info->m_screens, + info->m_activeScreenOnly); } void @@ -1293,7 +1295,9 @@ Server::handleKeyUpEvent(const Event& event, void*) { IPlatformScreen::KeyInfo* info = static_cast(event.getData()); - onKeyUp(info->m_key, info->m_mask, info->m_button, info->m_screens); + onKeyUp(info->m_key, info->m_mask, info->m_button, + info->m_screens, + info->m_activeScreenOnly); } void @@ -1630,7 +1634,7 @@ Server::onScreensaver(bool activated) void Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, - const char* screens) + const char* screens, bool activeScreenOnly) { LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x", id, mask, button)); assert(m_active != NULL); @@ -1639,6 +1643,15 @@ Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { m_active->keyDown(id, mask, button); } + else if (activeScreenOnly) { + auto activeName = m_active->getName(); + if (IKeyState::KeyInfo::contains(screens, activeName)) { + // This won't work on the primary client if the action has the same keystroke as the condition. + // Unlike other clients, the primary client registers the original keystroke with the OS as a hotkey to block + // other apps from handling them, which also stops Barrier from being able to create a fake event for them. + m_active->keyDown(id, mask, button); + } + } else { if (!screens && m_keyboardBroadcasting) { screens = m_keyboardBroadcastingScreens.c_str(); @@ -1657,7 +1670,7 @@ Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, void Server::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button, - const char* screens) + const char* screens, bool activeScreenOnly) { LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, button)); assert(m_active != NULL); @@ -1666,6 +1679,15 @@ Server::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button, if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { m_active->keyUp(id, mask, button); } + else if (activeScreenOnly) { + auto activeName = m_active->getName(); + if (IKeyState::KeyInfo::contains(screens, activeName)) { + // This won't work on the primary client if the action has the same keystroke as the condition. + // Unlike other clients, the primary client registers the original keystroke with the OS as a hotkey to block + // other apps from handling them, which also stops Barrier from being able to create a fake event for them. + m_active->keyUp(id, mask, button); + } + } else { if (!screens && m_keyboardBroadcasting) { screens = m_keyboardBroadcastingScreens.c_str(); diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h index ae8b2bd5..2a234bd4 100644 --- a/src/lib/server/Server.h +++ b/src/lib/server/Server.h @@ -322,9 +322,9 @@ private: ClipboardID id, UInt32 seqNum); void onScreensaver(bool activated); void onKeyDown(KeyID, KeyModifierMask, KeyButton, - const char* screens); + const char* screens, bool activeScreenOnly); void onKeyUp(KeyID, KeyModifierMask, KeyButton, - const char* screens); + const char* screens, bool activeScreenOnly); void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton); void onMouseDown(ButtonID); void onMouseUp(ButtonID);