/* * Deskflow -- mouse and keyboard sharing utility * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2008 Volker Lanz * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception */ #include "KeySequence.h" #include // this table originally comes from Qt sources (gui/kernel/qkeysequence.cpp) // and is heavily modified for Deskflow static const struct { int key; const char *name; } keyname[] = { {Qt::Key_Space, "Space"}, {Qt::Key_Escape, "Escape"}, {Qt::Key_Tab, "Tab"}, {Qt::Key_Backtab, "LeftTab"}, {Qt::Key_Backspace, "BackSpace"}, {Qt::Key_Return, "Return"}, {Qt::Key_Insert, "Insert"}, {Qt::Key_Delete, "Delete"}, {Qt::Key_Pause, "Pause"}, {Qt::Key_Print, "Print"}, {Qt::Key_SysReq, "SysReq"}, {Qt::Key_Home, "Home"}, {Qt::Key_End, "End"}, {Qt::Key_Left, "Left"}, {Qt::Key_Up, "Up"}, {Qt::Key_Right, "Right"}, {Qt::Key_Down, "Down"}, {Qt::Key_PageUp, "PageUp"}, {Qt::Key_PageDown, "PageDown"}, {Qt::Key_CapsLock, "CapsLock"}, {Qt::Key_NumLock, "NumLock"}, {Qt::Key_ScrollLock, "ScrollLock"}, {Qt::Key_Menu, "Menu"}, {Qt::Key_Help, "Help"}, {Qt::Key_Enter, "KP_Enter"}, {Qt::Key_Clear, "Clear"}, {Qt::Key_Back, "WWWBack"}, {Qt::Key_Forward, "WWWForward"}, {Qt::Key_Stop, "WWWStop"}, {Qt::Key_Refresh, "WWWRefresh"}, {Qt::Key_VolumeDown, "AudioDown"}, {Qt::Key_VolumeMute, "AudioMute"}, {Qt::Key_VolumeUp, "AudioUp"}, {Qt::Key_MediaPlay, "AudioPlay"}, {Qt::Key_MediaStop, "AudioStop"}, {Qt::Key_MediaPrevious, "AudioPrev"}, {Qt::Key_MediaNext, "AudioNext"}, {Qt::Key_HomePage, "WWWHome"}, {Qt::Key_Favorites, "WWWFavorites"}, {Qt::Key_Search, "WWWSearch"}, {Qt::Key_Standby, "Sleep"}, {Qt::Key_LaunchMail, "AppMail"}, {Qt::Key_LaunchMedia, "AppMedia"}, {Qt::Key_Launch0, "AppUser1"}, {Qt::Key_Launch1, "AppUser2"}, {Qt::Key_Select, "Select"}, {0, nullptr} }; bool KeySequence::isMouseButton() const { return !m_Sequence.isEmpty() && m_Sequence.last() < Qt::Key_Space; } QString KeySequence::toString() const { QString result; for (int i = 0; i < m_Sequence.size(); i++) { result += keyToString(m_Sequence[i]); if (i != m_Sequence.size() - 1) result += "+"; } return result; } bool KeySequence::appendMouseButton(int button) { return appendKey(button, 0); } bool KeySequence::appendKey(int key, int modifiers) { if (m_Sequence.size() == 4) return true; switch (key) { case Qt::Key_AltGr: return false; case Qt::Key_Control: case Qt::Key_Alt: case Qt::Key_Shift: case Qt::Key_Meta: case Qt::Key_Menu: { int mod = modifiers & (~m_Modifiers); if (mod) { m_Sequence.append(mod); m_Modifiers |= mod; } } break; default: // see if we can handle this key, if not, don't accept it if (keyToString(key).isEmpty()) break; m_Sequence.append(key); setValid(true); return true; } return false; } void KeySequence::loadSettings(QSettings &settings) { sequence().clear(); int num = settings.beginReadArray("keys"); for (int i = 0; i < num; i++) { settings.setArrayIndex(i); sequence().append(settings.value("key", 0).toInt()); } settings.endArray(); setModifiers(0); setValid(true); } void KeySequence::saveSettings(QSettings &settings) const { settings.beginWriteArray("keys"); for (int i = 0; i < sequence().size(); i++) { settings.setArrayIndex(i); settings.setValue("key", sequence()[i]); } settings.endArray(); } QString KeySequence::keyToString(int key) { // nothing there? if (key == 0) return ""; // a hack to handle mouse buttons as if they were keys if (key < Qt::Key_Space) { switch (key) { case Qt::LeftButton: return "1"; case Qt::RightButton: return "2"; case Qt::MiddleButton: return "3"; default: qDebug() << "unknown key" << key; break; } return "4"; // qt only knows three mouse buttons, so assume it's an unknown // fourth one } // modifiers? if (key & Qt::ShiftModifier) return "Shift"; if (key & Qt::ControlModifier) return "Control"; if (key & Qt::AltModifier) return "Alt"; if (key & Qt::MetaModifier) return "Meta"; // treat key pad like normal keys (FIXME: we should have another lookup table // for keypad keys instead) key &= ~Qt::KeypadModifier; // a printable 7 bit character? if (key < 0x80 && key != Qt::Key_Space) return QChar(key & 0x7f).toLower(); // a function key? if (key >= Qt::Key_F1 && key <= Qt::Key_F35) return QString::fromUtf8("F%1").arg(key - Qt::Key_F1 + 1); // a special key? int i = 0; while (keyname[i].name) { if (key == keyname[i].key) return QString::fromUtf8(keyname[i].name); i++; } // representable in ucs2? if (key < 0x10000) { #if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0) const uint16_t keyHex = QChar(key).toLower().unicode(); return QString("\\u%1").arg(keyHex, kStrSize, kBase, kFillChar); #else return QString("\\u%1").arg(QChar(key).toLower().unicode(), kStrSize, kBase, kFillChar); #endif } // give up, deskflow probably won't handle this return ""; }