Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Super keys #62

Merged
merged 4 commits into from Jan 16, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
148 changes: 103 additions & 45 deletions daemon/core.cpp
Expand Up @@ -1121,7 +1121,7 @@ void Core::run()

Window rootWindow = DefaultRootWindow(mDisplay);

XSelectInput(mDisplay, rootWindow, KeyPressMask);
XSelectInput(mDisplay, rootWindow, KeyPressMask | KeyReleaseMask);

mInterClientCommunicationWindow = XCreateSimpleWindow(mDisplay, rootWindow, 0, 0, 1, 1, 0, 0, 0);

Expand All @@ -1141,10 +1141,14 @@ void Core::run()
allModifiers.insert(ignoreLocks);
}

const QString metaLeft = XKeysymToString(XK_Super_L);
const QString metaRight = XKeysymToString(XK_Super_R);

char signal = 0;
if (write(mX11ResponsePipe[STDOUT_FILENO], &signal, sizeof(signal)) == sizeof(signal))
{
bool keyReleaseExpected = false;

XEvent event;
while (mX11EventLoopActive)
{
Expand All @@ -1154,7 +1158,15 @@ void Core::run()
break;
}

if (event.type == KeyPress && mDataMutex.tryLock(0))
if ((event.type == KeyRelease) && !keyReleaseExpected)
{
// pop event from the x11 queue and do nothing
XNextEvent(mDisplay, &event);
continue;
}
keyReleaseExpected = false; // Close time window for accepting meta keys.

if (((event.type == KeyPress) || (event.type == KeyRelease)) && mDataMutex.tryLock(0))
{
std::unique_lock<QMutex> unlocker(mDataMutex, std::adopt_lock);

Expand Down Expand Up @@ -1202,7 +1214,29 @@ void Core::run()
}
else
{
if (isModifier(keySym) || !isAllowed(keySym, event.xkey.state & allShifts))
if (isModifier(keySym))
{
if (event.type == KeyPress)
{
ignoreKey = true;
keyReleaseExpected = true;
}
else
{
// Only the meta keys are allowed.

if ((event.xkey.state & allShifts) == MetaMask)
{
shortcut = XKeysymToString(keySym);
event.xkey.state &= ~allShifts; // Modifier keys must not use shift states.
}
else
{
ignoreKey = true;
}
}
}
else if ((event.type == KeyRelease) || !isAllowed(keySym, event.xkey.state & allShifts))
{
ignoreKey = true;
}
Expand Down Expand Up @@ -1244,6 +1278,11 @@ void Core::run()
}
}
}
if (keySyms)
{
XFree(keySyms);
keySyms = nullptr;
}
if (!ignoreKey)
{
IdsByShortcut::iterator idsByShortcut = mIdsByShortcut.find(shortcut);
Expand Down Expand Up @@ -1317,73 +1356,92 @@ void Core::run()
}
else
{
if (event.type == KeyRelease)
{
event.xkey.state &= ~allShifts; // Modifier keys must not use shift states.
}

X11Shortcut shortcutKey = qMakePair(static_cast<KeyCode>(event.xkey.keycode), event.xkey.state & allShifts);
ShortcutByX11::const_iterator shortcutIt = mShortcutByX11.constFind(shortcutKey);
if(shortcutIt != mShortcutByX11.constEnd())
if (shortcutIt == mShortcutByX11.constEnd())
{
const QString& shortcut = shortcutIt.value();
log(LOG_DEBUG, "KeyPress %08x %08x %s", event.xkey.state & allShifts, event.xkey.keycode, qPrintable(shortcut));
continue;
}
const QString& shortcut = shortcutIt.value();

IdsByShortcut::iterator idsByShortcut = mIdsByShortcut.find(shortcut);
if (idsByShortcut != mIdsByShortcut.end())
if (event.type == KeyPress)
{
if ((shortcut == metaLeft) || (shortcut == metaRight))
{
Ids &ids = idsByShortcut.value();
switch (mMultipleActionsBehaviour)
{
case MULTIPLE_ACTIONS_BEHAVIOUR_FIRST:
{
Ids::iterator lastIds = ids.end();
for (Ids::iterator idi = ids.begin(); idi != lastIds; ++idi)
if (mShortcutAndActionById[*idi].second->call())
{
break;
}
}
break;
keyReleaseExpected = true;
continue;
}
log(LOG_DEBUG, "KeyPress %08x %08x %s", event.xkey.state & allShifts, event.xkey.keycode, qPrintable(shortcut));
}
else
{
log(LOG_DEBUG, "KeyRelease %08x %08x %s", event.xkey.state & allShifts, event.xkey.keycode, qPrintable(shortcut));
}

case MULTIPLE_ACTIONS_BEHAVIOUR_LAST:
{
Ids::iterator firstIds = ids.begin();
for (Ids::iterator idi = ids.end(); idi != firstIds;)
IdsByShortcut::iterator idsByShortcut = mIdsByShortcut.find(shortcut);
if (idsByShortcut != mIdsByShortcut.end())
{
Ids &ids = idsByShortcut.value();
switch (mMultipleActionsBehaviour)
{
case MULTIPLE_ACTIONS_BEHAVIOUR_FIRST:
{
Ids::iterator lastIds = ids.end();
for (Ids::iterator idi = ids.begin(); idi != lastIds; ++idi)
if (mShortcutAndActionById[*idi].second->call())
{
--idi;
if (mShortcutAndActionById[*idi].second->call())
{
break;
}
break;
}
}
break;
}
break;

case MULTIPLE_ACTIONS_BEHAVIOUR_NONE:
if (ids.size() == 1)
case MULTIPLE_ACTIONS_BEHAVIOUR_LAST:
{
Ids::iterator firstIds = ids.begin();
for (Ids::iterator idi = ids.end(); idi != firstIds;)
{
--idi;
if (mShortcutAndActionById[*idi].second->call())
{
mShortcutAndActionById[*(ids.begin())].second->call();
break;
}
break;
}
}
break;

case MULTIPLE_ACTIONS_BEHAVIOUR_ALL:
case MULTIPLE_ACTIONS_BEHAVIOUR_NONE:
if (ids.size() == 1)
{
Ids::iterator lastIds = ids.end();
for (Ids::iterator idi = ids.begin(); idi != lastIds; ++idi)
{
mShortcutAndActionById[*idi].second->call();
}
mShortcutAndActionById[*(ids.begin())].second->call();
}
break;

default:
;
case MULTIPLE_ACTIONS_BEHAVIOUR_ALL:
{
Ids::iterator lastIds = ids.end();
for (Ids::iterator idi = ids.begin(); idi != lastIds; ++idi)
{
mShortcutAndActionById[*idi].second->call();
}
}
break;

default:
;
}
}
}

}
else
// check for pending pipe requests from other thread
{
if (event.type != KeyPress) {
if ((event.type != KeyPress) && (event.type != KeyRelease)) {
XNextEvent(mDisplay, &event);
}

Expand Down