[FEATURE] Implement `disableGlobalHotkeyRegister` option for keystroke conditions to allow apps on the primary client to respond to the keystroke without the OS blocking them

This commit is contained in:
Rajveer Aujla 2023-01-19 13:37:15 +00:00
parent f38ab7d569
commit 903b34c32a
18 changed files with 89 additions and 61 deletions

View File

@ -155,8 +155,8 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides) = 0; virtual void reconfigure(UInt32 activeSides) = 0;
virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0;
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) = 0;
virtual void unregisterHotKey(UInt32 id) = 0; virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) = 0;
virtual void fakeInputBegin() = 0; virtual void fakeInputBegin() = 0;
virtual void fakeInputEnd() = 0; virtual void fakeInputEnd() = 0;
virtual SInt32 getJumpZoneSize() const = 0; virtual SInt32 getJumpZoneSize() const = 0;

View File

@ -111,13 +111,13 @@ public:
the modifiers in any order or to require the user to press the given key the modifiers in any order or to require the user to press the given key
last. last.
*/ */
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey) = 0;
//! Unregister a system hotkey //! Unregister a system hotkey
/*! /*!
Unregisters a previously registered hot key. 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 //! Prepare to synthesize input on primary screen
/*! /*!

View File

@ -44,8 +44,8 @@ public:
virtual void reconfigure(UInt32 activeSides) = 0; virtual void reconfigure(UInt32 activeSides) = 0;
virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0;
virtual UInt32 registerHotKey(KeyID key, virtual UInt32 registerHotKey(KeyID key,
KeyModifierMask mask) = 0; KeyModifierMask mask, bool registerGlobalHotkey) = 0;
virtual void unregisterHotKey(UInt32 id) = 0; virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey) = 0;
virtual void fakeInputBegin() = 0; virtual void fakeInputBegin() = 0;
virtual void fakeInputEnd() = 0; virtual void fakeInputEnd() = 0;
virtual SInt32 getJumpZoneSize() const = 0; virtual SInt32 getJumpZoneSize() const = 0;

View File

@ -330,15 +330,15 @@ Screen::setSequenceNumber(UInt32 seqNum)
} }
UInt32 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 void
Screen::unregisterHotKey(UInt32 id) Screen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey)
{ {
m_screen->unregisterHotKey(id); m_screen->unregisterHotKey(id, unregisterGlobalHotkey);
} }
void void

View File

@ -198,13 +198,13 @@ public:
Registers a system-wide hotkey for key \p key with modifiers \p mask. Registers a system-wide hotkey for key \p key with modifiers \p mask.
Returns an id used to unregister the hotkey. 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 //! Unregister a system hotkey
/*! /*!
Unregisters a previously registered hot key. Unregisters a previously registered hot key.
*/ */
void unregisterHotKey(UInt32 id); void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey);
//! Prepare to synthesize input on primary screen //! Prepare to synthesize input on primary screen
/*! /*!

View File

@ -548,7 +548,7 @@ void MSWindowsScreen::saveMousePosition(SInt32 x, SInt32 y) {
} }
UInt32 UInt32
MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey)
{ {
// only allow certain modifiers // only allow certain modifiers
if ((mask & ~(KeyModifierShift | KeyModifierControl | 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 // if this hot key has modifiers only then we'll handle it specially
bool err; bool err = false;
if (key == kKeyNone) { if (key == kKeyNone) {
// check if already registered // check if already registered
err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0); err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0);
} }
else { else if (registerGlobalHotkey) {
// register with OS // register with OS
err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); err = (RegisterHotKey(NULL, id, modifiers, vk) == 0);
} }
@ -625,7 +625,7 @@ MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
} }
void void
MSWindowsScreen::unregisterHotKey(UInt32 id) MSWindowsScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey)
{ {
// look up hotkey // look up hotkey
HotKeyMap::iterator i = m_hotKeys.find(id); HotKeyMap::iterator i = m_hotKeys.find(id);
@ -634,13 +634,10 @@ MSWindowsScreen::unregisterHotKey(UInt32 id)
} }
// unregister with OS // unregister with OS
bool err; bool err = false;
if (i->second.getVirtualKey() != 0) { if (unregisterGlobalHotkey && i->second.getVirtualKey() != 0) {
err = !UnregisterHotKey(NULL, id); err = !UnregisterHotKey(NULL, id);
} }
else {
err = false;
}
if (err) { if (err) {
LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); LOG((CLOG_WARN "failed to unregister hotkey id=%d", id));
} }

View File

@ -80,8 +80,8 @@ public:
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key, virtual UInt32 registerHotKey(KeyID key,
KeyModifierMask mask); KeyModifierMask mask, bool registerGlobalHotkey);
virtual void unregisterHotKey(UInt32 id); virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey);
virtual void fakeInputBegin(); virtual void fakeInputBegin();
virtual void fakeInputEnd(); virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;

View File

@ -68,8 +68,8 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey);
virtual void unregisterHotKey(UInt32 id); virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey);
virtual void fakeInputBegin(); virtual void fakeInputBegin();
virtual void fakeInputEnd(); virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;

View File

@ -315,7 +315,7 @@ OSXScreen::getCursorCenter(SInt32& x, SInt32& y) const
} }
UInt32 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 // get mac virtual key and modifier mask matching barrier key and mask
UInt32 macKey, macMask; UInt32 macKey, macMask;
@ -348,11 +348,13 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
} }
} }
else { else {
EventHotKeyID hkid = { 'SNRG', (UInt32)id }; if (registerGlobalHotkey) {
OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, EventHotKeyID hkid = { 'SNRG', (UInt32)id };
GetApplicationEventTarget(), 0, OSStatus status = RegisterEventHotKey(macKey, macMask, hkid,
&ref); GetApplicationEventTarget(), 0,
okay = (status == noErr); &ref);
okay = (status == noErr);
}
m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id; m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id;
} }
@ -370,7 +372,7 @@ OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask)
} }
void void
OSXScreen::unregisterHotKey(UInt32 id) OSXScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey)
{ {
// look up hotkey // look up hotkey
HotKeyMap::iterator i = m_hotKeys.find(id); HotKeyMap::iterator i = m_hotKeys.find(id);
@ -380,7 +382,7 @@ OSXScreen::unregisterHotKey(UInt32 id)
// unregister with OS // unregister with OS
bool okay; bool okay;
if (i->second.getRef() != NULL) { if (unregisterGlobalHotkey && i->second.getRef() != NULL) {
okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); okay = (UnregisterEventHotKey(i->second.getRef()) == noErr);
} }
else { else {

View File

@ -524,7 +524,7 @@ XWindowsScreen::warpCursor(SInt32 x, SInt32 y)
} }
UInt32 UInt32
XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey)
{ {
// only allow certain modifiers // only allow certain modifiers
if ((mask & ~(KeyModifierShift | KeyModifierControl | if ((mask & ~(KeyModifierShift | KeyModifierControl |
@ -642,8 +642,10 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) { for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) {
KeyCode code = modifiermap[k]; KeyCode code = modifiermap[k];
if (modifiermap[k] != 0) { if (modifiermap[k] != 0) {
m_impl->XGrabKey(m_display, code, modifiers2, m_root, if (registerGlobalHotkey) {
False, GrabModeAsync, GrabModeAsync); m_impl->XGrabKey(m_display, code, modifiers2, m_root,
False, GrabModeAsync, GrabModeAsync);
}
if (!err) { if (!err) {
hotKeys.push_back(std::make_pair(code, modifiers2)); hotKeys.push_back(std::make_pair(code, modifiers2));
m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id; m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id;
@ -689,8 +691,10 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
} }
// add grab // add grab
m_impl->XGrabKey(m_display, *j, tmpModifiers, m_root, if (registerGlobalHotkey) {
False, GrabModeAsync, GrabModeAsync); m_impl->XGrabKey(m_display, *j, tmpModifiers, m_root,
False, GrabModeAsync, GrabModeAsync);
}
if (!err) { if (!err) {
hotKeys.push_back(std::make_pair(*j, tmpModifiers)); hotKeys.push_back(std::make_pair(*j, tmpModifiers));
m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id; m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id;
@ -719,7 +723,7 @@ XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask)
} }
void void
XWindowsScreen::unregisterHotKey(UInt32 id) XWindowsScreen::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey)
{ {
// look up hotkey // look up hotkey
HotKeyMap::iterator i = m_hotKeys.find(id); HotKeyMap::iterator i = m_hotKeys.find(id);
@ -734,7 +738,9 @@ XWindowsScreen::unregisterHotKey(UInt32 id)
HotKeyList& hotKeys = i->second; HotKeyList& hotKeys = i->second;
for (HotKeyList::iterator j = hotKeys.begin(); for (HotKeyList::iterator j = hotKeys.begin();
j != hotKeys.end(); ++j) { 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)); m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second));
} }
} }

View File

@ -53,8 +53,8 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides); virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y); virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask, bool registerGlobalHotkey);
virtual void unregisterHotKey(UInt32 id); virtual void unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey);
virtual void fakeInputBegin(); virtual void fakeInputBegin();
virtual void fakeInputEnd(); virtual void fakeInputEnd();
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;

View File

@ -1029,13 +1029,19 @@ InputFilter::Condition* Config::parseCondition(ConfigReadContext& s, const std::
const std::vector<std::string>& args) const std::vector<std::string>& args)
{ {
if (name == "keystroke") { if (name == "keystroke") {
if (args.size() != 1) { if (args.size() < 1 || args.size() > 2) {
throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)"); throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key[,options])");
} }
IPlatformScreen::KeyInfo* keyInfo = s.parseKeystroke(args[0]); 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") { if (name == "mousebutton") {
@ -1293,6 +1299,19 @@ 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, void Config::parseKeystrokeActionOptions(ConfigReadContext& c, const std::string& s,
bool& activeScreenOnly) const bool& activeScreenOnly) const
{ {

View File

@ -453,6 +453,7 @@ private:
void parseScreens(ConfigReadContext&, const std::string&, std::set<std::string>& screens) const; void parseScreens(ConfigReadContext&, const std::string&, std::set<std::string>& screens) const;
void parseKeystrokeConditionOptions(ConfigReadContext& c, const std::string& s, bool& activeScreenOnly) const;
void parseKeystrokeActionOptions(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 const char* getOptionName(OptionID);

View File

@ -53,21 +53,23 @@ InputFilter::Condition::disablePrimary(PrimaryClient*)
} }
InputFilter::KeystrokeCondition::KeystrokeCondition( InputFilter::KeystrokeCondition::KeystrokeCondition(
IEventQueue* events, IPlatformScreen::KeyInfo* info) : IEventQueue* events, IPlatformScreen::KeyInfo* info, bool disableGlobalHotkeyRegister) :
m_id(0), m_id(0),
m_key(info->m_key), m_key(info->m_key),
m_mask(info->m_mask), m_mask(info->m_mask),
m_events(events) m_events(events),
m_disableGlobalHotkeyRegister(disableGlobalHotkeyRegister)
{ {
free(info); free(info);
} }
InputFilter::KeystrokeCondition::KeystrokeCondition( InputFilter::KeystrokeCondition::KeystrokeCondition(
IEventQueue* events, KeyID key, KeyModifierMask mask) : IEventQueue* events, KeyID key, KeyModifierMask mask, bool disableGlobalHotkeyRegister) :
m_id(0), m_id(0),
m_key(key), m_key(key),
m_mask(mask), m_mask(mask),
m_events(events) m_events(events),
m_disableGlobalHotkeyRegister(disableGlobalHotkeyRegister)
{ {
// do nothing // do nothing
} }
@ -92,7 +94,7 @@ InputFilter::KeystrokeCondition::getMask() const
InputFilter::Condition* InputFilter::Condition*
InputFilter::KeystrokeCondition::clone() const 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 std::string InputFilter::KeystrokeCondition::format() const
@ -131,13 +133,13 @@ InputFilter::KeystrokeCondition::match(const Event& event)
void void
InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient* primary) InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient* primary)
{ {
m_id = primary->registerHotKey(m_key, m_mask); m_id = primary->registerHotKey(m_key, m_mask, !m_disableGlobalHotkeyRegister);
} }
void void
InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient* primary) InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient* primary)
{ {
primary->unregisterHotKey(m_id); primary->unregisterHotKey(m_id, !m_disableGlobalHotkeyRegister);
m_id = 0; m_id = 0;
} }

View File

@ -57,8 +57,8 @@ public:
// KeystrokeCondition // KeystrokeCondition
class KeystrokeCondition : public Condition { class KeystrokeCondition : public Condition {
public: public:
KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*); KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*, bool disableGlobalHotkeyRegister);
KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask); KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask, bool disableGlobalHotkeyRegister);
virtual ~KeystrokeCondition(); virtual ~KeystrokeCondition();
KeyID getKey() const; KeyID getKey() const;
@ -76,6 +76,7 @@ public:
KeyID m_key; KeyID m_key;
KeyModifierMask m_mask; KeyModifierMask m_mask;
IEventQueue* m_events; IEventQueue* m_events;
bool m_disableGlobalHotkeyRegister;
}; };
// MouseButtonCondition // MouseButtonCondition

View File

@ -49,15 +49,15 @@ PrimaryClient::reconfigure(UInt32 activeSides)
} }
UInt32 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 void
PrimaryClient::unregisterHotKey(UInt32 id) PrimaryClient::unregisterHotKey(UInt32 id, bool unregisterGlobalHotkey)
{ {
m_screen->unregisterHotKey(id); m_screen->unregisterHotKey(id, unregisterGlobalHotkey);
} }
void void

View File

@ -55,13 +55,13 @@ public:
Registers a system-wide hotkey for key \p key with modifiers \p mask. Registers a system-wide hotkey for key \p key with modifiers \p mask.
Returns an id used to unregister the hotkey. 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 //! Unregister a system hotkey
/*! /*!
Unregisters a previously registered hot key. 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 //! Prepare to synthesize input on primary screen
/*! /*!

View File

@ -293,7 +293,7 @@ Server::setConfig(const Config& config)
if (!m_config->hasLockToScreenAction()) { if (!m_config->hasLockToScreenAction()) {
IPlatformScreen::KeyInfo* key = IPlatformScreen::KeyInfo* key =
IPlatformScreen::KeyInfo::alloc(kKeyScrollLock, 0, 0, 0); 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); rule.adoptAction(new InputFilter::LockCursorToScreenAction(m_events), true);
m_inputFilter->addFilterRule(rule); m_inputFilter->addFilterRule(rule);
} }