=== modified file 'libunity-2d-private/src/CMakeLists.txt'
--- libunity-2d-private/src/CMakeLists.txt 2012-03-20 14:50:42 +0000
+++ libunity-2d-private/src/CMakeLists.txt 2012-04-02 16:31:23 +0000
@@ -87,6 +87,7 @@
pointerbarrier.cpp
pointerbarriermanager.cpp
decayedvalue.cpp
+ gkeysequenceparser.cpp
)
# Build
=== added file 'libunity-2d-private/src/gkeysequenceparser.cpp'
--- libunity-2d-private/src/gkeysequenceparser.cpp 1970-01-01 00:00:00 +0000
+++ libunity-2d-private/src/gkeysequenceparser.cpp 2012-04-02 16:31:23 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "gkeysequenceparser.h"
+
+#include
+#include
+#include
+
+#include
+
+bool GKeySequenceParser::parse(const QString &keySequence, int *x11KeyCode, Qt::KeyboardModifiers *modifiers)
+{
+ // Parses a string in the form created by the gtk shortcut dialog into x11 keycode and qt modifiers
+ // The expected format is
+ // *Keyname?
+ // i.e. there can be none or multiple modifiers followed or not by the name of a key
+ bool success = true;
+ *x11KeyCode = 0;
+ *modifiers = Qt::NoModifier;
+ if (keySequence == "Disabled") {
+ return success;
+ }
+
+ QString aux = keySequence;
+ while (success && aux.startsWith('<')) {
+ const int closing = aux.indexOf('>');
+ if (closing > 0) {
+ const QString modifier = aux.mid(1, closing - 1);
+ if (modifier == "Control" || modifier == "Primary") {
+ *modifiers = *modifiers | Qt::ControlModifier;
+ } else if (modifier == "Shift") {
+ *modifiers = *modifiers | Qt::ShiftModifier;
+ } else if (modifier == "Alt") {
+ *modifiers = *modifiers | Qt::AltModifier;
+ } else if (modifier == "Super") {
+ *modifiers = *modifiers | Qt::MetaModifier;
+ } else {
+ qWarning() << "Could not parse modifier" << modifier << "in key sequence" << keySequence;
+ success = false;
+ }
+ aux = aux.mid(closing + 1);
+ } else {
+ qWarning() << "Could not find modifier end in key sequence" << keySequence;
+ success = false;
+ }
+ }
+
+ if (success && !aux.isEmpty()) {
+ KeySym keysym = XStringToKeysym(aux.toLatin1().constData());
+ if (keysym == NoSymbol) {
+ qWarning() << "Could not parse key" << aux << "in key sequence" << keySequence;
+ success = false;
+ } else {
+ *x11KeyCode = XKeysymToKeycode(QX11Info::display(), keysym);
+ }
+ }
+
+ return success;
+}
=== added file 'libunity-2d-private/src/gkeysequenceparser.h'
--- libunity-2d-private/src/gkeysequenceparser.h 1970-01-01 00:00:00 +0000
+++ libunity-2d-private/src/gkeysequenceparser.h 2012-04-02 16:31:23 +0000
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef GKEYSEQUENCEPARSER_H
+#define GKEYSEQUENCEPARSER_H
+
+#include
+
+namespace GKeySequenceParser
+{
+ bool parse(const QString &keySequence, int *x11KeyCode, Qt::KeyboardModifiers *modifiers);
+}
+
+#endif // GKEYSEQUENCEPARSER_H
+
=== modified file 'libunity-2d-private/src/hotkey.cpp'
--- libunity-2d-private/src/hotkey.cpp 2012-03-16 16:48:19 +0000
+++ libunity-2d-private/src/hotkey.cpp 2012-04-02 16:31:23 +0000
@@ -54,20 +54,8 @@
m_key(key), m_modifiers(modifiers),
m_x11key(0), m_x11modifiers(0)
{
- /* Translate the QT modifiers to X11 modifiers */
+ translateModifiers(modifiers);
- if (modifiers.testFlag(Qt::ShiftModifier)) {
- m_x11modifiers |= ShiftMask ;
- }
- if (modifiers.testFlag(Qt::ControlModifier)) {
- m_x11modifiers |= ControlMask ;
- }
- if (modifiers.testFlag(Qt::AltModifier)) {
- m_x11modifiers |= Mod1Mask;
- }
- if (modifiers.testFlag(Qt::MetaModifier)) {
- m_x11modifiers |= Mod4Mask;
- }
if (modifiers.testFlag(Qt::KeypadModifier)) {
/* Support 0..9 numpad keys only.
If we ever need to support additional numpad keys, then this logic should be extended
@@ -102,12 +90,24 @@
}
}
+Hotkey::Hotkey(uint x11key, Qt::KeyboardModifiers modifiers, QObject *parent)
+ : QObject(parent), m_connections(0),
+ m_key(0), m_modifiers(modifiers),
+ m_x11key(x11key), m_x11modifiers(0)
+{
+ translateModifiers(modifiers);
+}
+
void
Hotkey::connectNotify(const char * signal)
{
Q_UNUSED(signal);
if (m_connections == 0) {
- UQ_DEBUG << "Grabbing hotkey" << QKeySequence(m_key | m_modifiers).toString();
+ if (m_key != 0) {
+ UQ_DEBUG << "Grabbing hotkey" << QKeySequence(m_key | m_modifiers).toString();
+ } else {
+ UQ_DEBUG.nospace() << "Grabbing hotkey" << QKeySequence(m_modifiers).toString() << XKeysymToString(XKeycodeToKeysym(QX11Info::display(), m_x11key, 0));
+ }
_x_old_errhandler = XSetErrorHandler(_x_grabkey_errhandler);
XGrabKey(QX11Info::display(), m_x11key, m_x11modifiers,
QX11Info::appRootWindow(), True, GrabModeAsync, GrabModeAsync);
@@ -122,7 +122,11 @@
{
Q_UNUSED(signal);
if (m_connections == 1) {
- UQ_DEBUG << "Ungrabbing hotkey" << QKeySequence(m_key | m_modifiers).toString();
+ if (m_key != 0) {
+ UQ_DEBUG << "Ungrabbing hotkey" << QKeySequence(m_key | m_modifiers).toString();
+ } else {
+ UQ_DEBUG.nospace() << "Ungrabbing hotkey" << QKeySequence(m_modifiers).toString() << XKeysymToString(XKeycodeToKeysym(QX11Info::display(), m_x11key, 0));
+ }
XUngrabKey(QX11Info::display(), m_x11key, m_x11modifiers,
QX11Info::appRootWindow());
}
@@ -139,4 +143,22 @@
return false;
}
+void
+Hotkey::translateModifiers(Qt::KeyboardModifiers modifiers)
+{
+ /* Translate the QT modifiers to X11 modifiers */
+ if (modifiers.testFlag(Qt::ShiftModifier)) {
+ m_x11modifiers |= ShiftMask ;
+ }
+ if (modifiers.testFlag(Qt::ControlModifier)) {
+ m_x11modifiers |= ControlMask ;
+ }
+ if (modifiers.testFlag(Qt::AltModifier)) {
+ m_x11modifiers |= Mod1Mask;
+ }
+ if (modifiers.testFlag(Qt::MetaModifier)) {
+ m_x11modifiers |= Mod4Mask;
+ }
+}
+
#include "hotkey.moc"
=== modified file 'libunity-2d-private/src/hotkey.h'
--- libunity-2d-private/src/hotkey.h 2012-02-03 13:36:16 +0000
+++ libunity-2d-private/src/hotkey.h 2012-04-02 16:31:23 +0000
@@ -27,15 +27,16 @@
friend class HotkeyMonitor;
Q_OBJECT
- Q_PROPERTY(Qt::Key key READ key NOTIFY keyChanged)
+ Q_PROPERTY(int key READ key NOTIFY keyChanged)
Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers NOTIFY modifiersChanged)
public:
- Qt::Key key() const { return m_key; }
+ int key() const { return m_key; }
+ uint x11key() const { return m_x11key; }
Qt::KeyboardModifiers modifiers() const { return m_modifiers; }
Q_SIGNALS:
- void keyChanged(Qt::Key key);
+ void keyChanged(int key);
void modifiersChanged(Qt::KeyboardModifiers modifiers);
void pressed();
void released();
@@ -46,11 +47,13 @@
private:
Hotkey(Qt::Key key, Qt::KeyboardModifiers modifiers, QObject *parent);
+ Hotkey(uint x11key, Qt::KeyboardModifiers modifiers, QObject *parent);
bool processNativeEvent(uint x11Keycode, uint x11Modifiers, bool isPressEvent);
+ void translateModifiers(Qt::KeyboardModifiers modifiers);
private:
uint m_connections;
- Qt::Key m_key;
+ int m_key;
Qt::KeyboardModifiers m_modifiers;
uint m_x11key;
uint m_x11modifiers;
=== modified file 'libunity-2d-private/src/hotkeymonitor.cpp'
--- libunity-2d-private/src/hotkeymonitor.cpp 2012-02-06 12:07:47 +0000
+++ libunity-2d-private/src/hotkeymonitor.cpp 2012-04-02 16:31:23 +0000
@@ -78,6 +78,21 @@
return hotkey;
}
+Hotkey*
+HotkeyMonitor::getHotkeyFor(uint x11Keycode, Qt::KeyboardModifiers modifiers)
+{
+ Q_FOREACH(Hotkey* currentHotkey, m_hotkeys) {
+ if (currentHotkey->x11key() == x11Keycode &&
+ currentHotkey->modifiers() == modifiers) {
+ return currentHotkey;
+ }
+ }
+
+ Hotkey *hotkey = new Hotkey(x11Keycode, modifiers, this);
+ m_hotkeys.append(hotkey);
+ return hotkey;
+}
+
void HotkeyMonitor::disableModifiers(Qt::KeyboardModifiers modifiers)
{
m_disabledModifiers |= modifiers;
=== modified file 'libunity-2d-private/src/hotkeymonitor.h'
--- libunity-2d-private/src/hotkeymonitor.h 2012-02-06 12:07:47 +0000
+++ libunity-2d-private/src/hotkeymonitor.h 2012-04-02 16:31:23 +0000
@@ -34,6 +34,7 @@
~HotkeyMonitor();
Hotkey* getHotkeyFor(Qt::Key key, Qt::KeyboardModifiers modifiers);
+ Hotkey* getHotkeyFor(uint x11Keycode, Qt::KeyboardModifiers modifiers);
void disableModifiers(Qt::KeyboardModifiers modifiers);
void enableModifiers(Qt::KeyboardModifiers modifiers);
=== modified file 'libunity-2d-private/src/hotmodifier.cpp'
--- libunity-2d-private/src/hotmodifier.cpp 2012-02-20 16:51:19 +0000
+++ libunity-2d-private/src/hotmodifier.cpp 2012-04-02 16:31:23 +0000
@@ -29,6 +29,7 @@
QObject(parent)
, m_modifiers(modifiers)
, m_pressed(false)
+, m_partiallyPressed(false)
, m_held(false)
, m_ignored(false)
, m_otherModifierPressed(false)
@@ -56,13 +57,14 @@
void
HotModifier::onModifiersChanged(Qt::KeyboardModifiers modifiers)
{
- bool pressed = m_modifiers & modifiers;
- bool otherModifierPressed = modifiers ^ m_modifiers;
+ const bool partiallyPressed = m_modifiers & modifiers;
+ const bool pressed = m_modifiers == modifiers;
+ const bool otherModifierPressed = modifiers & ~m_modifiers;
/* if a modifier other than m_modifier is pressed, we take note of it because when the
other modifier is released, m_modifier is emitted again. If we don't ignore this
event, we generate a tap, which is wrong */
- if (otherModifierPressed && pressed) {
+ if (otherModifierPressed && partiallyPressed) {
m_otherModifierPressed = true;
}
@@ -72,17 +74,18 @@
m_held = false;
Q_EMIT heldChanged(m_held);
}
- if (!m_pressed && pressed) {
+ if (!m_partiallyPressed && partiallyPressed) {
m_ignored = false;
m_holdTimer.start();
}
/* Case where "other modifier" is released while m_modifier still pressed. In this case
we want to have the entire modifier press event ignored, to prevent generating a tap */
- if (m_otherModifierPressed && otherModifierPressed && pressed) {
+ if (m_otherModifierPressed && otherModifierPressed && partiallyPressed) {
m_otherModifierPressed = false;
m_ignored = true;
}
m_pressed = pressed;
+ m_partiallyPressed = partiallyPressed;
}
void
@@ -109,6 +112,7 @@
{
m_holdTimer.stop();
m_pressed = false;
+ m_partiallyPressed = false;
m_ignored = false;
if (m_held) {
m_held = false;
=== modified file 'libunity-2d-private/src/hotmodifier.h'
--- libunity-2d-private/src/hotmodifier.h 2012-02-20 16:51:19 +0000
+++ libunity-2d-private/src/hotmodifier.h 2012-04-02 16:31:23 +0000
@@ -52,6 +52,7 @@
QTimer m_holdTimer;
Qt::KeyboardModifiers m_modifiers;
bool m_pressed;
+ bool m_partiallyPressed;
bool m_held;
bool m_ignored;
bool m_otherModifierPressed;
=== modified file 'libunity-2d-private/tests/CMakeLists.txt'
--- libunity-2d-private/tests/CMakeLists.txt 2012-03-20 14:50:42 +0000
+++ libunity-2d-private/tests/CMakeLists.txt 2012-04-02 16:31:23 +0000
@@ -41,6 +41,7 @@
imageutilitiestest
pointerbarriertest
hotkeytest
+ gkeysequenceparser
)
target_link_libraries(pointerbarriertest ${X11_XTest_LIB})
=== added file 'libunity-2d-private/tests/gkeysequenceparser.cpp'
--- libunity-2d-private/tests/gkeysequenceparser.cpp 1970-01-01 00:00:00 +0000
+++ libunity-2d-private/tests/gkeysequenceparser.cpp 2012-04-02 16:31:23 +0000
@@ -0,0 +1,66 @@
+/*
+ * This file is part of unity-2d
+ *
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "gkeysequenceparser.h"
+
+class GKeySequenceParserTest : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void testParsing()
+ {
+ int x11Code;
+ Qt::KeyboardModifiers modifiers;
+ bool success;
+
+ success = GKeySequenceParser::parse("", &x11Code, &modifiers);
+ QVERIFY(success);
+ QCOMPARE(x11Code, 0);
+ QCOMPARE(modifiers, Qt::AltModifier);
+
+ success = GKeySequenceParser::parse("k", &x11Code, &modifiers);
+ QVERIFY(success);
+ QCOMPARE(x11Code, 45);
+ QCOMPARE(modifiers, Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier | Qt::MetaModifier);
+
+ success = GKeySequenceParser::parse("ccedillaj", &x11Code, &modifiers);
+ QVERIFY(!success);
+
+ success = GKeySequenceParser::parse("ccedillaj", &x11Code, &modifiers);
+ QVERIFY(!success);
+
+ success = GKeySequenceParser::parse("ccedillaj", &x11Code, &modifiers);
+ QVERIFY(!success);
+
+ success = GKeySequenceParser::parse("+p", &x11Code, &modifiers);
+ QVERIFY(!success);
+
+ success = GKeySequenceParser::parse("<>", &x11Code, &modifiers);
+ QVERIFY(!success);
+
+ success = GKeySequenceParser::parse("><", &x11Code, &modifiers);
+ QVERIFY(!success);
+ }
+};
+
+QAPP_TEST_MAIN(GKeySequenceParserTest)
+
+#include "gkeysequenceparser.moc"
\ No newline at end of file
=== modified file 'libunity-2d-private/tests/hotkeytest.cpp'
--- libunity-2d-private/tests/hotkeytest.cpp 2012-03-16 17:15:17 +0000
+++ libunity-2d-private/tests/hotkeytest.cpp 2012-04-02 16:31:23 +0000
@@ -51,7 +51,7 @@
void onKeyPressed() {
Hotkey* hotkey = qobject_cast(sender());
- m_key = hotkey->key();
+ m_key = (Qt::Key)hotkey->key();
m_modifiers = hotkey->modifiers();
++m_count;
}
=== modified file 'shell/app/shellmanager.cpp'
--- shell/app/shellmanager.cpp 2012-03-16 11:03:24 +0000
+++ shell/app/shellmanager.cpp 2012-04-02 16:31:23 +0000
@@ -27,6 +27,7 @@
// libunity-2d-private
#include
+#include
#include
#include
#include
@@ -42,6 +43,9 @@
#include
#include
+// libqtgconf
+#include
+
// bamf
#include "bamf-window.h"
#include "bamf-matcher.h"
@@ -55,6 +59,7 @@
static const char* COMMANDS_LENS_ID = "commands.lens";
static const int DASH_MIN_SCREEN_WIDTH = 1280;
static const int DASH_MIN_SCREEN_HEIGHT = 1084;
+static const char* HUD_SHORTCUT_KEY = "/apps/compiz-1/plugins/unityshell/screen0/options/show_hud";
GOBJECT_CALLBACK1(activeWorkspaceChangedCB, "onActiveWorkspaceChanged");
@@ -96,9 +101,14 @@
QString m_dashActiveLens; /* Lens id of the active lens */
HotModifier* m_superHotModifier;
- HotModifier* m_altHotModifier;
+
+ // Only one of the two is non null at a time
+ HotModifier* m_hudHotModifier;
+ Hotkey* m_hudHotKey;
WId m_last_focused_window;
+
+ GConfItemQmlWrapper *m_gconfItem;
};
@@ -270,6 +280,13 @@
{
d->q = this;
d->m_sourceFileUrl = sourceFileUrl;
+ d->m_hudHotModifier = NULL;
+ d->m_hudHotKey = NULL;
+
+ d->m_gconfItem = new GConfItemQmlWrapper(this);
+ connect(d->m_gconfItem, SIGNAL(valueChanged()), this, SLOT(onHudActivationShortcutChanged()));
+ d->m_gconfItem->setKey(HUD_SHORTCUT_KEY);
+ onHudActivationShortcutChanged();
qmlRegisterUncreatableType("Unity2d", 1, 0, "ShellDeclarativeView", "This can only be created from C++");
qmlRegisterUncreatableType("Unity2d", 1, 0, "ShellManager", "This can only be created from C++");
@@ -288,10 +305,6 @@
connect(d->m_superHotModifier, SIGNAL(tapped()), SLOT(toggleDashRequested()));
connect(d->m_superHotModifier, SIGNAL(heldChanged(bool)), SIGNAL(superKeyHeldChanged(bool)));
- /* Alt tap shows the HUD */
- d->m_altHotModifier = KeyboardModifiersMonitor::instance()->getHotModifierFor(Qt::AltModifier);
- connect(d->m_altHotModifier, SIGNAL(tapped()), SLOT(toggleHudRequested()));
-
/* Alt+F1 reveals the launcher and gives the keyboard focus to the Dash Button. */
Hotkey* altF1 = HotkeyMonitor::instance().getHotkeyFor(Qt::Key_F1, Qt::AltModifier);
connect(altF1, SIGNAL(pressed()), SLOT(onAltF1Pressed()));
@@ -479,6 +492,37 @@
Q_EMIT lastFocusedWindowChanged(d->m_last_focused_window);
}
+void ShellManager::onHudActivationShortcutChanged()
+{
+ // TODO It might make sense to abstract this logic
+ // of switching between hotkey and hotmodifier and put it
+ // in a class in libunity-2d-private
+ if (d->m_hudHotModifier) {
+ d->m_hudHotModifier->disconnect(this);
+ d->m_hudHotModifier = NULL;
+ }
+ if (d->m_hudHotKey) {
+ d->m_hudHotKey->disconnect(this);
+ d->m_hudHotKey = NULL;
+ }
+
+ int x11KeyCode;
+ Qt::KeyboardModifiers modifiers;
+ const QString shortcut = d->m_gconfItem->getValue().toString();
+ const bool success = GKeySequenceParser::parse(shortcut, &x11KeyCode, &modifiers);
+ if (success) {
+ if (x11KeyCode != 0) {
+ d->m_hudHotKey = HotkeyMonitor::instance().getHotkeyFor(x11KeyCode, modifiers);
+ connect(d->m_hudHotKey, SIGNAL(pressed()), SLOT(toggleHudRequested()));
+ } else if (modifiers != Qt::NoModifier) {
+ d->m_hudHotModifier = KeyboardModifiersMonitor::instance()->getHotModifierFor(modifiers);
+ connect(d->m_hudHotModifier, SIGNAL(tapped()), SLOT(toggleHudRequested()));
+ }
+ } else {
+ qWarning().nospace() << "Could not parse the key sequence " << shortcut << ". HUD won't be activated";
+ }
+}
+
/* ----------------- super key handling ---------------- */
void
@@ -580,7 +624,7 @@
Shortcut for 0 should activate item with index 10.
In other words, the indexes are activated in the same order as
the keys appear on a standard keyboard. */
- Qt::Key key = hotkey->key();
+ const int key = hotkey->key();
if (key >= Qt::Key_1 && key <= Qt::Key_9) {
int index = key - Qt::Key_0;
if (hotkey->modifiers() & Qt::ShiftModifier) {
=== modified file 'shell/app/shellmanager.h'
--- shell/app/shellmanager.h 2012-03-14 08:29:06 +0000
+++ shell/app/shellmanager.h 2012-04-02 16:31:23 +0000
@@ -117,6 +117,8 @@
void onActiveWorkspaceChanged();
+ void onHudActivationShortcutChanged();
+
private:
Q_DISABLE_COPY(ShellManager)
ShellManagerPrivate * const d;
=== modified file 'tests/manual-tests/hud.txt'
--- tests/manual-tests/hud.txt 2012-03-20 11:14:30 +0000
+++ tests/manual-tests/hud.txt 2012-04-02 16:31:23 +0000
@@ -15,3 +15,13 @@
* Use arrow keys to navigate up/down through the options returned
--> Check Orca speaks the contents of the results
+
+----
+ * Go into ccsm
+ * Change Key to Show HUD to Super+Alt
+--> Verify Super+Alt shows the HUD
+
+----
+ * Go into ccsm
+ * Change Key to Show HUD to Super+Alt
+--> Verify Super+Alt shows the HUD
\ No newline at end of file