aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/General/hotkey/hotkeymanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/General/hotkey/hotkeymanager.cpp')
-rw-r--r--src/plugins/General/hotkey/hotkeymanager.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/plugins/General/hotkey/hotkeymanager.cpp b/src/plugins/General/hotkey/hotkeymanager.cpp
new file mode 100644
index 000000000..5a78c910a
--- /dev/null
+++ b/src/plugins/General/hotkey/hotkeymanager.cpp
@@ -0,0 +1,266 @@
+/***************************************************************************
+ * Copyright (C) 2009 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * Copyright (C) 2003-2007 by Justin Karneges and Michail Pishchagin *
+ * *
+ * 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * 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, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <QX11Info>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QCoreApplication>
+#include <QApplication>
+#include <QDesktopWidget>
+#define Visual XVisual
+extern "C"
+{
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/XF86keysym.h>
+}
+#undef CursorShape
+#undef Status
+#undef Bool
+#undef None
+#undef KeyPress
+#undef Visual
+
+#include <qmmp/qmmp.h>
+#include <qmmp/soundcore.h>
+#include <qmmpui/mediaplayer.h>
+#include "hotkeymanager.h"
+
+quint32 Hotkey::defaultKey()
+{
+ return defaultKey(action);
+}
+
+quint32 Hotkey::defaultKey(int act)
+{
+ //default key bindings
+ QMap<int, quint32> keyMap;
+ keyMap[PLAY] = XF86XK_AudioPlay;
+ keyMap[STOP] = XF86XK_AudioStop;
+ keyMap[PAUSE] = XF86XK_AudioPause;
+ keyMap[PLAY_PAUSE] = 0;
+ keyMap[NEXT] = XF86XK_AudioNext;
+ keyMap[PREVIOUS] = XF86XK_AudioPrev;
+ keyMap[SHOW_HIDE] = 0;
+ return keyMap[act];
+}
+
+HotkeyManager::HotkeyManager(QObject *parent) : General(parent)
+{
+ QCoreApplication::instance()->installEventFilter(this);
+ WId rootWindow = QX11Info::appRootWindow();
+ QSettings settings(Qmmp::configFile(), QSettings::IniFormat); //load settings
+ settings.beginGroup("Hotkey");
+ for (int i = Hotkey::PLAY, j = 0; i <= Hotkey::SHOW_HIDE; ++i, ++j)
+ {
+ quint32 key = settings.value(QString("key_%1").arg(i), Hotkey::defaultKey(i)).toUInt();
+ quint32 mod = settings.value(QString("modifiers_%1").arg(i), 0).toUInt();
+
+ if (key)
+ {
+ foreach(long mask_mod, ignModifiersList())
+ {
+ Hotkey *hotkey = new Hotkey;
+ hotkey->action = i;
+ hotkey->key = key;
+ hotkey->code = XKeysymToKeycode(QX11Info::display(), hotkey->key);
+ XGrabKey(QX11Info::display(), hotkey->code, mod | mask_mod, rootWindow, False,
+ GrabModeAsync, GrabModeAsync);
+ hotkey->mod = mod | mask_mod;
+ m_grabbedKeys << hotkey;
+ }
+ }
+ }
+ settings.endGroup();
+ XSync(QX11Info::display(), False);
+// XSetErrorHandler();
+}
+
+HotkeyManager::~HotkeyManager()
+{
+ foreach(Hotkey *key, m_grabbedKeys)
+ XUngrabKey(QX11Info::display(), key->code, key->mod, QX11Info::appRootWindow());
+ while (!m_grabbedKeys.isEmpty())
+ delete m_grabbedKeys.takeFirst ();
+}
+
+const QString HotkeyManager::getKeyString(quint32 key, quint32 modifiers)
+{
+ QString strModList[] = { "Control", "Shift", "Alt", "Mod2", "Mod3", "Super", "Mod5" };
+ quint32 modList[] = { ControlMask, ShiftMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask };
+ QString keyStr;
+ for (int j = 0; j < 7; j++)
+ {
+ if (modifiers & modList[j])
+ keyStr.append(strModList[j] + "+");
+ }
+ keyStr.append(XKeysymToString(key));
+ return keyStr;
+}
+
+bool HotkeyManager::eventFilter(QObject* o, QEvent* e)
+{
+ //receive events from active and root windows only
+ if (e->type() == QEvent::KeyPress && (o == qApp->desktop () || o == qApp->activeWindow ()))
+ {
+ QKeyEvent* k = static_cast<QKeyEvent*>(e);
+ quint32 key = k->nativeVirtualKey ();
+ quint32 mod = k->nativeModifiers ();
+ foreach(Hotkey *hotkey, m_grabbedKeys)
+ {
+ if (hotkey->key != key || hotkey->mod != mod)
+ continue;
+ qDebug("HotkeyManager: [%s] pressed", qPrintable(getKeyString(key, mod)));
+
+ switch (hotkey->action)
+ {
+ case Hotkey::PLAY:
+ MediaPlayer::instance()->play();
+ break;
+ case Hotkey::STOP:
+ MediaPlayer::instance()->stop();
+ break;
+ case Hotkey::PAUSE:
+ SoundCore::instance()->pause();
+ break;
+ case Hotkey::PLAY_PAUSE:
+ if (SoundCore::instance()->state() == Qmmp::Stopped)
+ MediaPlayer::instance()->play();
+ else if (SoundCore::instance()->state() != Qmmp::FatalError)
+ SoundCore::instance()->pause();
+ break;
+ case Hotkey::NEXT:
+ MediaPlayer::instance()->next();
+ break;
+ case Hotkey::PREVIOUS:
+ MediaPlayer::instance()->previous();
+ break;
+ case Hotkey::SHOW_HIDE:
+ toggleVisibility();
+ }
+ qApp->processEvents();
+ }
+ }
+ return QObject::eventFilter(o, e);
+}
+long HotkeyManager::m_alt_mask = 0;
+long HotkeyManager::m_meta_mask = 0;
+long HotkeyManager::m_super_mask = 0;
+long HotkeyManager::m_hyper_mask = 0;
+long HotkeyManager::m_numlock_mask = 0;
+bool HotkeyManager::m_haveMods = FALSE;
+
+//copied from globalshortcutmanager_x11.cpp by Justin Karneges and Michail Pishchagin (Psi project)
+void HotkeyManager::ensureModifiers()
+{
+ if (m_haveMods)
+ return;
+
+ Display* appDpy = QX11Info::display();
+ XModifierKeymap* map = XGetModifierMapping(appDpy);
+ if (map)
+ {
+ // XKeycodeToKeysym helper code adapeted from xmodmap
+ int min_keycode, max_keycode, keysyms_per_keycode = 1;
+ XDisplayKeycodes (appDpy, &min_keycode, &max_keycode);
+ XFree(XGetKeyboardMapping (appDpy, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode));
+
+ int i, maskIndex = 0, mapIndex = 0;
+ for (maskIndex = 0; maskIndex < 8; maskIndex++)
+ {
+ for (i = 0; i < map->max_keypermod; i++)
+ {
+ if (map->modifiermap[mapIndex])
+ {
+ KeySym sym;
+ int symIndex = 0;
+ do
+ {
+ sym = XKeycodeToKeysym(appDpy, map->modifiermap[mapIndex], symIndex);
+ symIndex++;
+ }
+ while ( !sym && symIndex < keysyms_per_keycode);
+ if (!m_alt_mask && (sym == XK_Alt_L || sym == XK_Alt_R))
+ {
+ m_alt_mask = 1 << maskIndex;
+ }
+ if (!m_meta_mask && (sym == XK_Meta_L || sym == XK_Meta_R))
+ {
+ m_meta_mask = 1 << maskIndex;
+ }
+ if (!m_super_mask && (sym == XK_Super_L || sym == XK_Super_R))
+ {
+ m_super_mask = 1 << maskIndex;
+ }
+ if (!m_hyper_mask && (sym == XK_Hyper_L || sym == XK_Hyper_R))
+ {
+ m_hyper_mask = 1 << maskIndex;
+ }
+ if (!m_numlock_mask && (sym == XK_Num_Lock))
+ {
+ m_numlock_mask = 1 << maskIndex;
+ }
+ }
+ mapIndex++;
+ }
+ }
+
+ XFreeModifiermap(map);
+
+ // logic from qt source see gui/kernel/qkeymapper_x11.cpp
+ if (!m_meta_mask || m_meta_mask == m_alt_mask)
+ {
+ // no meta keys... s,meta,super,
+ m_meta_mask = m_super_mask;
+ if (!m_meta_mask || m_meta_mask == m_alt_mask)
+ {
+ // no super keys either? guess we'll use hyper then
+ m_meta_mask = m_hyper_mask;
+ }
+ }
+ }
+ else
+ {
+ // assume defaults
+ m_alt_mask = Mod1Mask;
+ m_meta_mask = Mod4Mask;
+ }
+
+ m_haveMods = TRUE;
+}
+
+QList<long> HotkeyManager::ignModifiersList()
+{
+ ensureModifiers();
+ QList<long> ret;
+ if (m_numlock_mask)
+ {
+ ret << 0 << LockMask << m_numlock_mask << (LockMask | m_numlock_mask);
+ }
+ else
+ {
+ ret << 0 << LockMask;
+ }
+ return ret;
+}