Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "keyboardapi.h"
23 :
24 : #include <QGuiApplication>
25 : #include <QKeyEvent>
26 : #include <QWindow>
27 : #include <QKeySequence>
28 : #include <QTimer>
29 :
30 : #include "log.h"
31 :
32 : using namespace muse::api;
33 :
34 0 : KeyboardApi::KeyboardApi(api::IApiEngine* e)
35 0 : : api::ApiObject(e)
36 : {
37 0 : }
38 :
39 0 : static int keyCode(const QString& key)
40 : {
41 0 : QKeySequence seq = QKeySequence::fromString(key.toUpper());
42 0 : if (seq.count() == 0) {
43 0 : LOGE() << "not recognized key: " << key;
44 0 : return -1;
45 : }
46 0 : int code = seq[0].toCombined();
47 0 : return code;
48 0 : }
49 :
50 0 : static Qt::KeyboardModifier keyMod(const QString& key)
51 : {
52 : static QMap<QString, Qt::KeyboardModifier> map = {
53 0 : { "SHIFT", Qt::ShiftModifier },
54 0 : { "CTRL", Qt::ControlModifier },
55 0 : { "ALT", Qt::AltModifier },
56 0 : { "META", Qt::MetaModifier },
57 0 : { "KEYPAD", Qt::KeypadModifier },
58 0 : { "GROUPSWITCH", Qt::GroupSwitchModifier }
59 0 : };
60 :
61 0 : return map.value(key.toUpper(), Qt::NoModifier);
62 0 : }
63 :
64 0 : QWindow* KeyboardApi::window() const
65 : {
66 0 : QWindow* w = qApp->focusWindow();
67 0 : if (!w) {
68 0 : w = mainWindow()->qWindow();
69 : }
70 :
71 0 : return w;
72 : }
73 :
74 0 : void KeyboardApi::doPressKey(QWindow* w, int key, Qt::KeyboardModifier mod, const QString& text)
75 : {
76 0 : QKeyEvent pressEvent(QEvent::KeyPress, key, mod, text);
77 0 : qApp->sendEvent(w, &pressEvent);
78 0 : }
79 :
80 0 : void KeyboardApi::doReleaseKey(QWindow* w, int key, Qt::KeyboardModifier mod, const QString& text)
81 : {
82 0 : QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, key, mod, text);
83 0 : qApp->postEvent(w, releaseEvent);
84 0 : }
85 :
86 0 : void KeyboardApi::key(const QString& key, const QString& mod)
87 : {
88 0 : LOGD() << key;
89 :
90 0 : int code = keyCode(key);
91 0 : if (code < 0) {
92 0 : return;
93 : }
94 :
95 0 : QWindow* w = window();
96 :
97 0 : doPressKey(w, code, keyMod(mod), key);
98 0 : doReleaseKey(w, code, keyMod(mod), key);
99 : }
100 :
101 0 : void KeyboardApi::pressKey(const QString& key, const QString& mod)
102 : {
103 0 : LOGD() << key;
104 :
105 0 : int code = keyCode(key);
106 0 : if (code < 0) {
107 0 : return;
108 : }
109 :
110 0 : QWindow* w = window();
111 :
112 0 : doPressKey(w, code, keyMod(mod), key);
113 : }
114 :
115 0 : void KeyboardApi::releaseKey(const QString& key, const QString& mod)
116 : {
117 0 : LOGD() << key;
118 :
119 0 : int code = keyCode(key);
120 0 : if (code < 0) {
121 0 : return;
122 : }
123 :
124 0 : QWindow* w = window();
125 :
126 0 : doReleaseKey(w, code, keyMod(mod), key);
127 : }
128 :
129 0 : void KeyboardApi::repeatKey(const QString& k, int count)
130 : {
131 0 : for (int i = 0; i < count; ++i) {
132 0 : QTimer::singleShot(10, this, [this, k]() {
133 0 : key(k);
134 0 : });
135 : }
136 0 : }
137 :
138 0 : void KeyboardApi::text(const QString& text)
139 : {
140 0 : for (const QChar& ch : text) {
141 0 : QTimer::singleShot(10, this, [this, ch]() {
142 0 : key(ch);
143 0 : });
144 : }
145 0 : }
|