/*************************************************************************** * Copyright (C) 2009-2019 by Ilya Kotov * * forkotov02@ya.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., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #ifdef QMMP_WS_X11 #include #include #include #include #include #include #include #include #define Visual XVisual extern "C" { #include #include #include #include #include } #undef CursorShape #undef Status #undef Bool #undef None #undef KeyPress #undef Visual #include #include #include #include #include "hotkeymanager.h" quint32 Hotkey::defaultKey() { return defaultKey(action); } quint32 Hotkey::defaultKey(int act) { //default key bindings QMap keyMap; keyMap[PLAY] = 0; keyMap[STOP] = XF86XK_AudioStop; keyMap[PAUSE] = XF86XK_AudioPause; keyMap[PLAY_PAUSE] = XF86XK_AudioPlay; keyMap[NEXT] = XF86XK_AudioNext; keyMap[PREVIOUS] = XF86XK_AudioPrev; keyMap[SHOW_HIDE] = 0; keyMap[VOLUME_UP] = XF86XK_AudioRaiseVolume; keyMap[VOLUME_DOWN] = XF86XK_AudioLowerVolume; keyMap[FORWARD] = 0; keyMap[REWIND] = 0; keyMap[JUMP_TO_TRACK] = 0; keyMap[VOLUME_MUTE] = XF86XK_AudioMute; return keyMap[act]; } HotkeyManager::HotkeyManager(QObject *parent) : QObject(parent) { if(!QX11Info::isPlatformX11()) { qWarning("HotkeyManager: X11 not found. Plugin disabled"); return; } QCoreApplication::instance()->installEventFilter(this); WId rootWindow = DefaultRootWindow(QX11Info::display()); QSettings settings(Qmmp::configFile(), QSettings::IniFormat); //load settings settings.beginGroup("Hotkey"); for (int i = Hotkey::PLAY, j = 0; i <= Hotkey::VOLUME_MUTE; ++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); if(!hotkey->code) continue; XGrabKey(QX11Info::display(), hotkey->code, mod | mask_mod, rootWindow, True, GrabModeAsync, GrabModeAsync); hotkey->mod = mod | mask_mod; m_grabbedKeys << hotkey; } } } settings.endGroup(); XSync(QX11Info::display(), False); qApp->installNativeEventFilter(this); } HotkeyManager::~HotkeyManager() { qApp->removeNativeEventFilter(this); while(!m_grabbedKeys.isEmpty()) { Hotkey *key = m_grabbedKeys.takeFirst (); if(key->code) XUngrabKey(QX11Info::display(), key->code, key->mod, QX11Info::appRootWindow()); delete key; } } 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::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(eventType); Q_UNUSED(result); xcb_generic_event_t *e = static_cast(message); if(e->response_type == XCB_KEY_PRESS) { xcb_key_press_event_t *ke = (xcb_key_press_event_t*)e; quint32 key = keycodeToKeysym(ke->detail); quint32 mod = ke->state; SoundCore *core = SoundCore::instance(); MediaPlayer *player = MediaPlayer::instance(); 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: player->play(); break; case Hotkey::STOP: player->stop(); break; case Hotkey::PAUSE: core->pause(); break; case Hotkey::PLAY_PAUSE: if (core->state() == Qmmp::Stopped) player->play(); else if (core->state() != Qmmp::FatalError) core->pause(); break; case Hotkey::NEXT: player->next(); break; case Hotkey::PREVIOUS: player->previous(); break; case Hotkey::SHOW_HIDE: UiHelper::instance()->toggleVisibility(); break; case Hotkey::VOLUME_UP: core->volumeUp(); break; case Hotkey::VOLUME_DOWN: core->volumeDown(); break; case Hotkey::FORWARD: core->seek(core->elapsed() + 5000); break; case Hotkey::REWIND: core->seek(qMax(qint64(0), core->elapsed() - 5000)); break; case Hotkey::JUMP_TO_TRACK: UiHelper::instance()->jumpToTrack(); break; case Hotkey::VOLUME_MUTE: SoundCore::instance()->setMuted(!SoundCore::instance()->isMuted()); break; } } } return false; } QList HotkeyManager::ignModifiersList() { QList ret = { 0, Mod2Mask, LockMask, (Mod2Mask | LockMask) }; return ret; } quint32 HotkeyManager::keycodeToKeysym(quint32 keycode) { return XkbKeycodeToKeysym(QX11Info::display(), keycode, 0, 0); } #include "moc_hotkeymanager.cpp" #endif