Skip to content

Commit 41cc42a

Browse files
author
rankun
committed
feat: add click multi
1 parent 1773f3c commit 41cc42a

File tree

7 files changed

+184
-5
lines changed

7 files changed

+184
-5
lines changed

QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp

+32-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize &frameSize, c
7878
}
7979

8080
// small eyes
81-
if (from->key() == m_keyMap.getMouseMoveMap().data.mouseMove.smallEyes.key) {
81+
if (m_keyMap.isValidMouseMoveMap() && from->key() == m_keyMap.getMouseMoveMap().data.mouseMove.smallEyes.key) {
8282
m_ctrlMouseMove.smallEyes = (QEvent::KeyPress == from->type());
8383

8484
if (QEvent::KeyPress == from->type()) {
@@ -110,6 +110,9 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize &frameSize, c
110110
case KeyMap::KMT_CLICK_TWICE:
111111
processKeyClick(node.data.clickTwice.keyNode.pos, true, false, from);
112112
return;
113+
case KeyMap::KMT_CLICK_MULTI:
114+
processKeyClickMulti(node.data.clickMulti.keyNode.delayClickNodes, node.data.clickMulti.keyNode.delayClickNodesCount, from);
115+
return;
113116
case KeyMap::KMT_DRAG:
114117
processKeyDrag(node.data.drag.keyNode.pos, node.data.drag.keyNode.extendPos, from);
115118
return;
@@ -309,6 +312,34 @@ void InputConvertGame::processKeyClick(const QPointF &clickPos, bool clickTwice,
309312
}
310313
}
311314

315+
void InputConvertGame::processKeyClickMulti(const KeyMap::DelayClickNode *nodes, const int count, const QKeyEvent *from)
316+
{
317+
if (QEvent::KeyPress != from->type()) {
318+
return;
319+
}
320+
321+
int key = from->key();
322+
int delay = 0;
323+
QPointF clickPos;
324+
325+
for (int i = 0; i < count; i++) {
326+
delay += nodes[i].delay;
327+
clickPos = nodes[i].pos;
328+
QTimer::singleShot(delay, this, [this, key, clickPos]() {
329+
int id = attachTouchID(key);
330+
sendTouchDownEvent(id, clickPos);
331+
});
332+
333+
// Don't up it too fast
334+
delay += 20;
335+
QTimer::singleShot(delay, this, [this, key, clickPos]() {
336+
int id = getTouchID(key);
337+
sendTouchUpEvent(id, clickPos);
338+
detachTouchID(key);
339+
});
340+
}
341+
}
342+
312343
void InputConvertGame::processKeyDrag(const QPointF &startPos, QPointF endPos, const QKeyEvent *from)
313344
{
314345
if (QEvent::KeyPress == from->type()) {

QtScrcpy/device/controller/inputconvert/inputconvertgame.h

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class InputConvertGame : public InputConvertNormal
4040
// click
4141
void processKeyClick(const QPointF &clickPos, bool clickTwice, bool switchMap, const QKeyEvent *from);
4242

43+
// click mutil
44+
void processKeyClickMulti(const KeyMap::DelayClickNode *nodes, const int count, const QKeyEvent *from);
45+
4346
// drag
4447
void processKeyDrag(const QPointF &startPos, QPointF endPos, const QKeyEvent *from);
4548

QtScrcpy/device/controller/inputconvert/keymap/keymap.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,41 @@ void KeyMap::loadKeyMap(const QString &json)
175175
keyMapNode.data.click.switchMap = getItemBool(node, "switchMap");
176176
m_keyMapNodes.push_back(keyMapNode);
177177
} break;
178+
case KeyMap::KMT_CLICK_MULTI: {
179+
// safe check
180+
if (!checkForClickMulti(node)) {
181+
qWarning() << "json error: keyMapNodes node format error";
182+
break;
183+
}
184+
QPair<ActionType, int> key = getItemKey(node, "key");
185+
if (key.first == AT_INVALID) {
186+
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("key").toString();
187+
break;
188+
}
189+
KeyMapNode keyMapNode;
190+
keyMapNode.type = type;
191+
keyMapNode.data.clickMulti.keyNode.type = key.first;
192+
keyMapNode.data.clickMulti.keyNode.key = key.second;
193+
194+
QJsonArray clickNodes = node.value("clickNodes").toArray();
195+
QJsonObject clickNode;
196+
keyMapNode.data.clickMulti.keyNode.delayClickNodesCount = 0;
197+
198+
for (int i = 0; i < clickNodes.size(); i++) {
199+
if (i >= MAX_DELAY_CLICK_NODES) {
200+
qInfo("clickNodes too much, up to %1", MAX_DELAY_CLICK_NODES);
201+
break;
202+
}
203+
clickNode = clickNodes.at(i).toObject();
204+
DelayClickNode delayClickNode;
205+
delayClickNode.delay = getItemDouble(clickNode, "delay");
206+
delayClickNode.pos = getItemPos(clickNode, "pos");
207+
keyMapNode.data.clickMulti.keyNode.delayClickNodes[i] = delayClickNode;
208+
keyMapNode.data.clickMulti.keyNode.delayClickNodesCount++;
209+
}
210+
211+
m_keyMapNodes.push_back(keyMapNode);
212+
} break;
178213
case KeyMap::KMT_STEER_WHEEL: {
179214
// safe check
180215
if (!checkForSteerWhell(node)) {
@@ -310,6 +345,10 @@ void KeyMap::makeReverseMap()
310345
QMultiHash<int, KeyMapNode *> &m = node.data.clickTwice.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
311346
m.insert(node.data.clickTwice.keyNode.key, &node);
312347
} break;
348+
case KMT_CLICK_MULTI: {
349+
QMultiHash<int, KeyMapNode *> &m = node.data.clickMulti.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
350+
m.insert(node.data.clickMulti.keyNode.key, &node);
351+
} break;
313352
case KMT_STEER_WHEEL: {
314353
QMultiHash<int, KeyMapNode *> &ml = node.data.steerWheel.left.type == AT_KEY ? m_rmapKey : m_rmapMouse;
315354
ml.insert(node.data.steerWheel.left.key, &node);
@@ -410,6 +449,45 @@ bool KeyMap::checkForClick(const QJsonObject &node)
410449
return checkForClickTwice(node) && checkItemBool(node, "switchMap");
411450
}
412451

452+
bool KeyMap::checkForClickMulti(const QJsonObject &node)
453+
{
454+
bool ret = true;
455+
456+
if (!node.contains("clickNodes") || !node.value("clickNodes").isArray()) {
457+
qWarning("json error: no find clickNodes");
458+
return false;
459+
}
460+
461+
QJsonArray clickNodes = node.value("clickNodes").toArray();
462+
QJsonObject clickNode;
463+
int size = clickNodes.size();
464+
if (0 == size) {
465+
qWarning("json error: clickNodes is empty");
466+
return false;
467+
}
468+
469+
for (int i = 0; i < size; i++) {
470+
if (!clickNodes.at(i).isObject()) {
471+
qWarning("json error: clickNodes node must be json object");
472+
ret = false;
473+
break;
474+
}
475+
476+
clickNode = clickNodes.at(i).toObject();
477+
if (!checkForDelayClickNode(clickNode)) {
478+
ret = false;
479+
break;
480+
}
481+
}
482+
483+
return ret;
484+
}
485+
486+
bool KeyMap::checkForDelayClickNode(const QJsonObject &node)
487+
{
488+
return checkItemPos(node, "pos") && checkItemDouble(node, "delay");
489+
}
490+
413491
bool KeyMap::checkForClickTwice(const QJsonObject &node)
414492
{
415493
return checkItemString(node, "key") && checkItemPos(node, "pos");

QtScrcpy/device/controller/inputconvert/keymap/keymap.h

+21-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <QRectF>
1010
#include <QVector>
1111

12+
#define MAX_DELAY_CLICK_NODES 50
13+
1214
class KeyMap : public QObject
1315
{
1416
Q_OBJECT
@@ -18,6 +20,7 @@ class KeyMap : public QObject
1820
KMT_INVALID = -1,
1921
KMT_CLICK = 0,
2022
KMT_CLICK_TWICE,
23+
KMT_CLICK_MULTI,
2124
KMT_STEER_WHEEL,
2225
KMT_DRAG,
2326
KMT_MOUSE_MOVE
@@ -32,13 +35,21 @@ class KeyMap : public QObject
3235
};
3336
Q_ENUM(ActionType)
3437

38+
struct DelayClickNode
39+
{
40+
int delay = 0;
41+
QPointF pos = QPointF(0, 0);
42+
};
43+
3544
struct KeyNode
3645
{
3746
ActionType type = AT_INVALID;
3847
int key = Qt::Key_unknown;
39-
QPointF pos = QPointF(0, 0); // normal key
40-
QPointF extendPos = QPointF(0, 0); // for drag
41-
double extendOffset = 0.0; // for steerWheel
48+
QPointF pos = QPointF(0, 0); // normal key
49+
QPointF extendPos = QPointF(0, 0); // for drag
50+
double extendOffset = 0.0; // for steerWheel
51+
DelayClickNode delayClickNodes[MAX_DELAY_CLICK_NODES]; // for multi clicks
52+
int delayClickNodesCount = 0;
4253

4354
KeyNode(
4455
ActionType type = AT_INVALID,
@@ -66,6 +77,10 @@ class KeyMap : public QObject
6677
KeyNode keyNode;
6778
} clickTwice;
6879
struct
80+
{
81+
KeyNode keyNode;
82+
} clickMulti;
83+
struct
6984
{
7085
QPointF centerPos = { 0.0, 0.0 };
7186
KeyNode left, right, up, down;
@@ -83,6 +98,7 @@ class KeyMap : public QObject
8398
DATA() {}
8499
~DATA() {}
85100
} data;
101+
86102
KeyMapNode() {}
87103
~KeyMapNode() {}
88104
};
@@ -116,6 +132,8 @@ class KeyMap : public QObject
116132

117133
// safe check for KeyMapNode
118134
bool checkForClick(const QJsonObject &node);
135+
bool checkForClickMulti(const QJsonObject &node);
136+
bool checkForDelayClickNode(const QJsonObject &node);
119137
bool checkForClickTwice(const QJsonObject &node);
120138
bool checkForSteerWhell(const QJsonObject &node);
121139
bool checkForDrag(const QJsonObject &node);

docs/KeyMapDes.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ There are several types of key mapping as follows:
3535
-type The type of key mapping, each element in keyMapNodes needs to be specified, and can be of the following types:
3636
-KMT_CLICK Ordinary click, key press simulates finger press, key lift simulates finger lift
3737
-KMT_CLICK_TWICE Double click, key press simulates finger press and then lift, key lift simulates finger press and then lift
38+
- KMT_CLICK_MULTI Click multiple times. According to the delay and pos in the clickNodes array, press one key to simulate touching multiple positions
3839
-KMT_DRAG drag and drop, the key press is simulated as a finger press and drag a distance, the key lift is simulated as a finger lift
3940
-KMT_STEER_WHEEL steering wheel mapping, which is dedicated to the mapping of the steering wheel for moving characters in FPS games, requires 4 buttons to cooperate.
4041

@@ -47,7 +48,11 @@ Description of the unique attributes of different key mapping types:
4748

4849
-KMT_CLICK_TWICE
4950
-key The key code to be mapped
50-
-pos simulates the location of the touch
51+
-pos Simulates the location of the touch
52+
53+
-KMT_CLICK_MULTI
54+
-delay Delay `delay` ms before simulating touch
55+
-pos Simulates the location of the touch
5156

5257
-KMT_DRAG
5358
-key The key code to be mapped

docs/KeyMapDes_zh.md

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- type 按键映射的类型,每个keyMapNodes中的元素都需要指明,可以是如下类型:
3636
- KMT_CLICK 普通点击,按键按下模拟为手指按下,按键抬起模拟为手指抬起
3737
- KMT_CLICK_TWICE 两次点击,按键按下模拟为手指按下再抬起,按键抬起模拟为手指按下再抬起
38+
- KMT_CLICK_MULTI 多次点击,根据clickNodes数组中的delay和pos实现一个按键多次点击
3839
- KMT_DRAG 拖拽,按键按下模拟为手指按下并拖动一段距离,按键抬起模拟为手指抬起
3940
- KMT_STEER_WHEEL 方向盘映射,专用于FPS游戏中移动人物脚步的方向盘的映射,需要4个按键来配合。
4041

@@ -49,6 +50,10 @@
4950
- key 要映射的按键码
5051
- pos 模拟触摸的位置
5152

53+
- KMT_CLICK_MULTI
54+
- delay 延迟delay毫秒以后再模拟触摸
55+
- pos 模拟触摸的位置
56+
5257
- KMT_DRAG
5358
- key 要映射的按键码
5459
- startPos 模拟触摸拖动的开始位置

keymap/test.json

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"switchKey": "Key_QuoteLeft",
3+
"keyMapNodes": [
4+
{
5+
"comment": "测试一键多点",
6+
"type": "KMT_CLICK_MULTI",
7+
"key": "Key_Space",
8+
"clickNodes": [
9+
{
10+
"delay": 500,
11+
"pos": {
12+
"x": 0.5,
13+
"y": 0.5
14+
}
15+
},
16+
{
17+
"delay": 500,
18+
"pos": {
19+
"x": 0.8,
20+
"y": 0.8
21+
}
22+
}
23+
]
24+
},
25+
{
26+
"comment": "测试拖拽",
27+
"type": "KMT_DRAG",
28+
"key": "Key_Up",
29+
"startPos": {
30+
"x": 0.5,
31+
"y": 0.7
32+
},
33+
"endPos": {
34+
"x": 0.5,
35+
"y": 0.3
36+
}
37+
}
38+
]
39+
}

0 commit comments

Comments
 (0)