Skip to content

Commit

Permalink
feat: add click multi
Browse files Browse the repository at this point in the history
  • Loading branch information
rankun committed Aug 2, 2020
1 parent 576f49e commit 0f5c116
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 5 deletions.
33 changes: 32 additions & 1 deletion QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize &frameSize, c
}

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

if (QEvent::KeyPress == from->type()) {
Expand Down Expand Up @@ -110,6 +110,9 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize &frameSize, c
case KeyMap::KMT_CLICK_TWICE:
processKeyClick(node.data.clickTwice.keyNode.pos, true, false, from);
return;
case KeyMap::KMT_CLICK_MULTI:
processKeyClickMulti(node.data.clickMulti.keyNode.delayClickNodes, node.data.clickMulti.keyNode.delayClickNodesCount, from);
return;
case KeyMap::KMT_DRAG:
processKeyDrag(node.data.drag.keyNode.pos, node.data.drag.keyNode.extendPos, from);
return;
Expand Down Expand Up @@ -309,6 +312,34 @@ void InputConvertGame::processKeyClick(const QPointF &clickPos, bool clickTwice,
}
}

void InputConvertGame::processKeyClickMulti(const KeyMap::DelayClickNode *nodes, const int count, const QKeyEvent *from)
{
if (QEvent::KeyPress != from->type()) {
return;
}

int key = from->key();
int delay = 0;
QPointF clickPos;

for (int i = 0; i < count; i++) {
delay += nodes[i].delay;
clickPos = nodes[i].pos;
QTimer::singleShot(delay, this, [this, key, clickPos]() {
int id = attachTouchID(key);
sendTouchDownEvent(id, clickPos);
});

// Don't up it too fast
delay += 20;
QTimer::singleShot(delay, this, [this, key, clickPos]() {
int id = getTouchID(key);
sendTouchUpEvent(id, clickPos);
detachTouchID(key);
});
}
}

void InputConvertGame::processKeyDrag(const QPointF &startPos, QPointF endPos, const QKeyEvent *from)
{
if (QEvent::KeyPress == from->type()) {
Expand Down
3 changes: 3 additions & 0 deletions QtScrcpy/device/controller/inputconvert/inputconvertgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class InputConvertGame : public InputConvertNormal
// click
void processKeyClick(const QPointF &clickPos, bool clickTwice, bool switchMap, const QKeyEvent *from);

// click mutil
void processKeyClickMulti(const KeyMap::DelayClickNode *nodes, const int count, const QKeyEvent *from);

// drag
void processKeyDrag(const QPointF &startPos, QPointF endPos, const QKeyEvent *from);

Expand Down
78 changes: 78 additions & 0 deletions QtScrcpy/device/controller/inputconvert/keymap/keymap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,41 @@ void KeyMap::loadKeyMap(const QString &json)
keyMapNode.data.click.switchMap = getItemBool(node, "switchMap");
m_keyMapNodes.push_back(keyMapNode);
} break;
case KeyMap::KMT_CLICK_MULTI: {
// safe check
if (!checkForClickMulti(node)) {
qWarning() << "json error: keyMapNodes node format error";
break;
}
QPair<ActionType, int> key = getItemKey(node, "key");
if (key.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("key").toString();
break;
}
KeyMapNode keyMapNode;
keyMapNode.type = type;
keyMapNode.data.clickMulti.keyNode.type = key.first;
keyMapNode.data.clickMulti.keyNode.key = key.second;

QJsonArray clickNodes = node.value("clickNodes").toArray();
QJsonObject clickNode;
keyMapNode.data.clickMulti.keyNode.delayClickNodesCount = 0;

for (int i = 0; i < clickNodes.size(); i++) {
if (i >= MAX_DELAY_CLICK_NODES) {
qInfo("clickNodes too much, up to %1", MAX_DELAY_CLICK_NODES);
break;
}
clickNode = clickNodes.at(i).toObject();
DelayClickNode delayClickNode;
delayClickNode.delay = getItemDouble(clickNode, "delay");
delayClickNode.pos = getItemPos(clickNode, "pos");
keyMapNode.data.clickMulti.keyNode.delayClickNodes[i] = delayClickNode;
keyMapNode.data.clickMulti.keyNode.delayClickNodesCount++;
}

m_keyMapNodes.push_back(keyMapNode);
} break;
case KeyMap::KMT_STEER_WHEEL: {
// safe check
if (!checkForSteerWhell(node)) {
Expand Down Expand Up @@ -310,6 +345,10 @@ void KeyMap::makeReverseMap()
QMultiHash<int, KeyMapNode *> &m = node.data.clickTwice.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
m.insert(node.data.clickTwice.keyNode.key, &node);
} break;
case KMT_CLICK_MULTI: {
QMultiHash<int, KeyMapNode *> &m = node.data.clickMulti.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
m.insert(node.data.clickMulti.keyNode.key, &node);
} break;
case KMT_STEER_WHEEL: {
QMultiHash<int, KeyMapNode *> &ml = node.data.steerWheel.left.type == AT_KEY ? m_rmapKey : m_rmapMouse;
ml.insert(node.data.steerWheel.left.key, &node);
Expand Down Expand Up @@ -410,6 +449,45 @@ bool KeyMap::checkForClick(const QJsonObject &node)
return checkForClickTwice(node) && checkItemBool(node, "switchMap");
}

bool KeyMap::checkForClickMulti(const QJsonObject &node)
{
bool ret = true;

if (!node.contains("clickNodes") || !node.value("clickNodes").isArray()) {
qWarning("json error: no find clickNodes");
return false;
}

QJsonArray clickNodes = node.value("clickNodes").toArray();
QJsonObject clickNode;
int size = clickNodes.size();
if (0 == size) {
qWarning("json error: clickNodes is empty");
return false;
}

for (int i = 0; i < size; i++) {
if (!clickNodes.at(i).isObject()) {
qWarning("json error: clickNodes node must be json object");
ret = false;
break;
}

clickNode = clickNodes.at(i).toObject();
if (!checkForDelayClickNode(clickNode)) {
ret = false;
break;
}
}

return ret;
}

bool KeyMap::checkForDelayClickNode(const QJsonObject &node)
{
return checkItemPos(node, "pos") && checkItemDouble(node, "delay");
}

bool KeyMap::checkForClickTwice(const QJsonObject &node)
{
return checkItemString(node, "key") && checkItemPos(node, "pos");
Expand Down
24 changes: 21 additions & 3 deletions QtScrcpy/device/controller/inputconvert/keymap/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <QRectF>
#include <QVector>

#define MAX_DELAY_CLICK_NODES 50

class KeyMap : public QObject
{
Q_OBJECT
Expand All @@ -18,6 +20,7 @@ class KeyMap : public QObject
KMT_INVALID = -1,
KMT_CLICK = 0,
KMT_CLICK_TWICE,
KMT_CLICK_MULTI,
KMT_STEER_WHEEL,
KMT_DRAG,
KMT_MOUSE_MOVE
Expand All @@ -32,13 +35,21 @@ class KeyMap : public QObject
};
Q_ENUM(ActionType)

struct DelayClickNode
{
int delay = 0;
QPointF pos = QPointF(0, 0);
};

struct KeyNode
{
ActionType type = AT_INVALID;
int key = Qt::Key_unknown;
QPointF pos = QPointF(0, 0); // normal key
QPointF extendPos = QPointF(0, 0); // for drag
double extendOffset = 0.0; // for steerWheel
QPointF pos = QPointF(0, 0); // normal key
QPointF extendPos = QPointF(0, 0); // for drag
double extendOffset = 0.0; // for steerWheel
DelayClickNode delayClickNodes[MAX_DELAY_CLICK_NODES]; // for multi clicks
int delayClickNodesCount = 0;

KeyNode(
ActionType type = AT_INVALID,
Expand Down Expand Up @@ -66,6 +77,10 @@ class KeyMap : public QObject
KeyNode keyNode;
} clickTwice;
struct
{
KeyNode keyNode;
} clickMulti;
struct
{
QPointF centerPos = { 0.0, 0.0 };
KeyNode left, right, up, down;
Expand All @@ -83,6 +98,7 @@ class KeyMap : public QObject
DATA() {}
~DATA() {}
} data;

KeyMapNode() {}
~KeyMapNode() {}
};
Expand Down Expand Up @@ -116,6 +132,8 @@ class KeyMap : public QObject

// safe check for KeyMapNode
bool checkForClick(const QJsonObject &node);
bool checkForClickMulti(const QJsonObject &node);
bool checkForDelayClickNode(const QJsonObject &node);
bool checkForClickTwice(const QJsonObject &node);
bool checkForSteerWhell(const QJsonObject &node);
bool checkForDrag(const QJsonObject &node);
Expand Down
7 changes: 6 additions & 1 deletion docs/KeyMapDes.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ There are several types of key mapping as follows:
-type The type of key mapping, each element in keyMapNodes needs to be specified, and can be of the following types:
-KMT_CLICK Ordinary click, key press simulates finger press, key lift simulates finger lift
-KMT_CLICK_TWICE Double click, key press simulates finger press and then lift, key lift simulates finger press and then lift
- KMT_CLICK_MULTI Click multiple times. According to the delay and pos in the clickNodes array, press one key to simulate touching multiple positions
-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
-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.

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

-KMT_CLICK_TWICE
-key The key code to be mapped
-pos simulates the location of the touch
-pos Simulates the location of the touch

-KMT_CLICK_MULTI
-delay Delay `delay` ms before simulating touch
-pos Simulates the location of the touch

-KMT_DRAG
-key The key code to be mapped
Expand Down
5 changes: 5 additions & 0 deletions docs/KeyMapDes_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
- type 按键映射的类型,每个keyMapNodes中的元素都需要指明,可以是如下类型:
- KMT_CLICK 普通点击,按键按下模拟为手指按下,按键抬起模拟为手指抬起
- KMT_CLICK_TWICE 两次点击,按键按下模拟为手指按下再抬起,按键抬起模拟为手指按下再抬起
- KMT_CLICK_MULTI 多次点击,根据clickNodes数组中的delay和pos实现一个按键多次点击
- KMT_DRAG 拖拽,按键按下模拟为手指按下并拖动一段距离,按键抬起模拟为手指抬起
- KMT_STEER_WHEEL 方向盘映射,专用于FPS游戏中移动人物脚步的方向盘的映射,需要4个按键来配合。

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

- KMT_CLICK_MULTI
- delay 延迟delay毫秒以后再模拟触摸
- pos 模拟触摸的位置

- KMT_DRAG
- key 要映射的按键码
- startPos 模拟触摸拖动的开始位置
Expand Down
39 changes: 39 additions & 0 deletions keymap/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"switchKey": "Key_QuoteLeft",
"keyMapNodes": [
{
"comment": "测试一键多点",
"type": "KMT_CLICK_MULTI",
"key": "Key_Space",
"clickNodes": [
{
"delay": 500,
"pos": {
"x": 0.5,
"y": 0.5
}
},
{
"delay": 500,
"pos": {
"x": 0.8,
"y": 0.8
}
}
]
},
{
"comment": "测试拖拽",
"type": "KMT_DRAG",
"key": "Key_Up",
"startPos": {
"x": 0.5,
"y": 0.7
},
"endPos": {
"x": 0.5,
"y": 0.3
}
}
]
}

0 comments on commit 0f5c116

Please sign in to comment.