Merge pull request #74 from barry-ran/dev

merge dev to master
This commit is contained in:
Barry 2020-01-31 20:54:46 -06:00 committed by GitHub
commit a6f3020f15
38 changed files with 1310 additions and 837 deletions

View file

@ -62,16 +62,16 @@ void AdbProcess::initSignals()
connect(this, &QProcess::readyReadStandardError, this,
[this](){
QString tmp = QString::fromLocal8Bit(readAllStandardError()).trimmed();
QString tmp = QString::fromUtf8(readAllStandardError()).trimmed();
m_errorOutput += tmp;
qWarning(QString("AdbProcess::error:%1").arg(tmp).toUtf8());
qWarning(QString("AdbProcess::error:%1").arg(tmp).toStdString().data());
});
connect(this, &QProcess::readyReadStandardOutput, this,
[this](){
QString tmp = QString::fromLocal8Bit(readAllStandardOutput()).trimmed();
QString tmp = QString::fromUtf8(readAllStandardOutput()).trimmed();
m_standardOutput += tmp;
qInfo(QString("AdbProcess::out:%1").arg(tmp).toUtf8());
qInfo(QString("AdbProcess::out:%1").arg(tmp).toStdString().data());
});
connect(this, &QProcess::started, this,

View file

@ -39,7 +39,10 @@ void Controller::postControlMsg(ControlMsg *controlMsg)
void Controller::test(QRect rc)
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_INJECT_TOUCH);
controlMsg->setInjectTouchMsgData(POINTER_ID_MOUSE, AMOTION_EVENT_ACTION_DOWN, AMOTION_EVENT_BUTTON_PRIMARY, rc, 1.0f);
controlMsg->setInjectTouchMsgData(POINTER_ID_MOUSE,
AMOTION_EVENT_ACTION_DOWN,
AMOTION_EVENT_BUTTON_PRIMARY,
rc, 1.0f);
postControlMsg(controlMsg);
}
@ -192,7 +195,7 @@ void Controller::keyEvent(const QKeyEvent *from, const QSize &frameSize, const Q
bool Controller::event(QEvent *event)
{
if (event && event->type() == ControlMsg::Control) {
if (event && static_cast<ControlMsg::Type>(event->type()) == ControlMsg::Control) {
ControlMsg* controlMsg = dynamic_cast<ControlMsg*>(event);
if (controlMsg) {
sendControl(controlMsg->serializeData());
@ -209,7 +212,7 @@ bool Controller::sendControl(const QByteArray &buffer)
}
qint32 len = 0;
if (m_controlSocket) {
len = m_controlSocket->write(buffer.data(), buffer.length());
len = static_cast<qint32>(m_controlSocket->write(buffer.data(), buffer.length()));
}
return len == buffer.length() ? true : false;
}

View file

@ -42,9 +42,8 @@ void InputConvertGame::mouseEvent(const QMouseEvent *from, const QSize &frameSiz
if (processMouseClick(from)) {
return;
}
} else {
InputConvertNormal::mouseEvent(from, frameSize, showSize);
}
InputConvertNormal::mouseEvent(from, frameSize, showSize);
}
void InputConvertGame::wheelEvent(const QWheelEvent *from, const QSize &frameSize, const QSize &showSize)
@ -73,10 +72,10 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize& frameSize, c
// 处理特殊按键:可以在按键映射和普通映射间切换的按键
if (m_needSwitchGameAgain
&& KeyMap::KMT_CLICK == node.type
&& node.click.switchMap) {
&& node.data.click.switchMap) {
updateSize(frameSize, showSize);
// Qt::Key_Tab Qt::Key_M for PUBG mobile
processKeyClick(node.click.keyNode.pos, false, node.click.switchMap, from);
processKeyClick(node.data.click.keyNode.pos, false, node.data.click.switchMap, from);
return;
}
@ -93,13 +92,13 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize& frameSize, c
return;
// 处理普通按键
case KeyMap::KMT_CLICK:
processKeyClick(node.click.keyNode.pos, false, node.click.switchMap, from);
processKeyClick(node.data.click.keyNode.pos, false, node.data.click.switchMap, from);
return;
case KeyMap::KMT_CLICK_TWICE:
processKeyClick(node.clickTwice.keyNode.pos, true, false, from);
processKeyClick(node.data.clickTwice.keyNode.pos, true, false, from);
return;
case KeyMap::KMT_DRAG:
processKeyDrag(node.drag.startPos, node.drag.endPos, from);
processKeyDrag(node.data.drag.keyNode.pos, node.data.drag.keyNode.extendPos, from);
return;
default:
break;
@ -112,25 +111,18 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize& frameSize, c
void InputConvertGame::loadKeyMap(const QString &json)
{
m_keyMap.loadKeyMap(json);
if (m_keyMap.isValidMouseMoveMap()) {
m_ctrlMouseMove.valid = true;
m_ctrlMouseMove.touching = false;
m_ctrlMouseMove.startPosRel = m_keyMap.getMouseMoveMap().startPos;
m_ctrlMouseMove.startPosPixel = calcFrameAbsolutePos(m_ctrlMouseMove.startPosRel);
}
if(m_keyMap.isValidSteerWheelMap()){
m_ctrlSteerWheel.valid = true;
m_ctrlMouseMove.touching = false;
}
}
void InputConvertGame::updateSize(const QSize &frameSize, const QSize &showSize)
{
if (showSize != m_showSize) {
if (m_gameMap && m_keyMap.isValidMouseMoveMap()) {
// show size change, resize grab cursor
emit grabCursor(true);
}
}
m_frameSize = frameSize;
m_showSize = showSize;
if(m_ctrlMouseMove.valid){
m_ctrlMouseMove.startPosPixel = calcScreenAbsolutePos(m_ctrlMouseMove.startPosRel);
}
}
void InputConvertGame::sendTouchDownEvent(int id, QPointF pos)
@ -159,7 +151,11 @@ void InputConvertGame::sendTouchEvent(int id, QPointF pos, AndroidMotioneventAct
if (!controlMsg) {
return;
}
controlMsg->setInjectTouchMsgData(id, action, (AndroidMotioneventButtons)0, QRect(calcFrameAbsolutePos(pos).toPoint(), m_frameSize), 1.0f);
controlMsg->setInjectTouchMsgData(static_cast<quint64>(id),
action,
static_cast<AndroidMotioneventButtons>(0),
QRect(calcFrameAbsolutePos(pos).toPoint(),m_frameSize),
1.0f);
sendControlMsg(controlMsg);
}
@ -181,25 +177,20 @@ QPointF InputConvertGame::calcScreenAbsolutePos(QPointF relativePos)
int InputConvertGame::attachTouchID(int key)
{
//QMetaEnum map = QMetaEnum::fromType<Qt::Key>();
for (int i = 0; i < MULTI_TOUCH_MAX_NUM; i++) {
if (0 == multiTouchID[i]) {
multiTouchID[i] = key;
//qDebug() << "attach "<<key<<" ("<<map.valueToKey(key)<<") as "<<i;
if (0 == m_multiTouchID[i]) {
m_multiTouchID[i] = key;
return i;
}
}
//qDebug() << "attach "<<key<<" ("<<map.valueToKey(key)<<") failed ";
return -1;
}
void InputConvertGame::detachTouchID(int key)
{
//QMetaEnum map = QMetaEnum::fromType<Qt::Key>();
for (int i = 0; i < MULTI_TOUCH_MAX_NUM; i++) {
if (key == multiTouchID[i]) {
multiTouchID[i] = 0;
//qDebug() << "detach "<<key<<" ("<<map.valueToKey(key)<<") from "<<i;
if (key == m_multiTouchID[i]) {
m_multiTouchID[i] = 0;
return;
}
}
@ -208,7 +199,7 @@ void InputConvertGame::detachTouchID(int key)
int InputConvertGame::getTouchID(int key)
{
for (int i = 0; i < MULTI_TOUCH_MAX_NUM; i++) {
if (key == multiTouchID[i]) {
if (key == m_multiTouchID[i]) {
return i;
}
}
@ -222,49 +213,54 @@ void InputConvertGame::processSteerWheel(const KeyMap::KeyMapNode &node, const Q
int key = from->key();
bool flag = from->type() == QEvent::KeyPress;
// identify keys
if(key == node.steerWheel.up.key){
if (key == node.data.steerWheel.up.key) {
m_ctrlSteerWheel.pressedUp = flag;
}else if(key == node.steerWheel.right.key){
} else if (key == node.data.steerWheel.right.key) {
m_ctrlSteerWheel.pressedRight = flag;
}else if(key == node.steerWheel.down.key){
} else if (key == node.data.steerWheel.down.key) {
m_ctrlSteerWheel.pressedDown = flag;
}else{ // left
} else { // left
m_ctrlSteerWheel.pressedLeft = flag;
}
// calc offset and pressed number
QPointF offset(0.0, 0.0);
int nPressed = 0;
if(m_ctrlSteerWheel.pressedUp){
++nPressed;
offset.ry() -= node.steerWheel.up.offset;
int pressedNum = 0;
if (m_ctrlSteerWheel.pressedUp) {
++pressedNum;
offset.ry() -= node.data.steerWheel.up.extendOffset;
}
if(m_ctrlSteerWheel.pressedRight){
++nPressed;
offset.rx() += node.steerWheel.right.offset;
if (m_ctrlSteerWheel.pressedRight) {
++pressedNum;
offset.rx() += node.data.steerWheel.right.extendOffset;
}
if(m_ctrlSteerWheel.pressedDown){
++nPressed;
offset.ry() += node.steerWheel.down.offset;
if (m_ctrlSteerWheel.pressedDown) {
++pressedNum;
offset.ry() += node.data.steerWheel.down.extendOffset;
}
if(m_ctrlSteerWheel.pressedLeft){
++nPressed;
offset.rx() -= node.steerWheel.left.offset;
if (m_ctrlSteerWheel.pressedLeft) {
++pressedNum;
offset.rx() -= node.data.steerWheel.left.extendOffset;
}
// action
//qDebug()<<nPressed<<"-"<<char(from->key())<<"-"<<from->type()<<"-"<<offset;
if(nPressed == 0){ // release all
if(pressedNum == 0){
// touch up release all
int id = getTouchID(m_ctrlSteerWheel.touchKey);
sendTouchUpEvent(id, node.steerWheel.centerPos + m_ctrlSteerWheel.lastOffset);
sendTouchUpEvent(id, node.data.steerWheel.centerPos + m_ctrlSteerWheel.lastOffset);
detachTouchID(m_ctrlSteerWheel.touchKey);
}else{
} else {
int id;
if(nPressed == 1 && flag){ // first press
// first press, get key and touch down
if (pressedNum == 1 && flag) {
m_ctrlSteerWheel.touchKey = from->key();
id = attachTouchID(m_ctrlSteerWheel.touchKey);
sendTouchDownEvent(id, node.steerWheel.centerPos);
}else{
sendTouchDownEvent(id, node.data.steerWheel.centerPos);
} else {
// jsut get touch id and move
id = getTouchID(m_ctrlSteerWheel.touchKey);
}
sendTouchMoveEvent(id, node.steerWheel.centerPos + offset);
sendTouchMoveEvent(id, node.data.steerWheel.centerPos + offset);
}
m_ctrlSteerWheel.lastOffset = offset;
return;
@ -299,10 +295,14 @@ void InputConvertGame::processKeyClick(
void InputConvertGame::processKeyDrag(const QPointF& startPos, QPointF endPos, const QKeyEvent* from)
{
if(QEvent::KeyPress == from->type()){
if (QEvent::KeyPress == from->type()){
int id = attachTouchID(from->key());
sendTouchDownEvent(id, startPos);
sendTouchMoveEvent(id, endPos);
}
if (QEvent::KeyRelease == from->type()) {
int id = getTouchID(from->key());
sendTouchUpEvent(id, endPos);
detachTouchID(from->key());
}
@ -317,16 +317,19 @@ bool InputConvertGame::processMouseClick(const QMouseEvent *from)
return false;
}
qDebug() << "mouse event " << from->type();
if (QEvent::MouseButtonPress == from->type() || QEvent::MouseButtonDblClick == from->type()) {
int id = attachTouchID(from->button());
sendTouchDownEvent(id, node.click.keyNode.pos);
} else if (QEvent::MouseButtonRelease == from->type()) {
sendTouchUpEvent(getTouchID(from->button()), node.click.keyNode.pos);
detachTouchID(from->button());
} else {
return false;
sendTouchDownEvent(id, node.data.click.keyNode.pos);
return true;
}
return true;
if (QEvent::MouseButtonRelease == from->type()) {
int id = getTouchID(from->button());
sendTouchUpEvent(id, node.data.click.keyNode.pos);
detachTouchID(from->button());
return true;
}
return false;
}
bool InputConvertGame::processMouseMove(const QMouseEvent *from)
@ -334,30 +337,61 @@ bool InputConvertGame::processMouseMove(const QMouseEvent *from)
if (QEvent::MouseMove != from->type()) {
return false;
}
if (m_ctrlMouseMove.touching) {
QPointF mousePos = from->localPos();
mousePos.rx() /= m_showSize.width();
mousePos.ry() /= m_showSize.height();
QPointF offset = mousePos - m_ctrlMouseMove.startPosRel;
//qDebug()<<from->localPos()<<" - "<<m_mouseMoveLastConverPos<<" - "<<offset<<" - "<<offset.manhattanLength();
if(mousePos.x()<0.05 || mousePos.x()>0.95 || mousePos.y()<0.05 || mousePos.y()>0.95) {
//qDebug()<<"reset";
if (checkCursorPos(from)) {
m_ctrlMouseMove.lastPos = QPointF(0.0, 0.0);
return true;
}
if (!m_ctrlMouseMove.lastPos.isNull()) {
QPointF distance = from->localPos() - m_ctrlMouseMove.lastPos;
distance /= m_keyMap.getMouseMoveMap().data.mouseMove.speedRatio;
mouseMoveStartTouch(from);
startMouseMoveTimer();
m_ctrlMouseMove.lastConverPos.setX(m_ctrlMouseMove.lastConverPos.x() + distance.x() / m_showSize.width());
m_ctrlMouseMove.lastConverPos.setY(m_ctrlMouseMove.lastConverPos.y() + distance.y() / m_showSize.height());
if (m_ctrlMouseMove.lastConverPos.x() < 0.1
|| m_ctrlMouseMove.lastConverPos.x() > 0.8
|| m_ctrlMouseMove.lastConverPos.y() < 0.1
|| m_ctrlMouseMove.lastConverPos.y() > 0.8) {
mouseMoveStopTouch();
mouseMoveStartTouch(from);
}
offset /= m_keyMap.getMouseMoveMap().speedRatio;
m_ctrlMouseMove.lastPosRel = m_ctrlMouseMove.startPosRel + offset;
mouseMoveMovingTouch(m_ctrlMouseMove.lastPosRel);
} else {
m_ctrlMouseMove.touching = true;
mouseMoveStartTouch(from);
int left = from->globalX() - from->x();
int top = from->globalY() - from->y();
sendTouchMoveEvent(getTouchID(Qt::ExtraButton24), m_ctrlMouseMove.lastConverPos);
}
m_ctrlMouseMove.lastPos = from->localPos();
return true;
}
bool InputConvertGame::checkCursorPos(const QMouseEvent *from)
{
bool moveCursor = false;
QPoint pos = from->pos();
if (pos.x() < CURSOR_POS_CHECK) {
pos.setX(m_showSize.width() - CURSOR_POS_CHECK);
moveCursor = true;
} else if (pos.x() > m_showSize.width() - CURSOR_POS_CHECK) {
pos.setX(CURSOR_POS_CHECK);
moveCursor = true;
} else if (pos.y() < CURSOR_POS_CHECK) {
pos.setY(m_showSize.height() - CURSOR_POS_CHECK);
moveCursor = true;
} else if (pos.y() > m_showSize.height() - CURSOR_POS_CHECK) {
pos.setY(CURSOR_POS_CHECK);
moveCursor = true;
}
if (moveCursor) {
moveCursorTo(from, pos);
}
return moveCursor;
}
void InputConvertGame::moveCursorTo(const QMouseEvent *from, const QPoint &localPosPixel)
{
QPoint posOffset = from->pos() - localPosPixel;
@ -369,53 +403,56 @@ void InputConvertGame::moveCursorTo(const QMouseEvent *from, const QPoint &local
void InputConvertGame::mouseMoveStartTouch(const QMouseEvent* from)
{
moveCursorTo(from, m_ctrlMouseMove.startPosPixel.toPoint());
int id = attachTouchID(m_ctrlMouseMove.touchKey);
sendTouchDownEvent(id, m_ctrlMouseMove.startPosRel);
m_ctrlMouseMove.lastPosRel = m_ctrlMouseMove.startPosRel;
m_ctrlMouseMove.touching = true;
}
void InputConvertGame::mouseMoveMovingTouch(const QPointF& target)
{
sendTouchMoveEvent(getTouchID(m_ctrlMouseMove.touchKey), target);
Q_UNUSED(from)
if (!m_ctrlMouseMove.touching) {
QPointF mouseMoveStartPos = m_keyMap.getMouseMoveMap().data.mouseMove.startPos;
int id = attachTouchID(Qt::ExtraButton24);
sendTouchDownEvent(id, mouseMoveStartPos);
m_ctrlMouseMove.lastConverPos = mouseMoveStartPos;
m_ctrlMouseMove.touching = true;
}
}
void InputConvertGame::mouseMoveStopTouch()
{
int id = getTouchID(m_ctrlMouseMove.touchKey);
sendTouchUpEvent(id, m_ctrlMouseMove.lastPosRel);
detachTouchID(m_ctrlMouseMove.touchKey);
m_ctrlMouseMove.touching = false;
if (m_ctrlMouseMove.touching) {
sendTouchUpEvent(getTouchID(Qt::ExtraButton24), m_ctrlMouseMove.lastConverPos);
detachTouchID(Qt::ExtraButton24);
m_ctrlMouseMove.touching = false;
}
}
void InputConvertGame::startMouseMoveTimer()
{
stopMouseMoveTimer();
m_mouseMoveTimer = startTimer(1000);
m_ctrlMouseMove.timer = startTimer(1000);
}
void InputConvertGame::stopMouseMoveTimer()
{
if (0 != m_mouseMoveTimer) {
killTimer(m_mouseMoveTimer);
m_mouseMoveTimer = 0;
if (0 != m_ctrlMouseMove.timer) {
killTimer(m_ctrlMouseMove.timer);
m_ctrlMouseMove.timer = 0;
}
}
bool InputConvertGame::switchGameMap()
{
m_gameMap = !m_gameMap;
if (!m_keyMap.isValidMouseMoveMap()) {
return m_gameMap;
}
// grab cursor and set cursor only mouse move map
emit grabCursor(m_gameMap);
if (m_gameMap) {
#ifdef QT_NO_DEBUG
QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
#else
QGuiApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
#endif
#ifdef QT_NO_DEBUG
QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
#else
QGuiApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
#endif
} else {
if(m_ctrlMouseMove.touching)
mouseMoveStopTouch();
QGuiApplication::restoreOverrideCursor();
}
return m_gameMap;
@ -423,7 +460,7 @@ bool InputConvertGame::switchGameMap()
void InputConvertGame::timerEvent(QTimerEvent *event)
{
if (m_mouseMoveTimer == event->timerId()) {
if (m_ctrlMouseMove.timer == event->timerId()) {
stopMouseMoveTimer();
mouseMoveStopTouch();
}

View file

@ -48,13 +48,12 @@ protected:
bool processMouseMove(const QMouseEvent* from);
void moveCursorTo(const QMouseEvent* from, const QPoint& localPosPixel);
void mouseMoveStartTouch(const QMouseEvent* from);
void mouseMoveMovingTouch(const QPointF& target);
void mouseMoveStopTouch();
void startMouseMoveTimer();
void stopMouseMoveTimer();
bool switchGameMap();
bool checkCursorPos(const QMouseEvent *from);
protected:
void timerEvent(QTimerEvent *event);
@ -63,37 +62,29 @@ private:
QSize m_frameSize;
QSize m_showSize;
bool m_gameMap = false;
int multiTouchID[MULTI_TOUCH_MAX_NUM] = { 0 };
bool m_needSwitchGameAgain = false;
int m_multiTouchID[MULTI_TOUCH_MAX_NUM] = { 0 };
KeyMap m_keyMap;
// steer wheel
struct{
bool valid = false;
bool touching = false;
int touchKey = Qt::Key_unknown; // the first key pressed
int nKeyPressed = 0;
bool pressedUp = false, pressedDown = false;
bool pressedLeft = false, pressedRight = false;
QPointF centerPos;
struct {
// the first key pressed
int touchKey = Qt::Key_unknown;
bool pressedUp = false;
bool pressedDown = false;
bool pressedLeft = false;
bool pressedRight = false;
// for last up
QPointF lastOffset;
} m_ctrlSteerWheel;
// mouse move
struct{
bool valid = false;
struct {
QPointF lastConverPos;
QPointF lastPos = {0.0, 0.0};
bool touching = false;
const int touchKey = Qt::ExtraButton24;
QPointF startPosRel; // in [0, 1)
QPointF startPosPixel; // in [0, size)
QPointF lastPosRel;
//QPointF lastPosPixel;
int timer = 0;
} m_ctrlMouseMove;
int m_mouseMoveTimer = 0;
bool m_needSwitchGameAgain = false;
KeyMap m_keyMap;
};
#endif // INPUTCONVERTGAME_H

View file

@ -1,6 +1,5 @@
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMetaEnum>
#include <QFileInfo>
@ -40,51 +39,57 @@ void KeyMap::loadKeyMap(const QString &json)
QJsonParseError jsonError;
QJsonDocument jsonDoc;
QJsonObject rootObj;
QPair<ActionType, int> switchKey;
jsonDoc = QJsonDocument::fromJson(json.toUtf8(), &jsonError);
if(jsonError.error != QJsonParseError::NoError)
{
if(jsonError.error != QJsonParseError::NoError) {
errorString = QString("json error: %1").arg(jsonError.errorString());
goto parseError;
}
// switchKey
rootObj = jsonDoc.object();
if (rootObj.contains("switchKey") && rootObj.value("switchKey").isString()) {
QPair<ActionType, int> p = getItemKey(rootObj, "switchKey");
if(p.first == AT_INVALID){
errorString = QString("json error: switchKey invalid");
goto parseError;
}
m_switchType = p.first;
m_switchKey = p.second;
} else {
if (!checkItemString(rootObj, "switchKey")) {
errorString = QString("json error: no find switchKey");
goto parseError;
}
switchKey = getItemKey(rootObj, "switchKey");
if(switchKey.first == AT_INVALID) {
errorString = QString("json error: switchKey invalid");
goto parseError;
}
m_switchKey.type = switchKey.first;
m_switchKey.key= switchKey.second;
// mouseMoveMap
if (rootObj.contains("mouseMoveMap") && rootObj.value("mouseMoveMap").isObject()) {
QJsonObject mouseMoveMap = rootObj.value("mouseMoveMap").toObject();
if (mouseMoveMap.contains("speedRatio") && mouseMoveMap.value("speedRatio").isDouble()) {
m_mouseMoveMap.speedRatio = mouseMoveMap.value("speedRatio").toInt();
} else {
if (checkItemObject(rootObj, "mouseMoveMap")) {
QJsonObject mouseMoveMap = getItemObject(rootObj, "mouseMoveMap");
KeyMapNode keyMapNode;
keyMapNode.type = KMT_MOUSE_MOVE;
if (!checkItemDouble(mouseMoveMap, "speedRatio")) {
errorString = QString("json error: mouseMoveMap on find speedRatio");
goto parseError;
}
if (mouseMoveMap.contains("startPos") && mouseMoveMap.value("startPos").isObject()) {
QJsonObject startPos = mouseMoveMap.value("startPos").toObject();
if (startPos.contains("x") && startPos.value("x").isDouble()) {
m_mouseMoveMap.startPos.setX(startPos.value("x").toDouble());
}
if (startPos.contains("y") && startPos.value("y").isDouble()) {
m_mouseMoveMap.startPos.setY(startPos.value("y").toDouble());
}
} else {
keyMapNode.data.mouseMove.speedRatio = static_cast<int>(getItemDouble(mouseMoveMap, "speedRatio"));
if (!checkItemObject(mouseMoveMap, "startPos")) {
errorString = QString("json error: mouseMoveMap on find startPos");
goto parseError;
}
QJsonObject startPos = mouseMoveMap.value("startPos").toObject();
if (checkItemDouble(startPos, "x")) {
keyMapNode.data.mouseMove.startPos.setX(getItemDouble(startPos, "x"));
}
if (checkItemDouble(startPos, "y")) {
keyMapNode.data.mouseMove.startPos.setY(getItemDouble(startPos, "y"));
}
m_idxMouseMove = m_keyMapNodes.size();
m_keyMapNodes.push_back(keyMapNode);
}
// keyMapNodes
@ -103,7 +108,7 @@ void KeyMap::loadKeyMap(const QString &json)
goto parseError;
}
KeyMap::KeyMapType type = getItemType(node, "type");
KeyMap::KeyMapType type = getItemKeyMapType(node, "type");
switch (type) {
case KeyMap::KMT_CLICK:
{
@ -113,45 +118,45 @@ void KeyMap::loadKeyMap(const QString &json)
break;
}
QPair<ActionType, int> key = getItemKey(node, "key");
if(key.first == AT_INVALID){
if (key.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("key").toString();
break;
}
KeyMapNode keyMapNode;
keyMapNode.type = type;
keyMapNode.click.keyNode.type = key.first;
keyMapNode.click.keyNode.key = key.second;
keyMapNode.click.keyNode.pos = getItemPos(node, "pos");
keyMapNode.click.switchMap = getItemSwitchMap(node, "switchMap");
keyMapNode.data.click.keyNode.type = key.first;
keyMapNode.data.click.keyNode.key = key.second;
keyMapNode.data.click.keyNode.pos = getItemPos(node, "pos");
keyMapNode.data.click.switchMap = getItemBool(node, "switchMap");
m_keyMapNodes.push_back(keyMapNode);
}
break;
case KeyMap::KMT_CLICK_TWICE:
{
// safe check
if (!checkForClickDouble(node)) {
if (!checkForClickTwice(node)) {
qWarning() << "json error: keyMapNodes node format error";
break;
}
QPair<ActionType, int> key = getItemKey(node, "key");
if(key.first == AT_INVALID){
if (key.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("key").toString();
break;
}
KeyMapNode keyMapNode;
keyMapNode.type = type;
keyMapNode.click.keyNode.type = key.first;
keyMapNode.click.keyNode.key = key.second;
keyMapNode.click.keyNode.pos = getItemPos(node, "pos");
keyMapNode.click.switchMap = getItemSwitchMap(node, "switchMap");
keyMapNode.data.click.keyNode.type = key.first;
keyMapNode.data.click.keyNode.key = key.second;
keyMapNode.data.click.keyNode.pos = getItemPos(node, "pos");
keyMapNode.data.click.switchMap = getItemBool(node, "switchMap");
m_keyMapNodes.push_back(keyMapNode);
}
break;
case KeyMap::KMT_STEER_WHEEL:
{
// safe check
if(!checkForSteerWhell(node)){
if (!checkForSteerWhell(node)) {
qWarning() << "json error: keyMapNodes node format error";
break;
}
@ -159,33 +164,40 @@ void KeyMap::loadKeyMap(const QString &json)
QPair<ActionType, int> rightKey = getItemKey(node, "rightKey");
QPair<ActionType, int> upKey = getItemKey(node, "upKey");
QPair<ActionType, int> downKey = getItemKey(node, "downKey");
if(leftKey.first == AT_INVALID || rightKey.first == AT_INVALID
|| upKey.first == AT_INVALID || downKey.first == AT_INVALID)
{
if(leftKey.first == AT_INVALID)
if (leftKey.first == AT_INVALID || rightKey.first == AT_INVALID
|| upKey.first == AT_INVALID || downKey.first == AT_INVALID) {
if (leftKey.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("leftKey").toString();
if(rightKey.first == AT_INVALID)
}
if (rightKey.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("rightKey").toString();
if(upKey.first == AT_INVALID)
}
if (upKey.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("upKey").toString();
if(downKey.first == AT_INVALID)
}
if (downKey.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("downKey").toString();
}
break;
}
KeyMapNode keyMapNode;
keyMapNode.type = type;
keyMapNode.steerWheel.left = { leftKey.first, leftKey.second,
getItemNumber(node, "leftOffset") };
keyMapNode.steerWheel.right = { rightKey.first, rightKey.second,
getItemNumber(node, "rightOffset") };
keyMapNode.steerWheel.up = { upKey.first, upKey.second,
getItemNumber(node, "upOffset") };
keyMapNode.steerWheel.down = { downKey.first, downKey.second,
getItemNumber(node, "downOffset") };
keyMapNode.data.steerWheel.left = { leftKey.first, leftKey.second,
QPointF(0, 0), QPointF(0, 0),
getItemDouble(node, "leftOffset") };
keyMapNode.data.steerWheel.right = { rightKey.first, rightKey.second,
QPointF(0, 0), QPointF(0, 0),
getItemDouble(node, "rightOffset") };
keyMapNode.data.steerWheel.up = { upKey.first, upKey.second,
QPointF(0, 0), QPointF(0, 0),
getItemDouble(node, "upOffset") };
keyMapNode.data.steerWheel.down = { downKey.first, downKey.second,
QPointF(0, 0), QPointF(0, 0),
getItemDouble(node, "downOffset") };
keyMapNode.steerWheel.centerPos = getItemPos(node, "centerPos");
keyMapNode.data.steerWheel.centerPos = getItemPos(node, "centerPos");
m_idxSteerWheel = m_keyMapNodes.size();
m_keyMapNodes.push_back(keyMapNode);
}
@ -193,22 +205,22 @@ void KeyMap::loadKeyMap(const QString &json)
case KeyMap::KMT_DRAG:
{
// safe check
if(!checkForDrag(node)){
if (!checkForDrag(node)) {
qWarning() << "json error: keyMapNodes node format error";
break;
}
QPair<ActionType, int> key = getItemKey(node, "key");
if(key.first == AT_INVALID){
if (key.first == AT_INVALID) {
qWarning() << "json error: keyMapNodes node invalid key: " << node.value("key").toString();
break;
}
KeyMapNode keyMapNode;
keyMapNode.type = type;
keyMapNode.drag.type = key.first;
keyMapNode.drag.key = key.second;
keyMapNode.drag.startPos = getItemPos(node, "startPos");
keyMapNode.drag.endPos = getItemPos(node, "endPos");
keyMapNode.data.drag.keyNode.type = key.first;
keyMapNode.data.drag.keyNode.key = key.second;
keyMapNode.data.drag.keyNode.pos = getItemPos(node, "startPos");
keyMapNode.data.drag.keyNode.extendPos = getItemPos(node, "endPos");
m_keyMapNodes.push_back(keyMapNode);
break;
}
@ -220,7 +232,7 @@ void KeyMap::loadKeyMap(const QString &json)
}
// this must be called after m_keyMapNodes is stable
makeReverseMap();
qWarning() << "Script updated.";
qInfo() << "Script updated.";
parseError:
if (!errorString.isEmpty()) {
@ -231,45 +243,41 @@ parseError:
const KeyMap::KeyMapNode& KeyMap::getKeyMapNode(int key)
{
auto p = rmapKey.value(key, &m_invalidNode);
if(p == &m_invalidNode)
return *rmapMouse.value(key, &m_invalidNode);
auto p = m_rmapKey.value(key, &m_invalidNode);
if (p == &m_invalidNode) {
return *m_rmapMouse.value(key, &m_invalidNode);
}
return *p;
}
const KeyMap::KeyMapNode& KeyMap::getKeyMapNodeKey(int key)
{
return *rmapKey.value(key, &m_invalidNode);
return *m_rmapKey.value(key, &m_invalidNode);
}
const KeyMap::KeyMapNode& KeyMap::getKeyMapNodeMouse(int key)
{
return *rmapMouse.value(key, &m_invalidNode);
return *m_rmapMouse.value(key, &m_invalidNode);
}
bool KeyMap::isSwitchOnKeyboard()
{
return m_switchType == AT_KEY;
return m_switchKey.type == AT_KEY;
}
int KeyMap::getSwitchKey()
{
return m_switchKey;
return m_switchKey.key;
}
const KeyMap::MouseMoveMap& KeyMap::getMouseMoveMap()
const KeyMap::KeyMapNode& KeyMap::getMouseMoveMap()
{
return m_mouseMoveMap;
}
const KeyMap::KeyMapNode& KeyMap::getSteerWheelMap()
{
return m_keyMapNodes[m_idxSteerWheel];
return m_keyMapNodes[m_idxMouseMove];
}
bool KeyMap::isValidMouseMoveMap()
{
return !m_mouseMoveMap.startPos.isNull();
return m_idxMouseMove != -1;
}
bool KeyMap::isValidSteerWheelMap()
@ -279,39 +287,39 @@ bool KeyMap::isValidSteerWheelMap()
void KeyMap::makeReverseMap()
{
rmapKey.clear();
rmapMouse.clear();
for(int i = 0 ;i < m_keyMapNodes.size(); ++i) {
m_rmapKey.clear();
m_rmapMouse.clear();
for (int i = 0 ; i < m_keyMapNodes.size(); ++i) {
auto& node = m_keyMapNodes[i];
switch (node.type) {
case KMT_CLICK:
{
QMultiHash<int, KeyMapNode*>& m = node.click.keyNode.type == AT_KEY ? rmapKey : rmapMouse;
m.insert(node.click.keyNode.key, &node);
QMultiHash<int, KeyMapNode*>& m = node.data.click.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
m.insert(node.data.click.keyNode.key, &node);
}
break;
case KMT_CLICK_TWICE:
{
QMultiHash<int, KeyMapNode*>& m = node.clickTwice.keyNode.type == AT_KEY ? rmapKey : rmapMouse;
m.insert(node.clickTwice.keyNode.key, &node);
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_STEER_WHEEL:
{
QMultiHash<int, KeyMapNode*>& ml = node.steerWheel.left.type == AT_KEY ? rmapKey : rmapMouse;
ml.insert(node.steerWheel.left.key, &node);
QMultiHash<int, KeyMapNode*>& mr = node.steerWheel.right.type == AT_KEY ? rmapKey : rmapMouse;
mr.insert(node.steerWheel.right.key, &node);
QMultiHash<int, KeyMapNode*>& mu = node.steerWheel.up.type == AT_KEY ? rmapKey : rmapMouse;
mu.insert(node.steerWheel.up.key, &node);
QMultiHash<int, KeyMapNode*>& md = node.steerWheel.down.type == AT_KEY ? rmapKey : rmapMouse;
md.insert(node.steerWheel.down.key, &node);
QMultiHash<int, KeyMapNode*>& ml = node.data.steerWheel.left.type == AT_KEY ? m_rmapKey : m_rmapMouse;
ml.insert(node.data.steerWheel.left.key, &node);
QMultiHash<int, KeyMapNode*>& mr = node.data.steerWheel.right.type == AT_KEY ? m_rmapKey : m_rmapMouse;
mr.insert(node.data.steerWheel.right.key, &node);
QMultiHash<int, KeyMapNode*>& mu = node.data.steerWheel.up.type == AT_KEY ? m_rmapKey : m_rmapMouse;
mu.insert(node.data.steerWheel.up.key, &node);
QMultiHash<int, KeyMapNode*>& md = node.data.steerWheel.down.type == AT_KEY ? m_rmapKey : m_rmapMouse;
md.insert(node.data.steerWheel.down.key, &node);
}
break;
case KMT_DRAG:
{
QMultiHash<int, KeyMapNode*>& m = node.drag.type == AT_KEY ? rmapKey : rmapMouse;
m.insert(node.drag.key, &node);
QMultiHash<int, KeyMapNode*>& m = node.data.drag.keyNode.type == AT_KEY ? m_rmapKey : m_rmapMouse;
m.insert(node.data.drag.keyNode.key, &node);
}
break;
default:
@ -320,51 +328,24 @@ void KeyMap::makeReverseMap()
}
}
// ---- check and get of json item ----
bool KeyMap::checkItemKey(const QJsonObject& node, const QString& name)
QString KeyMap::getItemString(const QJsonObject &node, const QString &name)
{
return node.contains(name) && node.value(name).isString();
return node.value(name).toString();
}
bool KeyMap::checkItemPos(const QJsonObject& node, const QString& name)
double KeyMap::getItemDouble(const QJsonObject& node, const QString& name)
{
if(node.contains(name) && node.value(name).isObject()){
QJsonObject pos = node.value(name).toObject();
return pos.contains("x") && pos.value("x").isDouble()
&& pos.contains("y") && pos.value("y").isDouble();
}
return false;
return node.value(name).toDouble();
}
bool KeyMap::checkItemDouble(const QJsonObject& node, const QString& name)
bool KeyMap::getItemBool(const QJsonObject& node, const QString& name)
{
return node.contains(name) && node.value(name).isDouble();
return node.value(name).toBool(false);
}
bool KeyMap::checkItemSwitchMap(const QJsonObject& node, const QString& name)
QJsonObject KeyMap::getItemObject(const QJsonObject &node, const QString &name)
{
return !node.contains(name) || node.value(name).isBool();
}
KeyMap::KeyMapType KeyMap::getItemType(const QJsonObject& node, const QString& name)
{
QString value = node.value(name).toString();
return static_cast<KeyMap::KeyMapType>(m_metaEnumKeyMapType.keyToValue(value.toStdString().c_str()));
}
QPair<KeyMap::ActionType, int> KeyMap::getItemKey(const QJsonObject& node, const QString& name)
{
QString value = node.value(name).toString();
int key = m_metaEnumKey.keyToValue(value.toStdString().c_str());
int btn = m_metaEnumMouseButtons.keyToValue(value.toStdString().c_str());
if(key == -1 && btn == -1){
return {AT_INVALID, -1};
}else if(key != -1){
return {AT_KEY, key};
}else{
return {AT_MOUSE, btn};
}
return node.value(name).toObject();
}
QPointF KeyMap::getItemPos(const QJsonObject& node, const QString& name)
@ -373,34 +354,70 @@ QPointF KeyMap::getItemPos(const QJsonObject& node, const QString& name)
return QPointF(pos.value("x").toDouble(), pos.value("y").toDouble());
}
double KeyMap::getItemNumber(const QJsonObject& node, const QString& name)
QPair<KeyMap::ActionType, int> KeyMap::getItemKey(const QJsonObject& node, const QString& name)
{
return node.value(name).toDouble();
QString value = getItemString(node, name);
int key = m_metaEnumKey.keyToValue(value.toStdString().c_str());
int btn = m_metaEnumMouseButtons.keyToValue(value.toStdString().c_str());
if (key == -1 && btn == -1) {
return {AT_INVALID, -1};
} else if (key != -1) {
return {AT_KEY, key};
} else {
return {AT_MOUSE, btn};
}
}
bool KeyMap::getItemSwitchMap(const QJsonObject& node, const QString& name)
KeyMap::KeyMapType KeyMap::getItemKeyMapType(const QJsonObject& node, const QString& name)
{
return node.value(name).toBool(false);
QString value = getItemString(node, name);
return static_cast<KeyMap::KeyMapType>(m_metaEnumKeyMapType.keyToValue(value.toStdString().c_str()));
}
bool KeyMap::checkItemString(const QJsonObject& node, const QString& name)
{
return node.contains(name) && node.value(name).isString();
}
// ---- check for key-map node ----
bool KeyMap::checkItemDouble(const QJsonObject& node, const QString& name)
{
return node.contains(name) && node.value(name).isDouble();
}
bool KeyMap::checkItemBool(const QJsonObject& node, const QString& name)
{
return node.contains(name) && node.value(name).isBool();
}
bool KeyMap::checkItemObject(const QJsonObject &node, const QString &name)
{
return node.contains(name) && node.value(name).isObject();
}
bool KeyMap::checkItemPos(const QJsonObject& node, const QString& name)
{
if (node.contains(name) && node.value(name).isObject()) {
QJsonObject pos = node.value(name).toObject();
return pos.contains("x") && pos.value("x").isDouble()
&& pos.contains("y") && pos.value("y").isDouble();
}
return false;
}
bool KeyMap::checkForClick(const QJsonObject& node)
{
return checkItemKey(node, "key") && checkItemPos(node, "pos")
&& checkItemSwitchMap(node, "switchMap");
return checkForClickTwice(node) && checkItemBool(node, "switchMap");
}
bool KeyMap::checkForClickDouble(const QJsonObject& node)
bool KeyMap::checkForClickTwice(const QJsonObject& node)
{
return checkForClick(node);
return checkItemString(node, "key") && checkItemPos(node, "pos");
}
bool KeyMap::checkForSteerWhell(const QJsonObject& node)
{
return checkItemKey(node, "leftKey") && checkItemKey(node, "rightKey")
&& checkItemKey(node, "upKey") && checkItemKey(node, "downKey")
return checkItemString(node, "leftKey") && checkItemString(node, "rightKey")
&& checkItemString(node, "upKey") && checkItemString(node, "downKey")
&& checkItemDouble(node, "leftOffset") && checkItemDouble(node, "rightOffset")
&& checkItemDouble(node, "upOffset") && checkItemDouble(node, "downOffset")
&& checkItemPos(node, "centerPos");
@ -408,8 +425,7 @@ bool KeyMap::checkForSteerWhell(const QJsonObject& node)
bool KeyMap::checkForDrag(const QJsonObject& node)
{
return checkItemKey(node, "key")
&& checkItemPos(node, "startPos") && checkItemPos(node, "endPos")
&& checkItemSwitchMap(node, "switchMap");
return checkItemString(node, "key")
&& checkItemPos(node, "startPos") && checkItemPos(node, "endPos");
}

View file

@ -7,8 +7,7 @@
#include <QPair>
#include <QMetaEnum>
#include <QMultiHash>
class QJsonObject;
#include <QJsonObject>
class KeyMap : public QObject
{
@ -20,6 +19,7 @@ public:
KMT_CLICK_TWICE,
KMT_STEER_WHEEL,
KMT_DRAG,
KMT_MOUSE_MOVE
};
Q_ENUM(KeyMapType)
@ -33,12 +33,14 @@ public:
struct KeyNode {
ActionType type = AT_INVALID;
int key = Qt::Key_unknown;
QPointF pos = QPointF(0, 0);
QPointF pos = QPointF(0, 0); // normal key
QPointF extendPos = QPointF(0, 0); // for drag
double extendOffset = 0.0; // for steerWheel
};
struct KeyMapNode {
KeyMapType type = KMT_INVALID;
union {
union DATA {
struct {
KeyNode keyNode;
bool switchMap = false;
@ -48,29 +50,22 @@ public:
} clickTwice;
struct {
QPointF centerPos = {0.0, 0.0};
struct DirInfo{
ActionType type = AT_KEY; // keyboard/mouse
int key = Qt::Key_unknown; // key/button
double offset = 0.0;
};
DirInfo left, right, up, down;
KeyNode left, right, up, down;
} steerWheel;
struct {
ActionType type = AT_KEY;
int key = Qt::Key_unknown;
QPointF startPos = QPointF(0, 0);
QPointF endPos = QPointF(0, 0);
KeyNode keyNode;
} drag;
};
struct {
QPointF startPos = {0.0, 0.0};
int speedRatio = 1;
} mouseMove;
DATA() {}
~DATA() {}
} data;
KeyMapNode() {}
~KeyMapNode() {}
};
struct MouseMoveMap {
QPointF startPos = {0.0, 0.0};
int speedRatio = 1;
};
KeyMap(QObject *parent = Q_NULLPTR);
virtual ~KeyMap();
@ -83,8 +78,7 @@ public:
bool isValidMouseMoveMap();
bool isValidSteerWheelMap();
const MouseMoveMap& getMouseMoveMap();
const KeyMapNode& getSteerWheelMap();
const KeyMap::KeyMapNode& getMouseMoveMap();
static const QString& getKeyMapPath();
@ -92,41 +86,50 @@ private:
// set up the reverse map from key/event event to keyMapNode
void makeReverseMap();
// parse json of the mapping script
bool checkItemKey(const QJsonObject& node, const QString& name="key");
bool checkItemPos(const QJsonObject& node, const QString& name="pos");
// safe check for base
bool checkItemString(const QJsonObject& node, const QString& name);
bool checkItemDouble(const QJsonObject& node, const QString& name);
bool checkItemSwitchMap(const QJsonObject& node, const QString& name="switchMap");
bool checkItemBool(const QJsonObject& node, const QString& name);
bool checkItemObject(const QJsonObject& node, const QString& name);
bool checkItemPos(const QJsonObject& node, const QString& name);
KeyMapType getItemType(const QJsonObject& node, const QString& name="type");
QPair<ActionType, int> getItemKey(const QJsonObject& node, const QString& name="key");
QPointF getItemPos(const QJsonObject& node, const QString& name="pos");
double getItemNumber(const QJsonObject& node, const QString& name);
bool getItemSwitchMap(const QJsonObject& node, const QString& name="switchMap");
private:
// safe check for KeyMapNode
bool checkForClick(const QJsonObject& node);
bool checkForClickDouble(const QJsonObject& node);
bool checkForClickTwice(const QJsonObject& node);
bool checkForSteerWhell(const QJsonObject& node);
bool checkForDrag(const QJsonObject& node);
// get keymap from json object
QString getItemString(const QJsonObject& node, const QString& name);
double getItemDouble(const QJsonObject& node, const QString& name);
bool getItemBool(const QJsonObject& node, const QString& name);
QJsonObject getItemObject(const QJsonObject& node, const QString& name);
QPointF getItemPos(const QJsonObject& node, const QString& name);
QPair<ActionType, int> getItemKey(const QJsonObject& node, const QString& name);
KeyMapType getItemKeyMapType(const QJsonObject& node, const QString& name);
private:
QVector<KeyMapNode> m_keyMapNodes;
KeyMapNode m_invalidNode;
ActionType m_switchType = AT_KEY;
int m_switchKey = Qt::Key_QuoteLeft;
MouseMoveMap m_mouseMoveMap;
static QString s_keyMapPath;
QVector<KeyMapNode> m_keyMapNodes;
KeyNode m_switchKey = { AT_KEY, Qt::Key_QuoteLeft };
// just for return
KeyMapNode m_invalidNode;
// steer wheel index
int m_idxSteerWheel = -1;
// mouse move index
int m_idxMouseMove = -1;
// mapping of key/mouse event name to index
QMetaEnum m_metaEnumKey = QMetaEnum::fromType<Qt::Key>();
QMetaEnum m_metaEnumMouseButtons = QMetaEnum::fromType<Qt::MouseButtons>();
QMetaEnum m_metaEnumKeyMapType = QMetaEnum::fromType<KeyMap::KeyMapType>();
// reverse map of key/mouse event
QMultiHash<int, KeyMapNode*> rmapKey;
QMultiHash<int, KeyMapNode*> rmapMouse;
QMultiHash<int, KeyMapNode*> m_rmapKey;
QMultiHash<int, KeyMapNode*> m_rmapMouse;
};
#endif // KEYMAP_H

View file

@ -12,7 +12,7 @@ AVFrameConvert::~AVFrameConvert()
}
void AVFrameConvert::setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixelFormat srcFormat)
void AVFrameConvert::setSrcFrameInfo(int srcWidth, int srcHeight, AVPixelFormat srcFormat)
{
m_srcWidth = srcWidth;
m_srcHeight = srcHeight;
@ -20,21 +20,21 @@ void AVFrameConvert::setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixe
qDebug() << "Convert::src frame info " << srcWidth << "x" << srcHeight;
}
void AVFrameConvert::getSrcFrameInfo(quint32& srcWidth, quint32& srcHeight, AVPixelFormat& srcFormat)
void AVFrameConvert::getSrcFrameInfo(int& srcWidth, int& srcHeight, AVPixelFormat& srcFormat)
{
srcWidth = m_srcWidth;
srcHeight = m_srcHeight;
srcFormat = m_srcFormat;
}
void AVFrameConvert::setDstFrameInfo(quint32 dstWidth, quint32 dstHeight, AVPixelFormat dstFormat)
void AVFrameConvert::setDstFrameInfo(int dstWidth, int dstHeight, AVPixelFormat dstFormat)
{
m_dstWidth = dstWidth;
m_dstHeight = dstHeight;
m_dstFormat = dstFormat;
}
void AVFrameConvert::getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat)
void AVFrameConvert::getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat)
{
dstWidth = m_dstWidth;
dstHeight = m_dstHeight;
@ -67,12 +67,15 @@ void AVFrameConvert::deInit()
}
}
bool AVFrameConvert::convert(AVFrame* srcFrame, AVFrame* dstFrame)
bool AVFrameConvert::convert(const AVFrame* srcFrame, AVFrame* dstFrame)
{
if(!m_convertCtx || !srcFrame || !dstFrame) {
return false;
}
qint32 ret = sws_scale(m_convertCtx, (const uint8_t* const*)srcFrame->data, srcFrame->linesize, 0, m_srcHeight, dstFrame->data, dstFrame->linesize);
qint32 ret = sws_scale(m_convertCtx,
static_cast<const uint8_t* const*>(srcFrame->data),
srcFrame->linesize, 0, m_srcHeight, dstFrame->data,
dstFrame->linesize);
if (0 == ret) {
return false;
}

View file

@ -16,22 +16,22 @@ public:
virtual ~AVFrameConvert();
public:
void setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixelFormat srcFormat);
void getSrcFrameInfo(quint32& srcWidth, quint32& srcHeight, AVPixelFormat& srcFormat);
void setDstFrameInfo(quint32 dstWidth, quint32 dstHeight, AVPixelFormat dstFormat);
void getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat);
void setSrcFrameInfo(int srcWidth, int srcHeight, AVPixelFormat srcFormat);
void getSrcFrameInfo(int& srcWidth, int& srcHeight, AVPixelFormat& srcFormat);
void setDstFrameInfo(int dstWidth, int dstHeight, AVPixelFormat dstFormat);
void getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat);
bool init();
bool isInit();
void deInit();
bool convert(AVFrame* srcFrame, AVFrame* dstFrame);
bool convert(const AVFrame* srcFrame, AVFrame* dstFrame);
private:
quint32 m_srcWidth = 0;
quint32 m_srcHeight = 0;
int m_srcWidth = 0;
int m_srcHeight = 0;
AVPixelFormat m_srcFormat = AV_PIX_FMT_NONE;
quint32 m_dstWidth = 0;
quint32 m_dstHeight = 0;
int m_dstWidth = 0;
int m_dstHeight = 0;
AVPixelFormat m_dstFormat = AV_PIX_FMT_NONE;
struct SwsContext *m_convertCtx = Q_NULLPTR;

View file

@ -9,6 +9,3 @@ SOURCES += \
$$PWD/fpscounter.cpp \
$$PWD/avframeconvert.cpp \
$$PWD/videobuffer.cpp
#DEFINES += SKIP_FRAMES

View file

@ -15,8 +15,9 @@ VideoBuffer::~VideoBuffer()
}
bool VideoBuffer::init()
bool VideoBuffer::init(bool renderExpiredFrames)
{
m_renderExpiredFrames = renderExpiredFrames;
m_decodingFrame = av_frame_alloc();
if (!m_decodingFrame) {
goto error;
@ -71,17 +72,17 @@ void VideoBuffer::offerDecodedFrame(bool& previousFrameSkipped)
{
m_mutex.lock();
#ifndef SKIP_FRAMES
// if SKIP_FRAMES is disabled, then the decoder must wait for the current
// frame to be consumed
while (!m_renderingFrameConsumed && !m_interrupted) {
m_renderingFrameConsumedCond.wait(&m_mutex);
}
#else
if (m_fpsCounter.isStarted() && !m_renderingFrameConsumed) {
m_fpsCounter.addSkippedFrame();
if (m_renderExpiredFrames) {
// if m_renderExpiredFrames is enable, then the decoder must wait for the current
// frame to be consumed
while (!m_renderingFrameConsumed && !m_interrupted) {
m_renderingFrameConsumedCond.wait(&m_mutex);
}
} else {
if (m_fpsCounter.isStarted() && !m_renderingFrameConsumed) {
m_fpsCounter.addSkippedFrame();
}
}
#endif
swap();
previousFrameSkipped = !m_renderingFrameConsumed;
@ -96,23 +97,23 @@ const AVFrame *VideoBuffer::consumeRenderedFrame()
if (m_fpsCounter.isStarted()) {
m_fpsCounter.addRenderedFrame();
}
#ifndef SKIP_FRAMES
// if SKIP_FRAMES is disabled, then notify the decoder the current frame is
// consumed, so that it may push a new one
m_renderingFrameConsumedCond.wakeOne();
#endif
if (m_renderExpiredFrames) {
// if m_renderExpiredFrames is enable, then notify the decoder the current frame is
// consumed, so that it may push a new one
m_renderingFrameConsumedCond.wakeOne();
}
return m_renderingframe;
}
void VideoBuffer::interrupt()
{
#ifndef SKIP_FRAMES
m_mutex.lock();
m_interrupted = true;
m_mutex.unlock();
// wake up blocking wait
m_renderingFrameConsumedCond.wakeOne();
#endif
if (m_renderExpiredFrames) {
m_mutex.lock();
m_interrupted = true;
m_mutex.unlock();
// wake up blocking wait
m_renderingFrameConsumedCond.wakeOne();
}
}
void VideoBuffer::swap()

View file

@ -15,7 +15,7 @@ public:
VideoBuffer();
virtual ~VideoBuffer();
bool init();
bool init(bool renderExpiredFrames = false);
void deInit();
void lock();
void unLock();
@ -45,10 +45,12 @@ private:
bool m_renderingFrameConsumed = true;
FpsCounter m_fpsCounter;
#ifndef SKIP_FRAMES
bool m_renderExpiredFrames = false;
QWaitCondition m_renderingFrameConsumedCond;
bool m_interrupted = true;
#endif
// interrupted is not used if expired frames are not rendered
// since offering a frame will never block
bool m_interrupted = false;
};
#endif // VIDEO_BUFFER_H

View file

@ -1,5 +1,6 @@
#include <QTimer>
#include <QMessageBox>
#include <QDir>
#include "device.h"
#include "recorder.h"
@ -11,6 +12,11 @@
#include "videoform.h"
#include "controller.h"
#include "config.h"
#include "avframeconvert.h"
extern "C"
{
#include "libavutil/imgutils.h"
}
Device::Device(DeviceParams params, QObject *parent)
: QObject(parent)
@ -24,7 +30,7 @@ Device::Device(DeviceParams params, QObject *parent)
if (params.display) {
m_vb = new VideoBuffer();
m_vb->init();
m_vb->init(params.renderExpiredFrames);
m_decoder = new Decoder(m_vb, this);
m_fileHandler = new FileHandler(this);
m_controller = new Controller(params.gameScript, this);
@ -97,10 +103,16 @@ void Device::updateScript(QString script)
}
}
void Device::onScreenshot()
{
m_screenshot = true;
}
void Device::initSignals()
{
if (m_controller && m_videoForm) {
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor);
connect(m_videoForm, &VideoForm::screenshot, this, &Device::onScreenshot);
}
if (m_videoForm) {
connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){
@ -120,7 +132,7 @@ void Device::initSignals()
QMessageBox::warning(m_videoForm, "QtScrcpy", tr("wait current %1 to complete").arg(tips), QMessageBox::Ok);
}
if (FileHandler::FAR_SUCCESS_EXEC == processResult && m_videoForm) {
QMessageBox::information(m_videoForm, "QtScrcpy", tr("%1 complete, save in %2").arg(tips).arg(m_fileHandler->getDevicePath()), QMessageBox::Ok);
QMessageBox::information(m_videoForm, "QtScrcpy", tr("%1 complete, save in %2").arg(tips).arg(Config::getInstance().getPushFilePath()), QMessageBox::Ok);
}
if (FileHandler::FAR_ERROR_EXEC == processResult && m_videoForm) {
QMessageBox::information(m_videoForm, "QtScrcpy", tr("%1 failed").arg(tips), QMessageBox::Ok);
@ -138,7 +150,7 @@ void Device::initSignals()
});
connect(m_server, &Server::connectToResult, this, [this](bool success, const QString &deviceName, const QSize &size){
if (success) {
float diff = m_startTimeCount.elapsed() / 1000.0f;
double diff = m_startTimeCount.elapsed() / 1000.0;
qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str());
// update ui
@ -189,6 +201,12 @@ void Device::initSignals()
if (m_videoForm) {
m_videoForm->updateRender(frame);
}
// screenshot
if (m_screenshot) {
saveFrame(frame);
m_screenshot = false;
}
m_vb->unLock();
},Qt::QueuedConnection);
}
@ -216,3 +234,56 @@ void Device::startServer()
m_server->start(params);
});
}
bool Device::saveFrame(const AVFrame* frame)
{
if (!frame) {
return false;
}
// create buffer
QImage rgbImage(frame->width, frame->height, QImage::Format_RGB32);
AVFrame* rgbFrame = av_frame_alloc();
if (!rgbFrame) {
return false;
}
// bind buffer to AVFrame
av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, rgbImage.bits(), AV_PIX_FMT_RGB32, frame->width, frame->height, 4);
// convert
AVFrameConvert convert;
convert.setSrcFrameInfo(frame->width, frame->height, AV_PIX_FMT_YUV420P);
convert.setDstFrameInfo(frame->width, frame->height, AV_PIX_FMT_RGB32);
bool ret = false;
ret = convert.init();
if (!ret) {
return false;
}
ret = convert.convert(frame, rgbFrame);
if (!ret) {
return false;
}
convert.deInit();
av_free(rgbFrame);
// save
QString absFilePath;
QString fileDir(Config::getInstance().getRecordPath());
if (fileDir.isEmpty()) {
qWarning() << "please select record save path!!!";
return false;
}
QDateTime dateTime = QDateTime::currentDateTime();
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
fileName = Config::getInstance().getTitle() + fileName + ".jpg";
QDir dir(fileDir);
absFilePath = dir.absoluteFilePath(fileName);
ret = rgbImage.save(absFilePath);
if (!ret) {
return false;
}
qInfo() << "screenshot save to " << absFilePath;
return true;
}

View file

@ -12,21 +12,23 @@ class FileHandler;
class Stream;
class VideoForm;
class Controller;
struct AVFrame;
class Device : public QObject
{
Q_OBJECT
public:
struct DeviceParams {
QString recordFileName = ""; // 视频录制文件名
QString serial = ""; // 设备序列号
quint16 localPort = 27183; // reverse时本地监听端口
quint16 maxSize = 720; // 视频分辨率
quint32 bitRate = 8000000; // 视频比特率
quint32 maxFps = 60; // 视频最大帧率
bool closeScreen = false; // 启动时自动息屏
bool useReverse = true; // true:先使用adb reverse失败后自动使用adb forwardfalse:直接使用adb forward
bool display = true; // 是否显示画面(或者仅仅后台录制)
QString gameScript = ""; // 游戏映射脚本
QString recordFileName = ""; // 视频录制文件名
QString serial = ""; // 设备序列号
quint16 localPort = 27183; // reverse时本地监听端口
quint16 maxSize = 720; // 视频分辨率
quint32 bitRate = 8000000; // 视频比特率
quint32 maxFps = 60; // 视频最大帧率
bool closeScreen = false; // 启动时自动息屏
bool useReverse = true; // true:先使用adb reverse失败后自动使用adb forwardfalse:直接使用adb forward
bool display = true; // 是否显示画面(或者仅仅后台录制)
QString gameScript = ""; // 游戏映射脚本
bool renderExpiredFrames = false; // 是否渲染延迟视频帧
};
explicit Device(DeviceParams params, QObject *parent = nullptr);
virtual ~Device();
@ -40,9 +42,13 @@ public:
signals:
void deviceDisconnect(QString serial);
public slots:
void onScreenshot();
private:
void initSignals();
void startServer();
bool saveFrame(const AVFrame* frame);
private:
// server relevant
@ -59,6 +65,8 @@ private:
QTime m_startTimeCount;
DeviceParams m_params;
bool m_screenshot = false;
};
#endif // DEVICE_H

View file

@ -1,7 +1,5 @@
#include "filehandler.h"
#define DEVICE_SDCARD_PATH "/sdcard/"
FileHandler::FileHandler(QObject *parent)
: QObject (parent)
{
@ -32,12 +30,9 @@ void FileHandler::pushFileRequest(const QString &serial, const QString &file, co
emit fileHandlerResult(FAR_IS_RUNNING, false);
return;
}
m_devicePath = devicePath;
if (m_devicePath.isEmpty()) {
m_devicePath = DEVICE_SDCARD_PATH;
}
m_isApk = false;
m_adb.push(serial, file, m_devicePath);
m_adb.push(serial, file, devicePath);
}
void FileHandler::installApkRequest(const QString &serial, const QString &apkFile)
@ -46,12 +41,6 @@ void FileHandler::installApkRequest(const QString &serial, const QString &apkFil
emit fileHandlerResult(FAR_IS_RUNNING, true);
return;
}
m_devicePath = "";
m_isApk = true;
m_adb.install(serial, apkFile);
}
const QString &FileHandler::getDevicePath()
{
return m_devicePath;
}

View file

@ -8,7 +8,6 @@
#include "server.h"
#include "config.h"
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
#define DEVICE_NAME_FIELD_LENGTH 64
#define SOCKET_NAME "scrcpy"
#define MAX_CONNECT_COUNT 30
@ -68,7 +67,7 @@ bool Server::pushServer()
if (m_workProcess.isRuning()) {
m_workProcess.kill();
}
m_workProcess.push(m_params.serial, getServerPath(), DEVICE_SERVER_PATH);
m_workProcess.push(m_params.serial, getServerPath(), Config::getInstance().getServerPath());
return true;
}
@ -126,7 +125,7 @@ bool Server::execute()
}
QStringList args;
args << "shell";
args << QString("CLASSPATH=%1").arg(DEVICE_SERVER_PATH);
args << QString("CLASSPATH=%1").arg(Config::getInstance().getServerPath());
args << "app_process";
args << "/"; // unused;
args << "com.genymobile.scrcpy.Server";

View file

@ -82,8 +82,8 @@ private:
QPointer<QTcpSocket> m_controlSocket = Q_NULLPTR;
bool m_tunnelEnabled = false;
bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse"
quint32 m_acceptTimeoutTimer = 0;
quint32 m_connectTimeoutTimer = 0;
int m_acceptTimeoutTimer = 0;
int m_connectTimeoutTimer = 0;
quint32 m_connectCount = 0;
quint32 m_restartCount = 0;
QString m_deviceName = "";

View file

@ -20,9 +20,6 @@ ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
initStyle();
// TODO
ui->screenShotBtn->hide();
}
ToolForm::~ToolForm()
@ -69,11 +66,13 @@ void ToolForm::mouseMoveEvent(QMouseEvent *event)
void ToolForm::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
qDebug() << "show event";
}
void ToolForm::hideEvent(QHideEvent *event)
{
Q_UNUSED(event)
qDebug() << "hide event";
}
@ -121,7 +120,7 @@ void ToolForm::on_powerBtn_clicked()
void ToolForm::on_screenShotBtn_clicked()
{
// TODO
emit screenshot();
}
void ToolForm::on_volumeUpBtn_clicked()

View file

@ -27,6 +27,9 @@ protected:
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
signals:
void screenshot();
private slots:
void on_fullScreenBtn_clicked();

View file

@ -16,6 +16,7 @@
#include "toolform.h"
#include "controller.h"
#include "filehandler.h"
#include "config.h"
extern "C"
{
#include "libavutil/frame.h"
@ -92,6 +93,8 @@ void VideoForm::showToolForm(bool show)
if (!m_toolForm) {
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT);
m_toolForm->move(pos().x() + geometry().width(), pos().y() + 30);
connect(m_toolForm, &ToolForm::screenshot, this, &VideoForm::screenshot);
}
m_toolForm->setVisible(show);
}
@ -349,7 +352,6 @@ void VideoForm::keyPressEvent(QKeyEvent *event)
return;
}
//qDebug() << "keyPressEvent" << event->isAutoRepeat();
m_controller->keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size());
}
@ -358,7 +360,6 @@ void VideoForm::keyReleaseEvent(QKeyEvent *event)
if (!m_controller) {
return;
}
//qDebug() << "keyReleaseEvent" << event->isAutoRepeat();
m_controller->keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size());
}
@ -412,5 +413,5 @@ void VideoForm::dropEvent(QDropEvent *event)
m_fileHandler->installApkRequest(m_serial, file);
return;
}
m_fileHandler->pushFileRequest(m_serial, file);
m_fileHandler->pushFileRequest(m_serial, file, Config::getInstance().getPushFilePath() + fileInfo.fileName());
}

View file

@ -29,6 +29,9 @@ public:
void setFileHandler(FileHandler *fileHandler);
void setSerial(const QString &serial);
signals:
void screenshot();
public slots:
void onGrabCursor(bool grab);

View file

@ -49,6 +49,10 @@ bool DeviceManage::connectDevice(Device::DeviceParams params)
void DeviceManage::updateScript(QString script)
{
if (m_devices.isEmpty()) {
qWarning() << "no device connect!!!";
return;
}
QMapIterator<QString, QPointer<Device>> i(m_devices);
while (i.hasNext()) {
i.next();

View file

@ -3,6 +3,7 @@
#include <QKeyEvent>
#include <QFileDialog>
#include <QTimer>
#include <QDebug>
#include "dialog.h"
#include "ui_dialog.h"
@ -46,14 +47,18 @@ Dialog::Dialog(QWidget *parent) :
}
} else if (args.contains("show") && args.contains("wlan0")) {
QString ip = m_adb.getDeviceIPFromStdOut();
if (!ip.isEmpty()) {
ui->deviceIpEdt->setText(ip);
if (ip.isEmpty()) {
log = "ip not find, connect to wifi?";
break;
}
ui->deviceIpEdt->setText(ip);
} else if (args.contains("ifconfig") && args.contains("wlan0")) {
QString ip = m_adb.getDeviceIPFromStdOut();
if (!ip.isEmpty()) {
ui->deviceIpEdt->setText(ip);
if (ip.isEmpty()) {
log = "ip not find, connect to wifi?";
break;
}
ui->deviceIpEdt->setText(ip);
}
break;
}
@ -91,11 +96,6 @@ void Dialog::initUI()
ui->formatBox->addItem("mp4");
ui->formatBox->addItem("mkv");
#ifndef Q_OS_WIN32
// game only windows
ui->gameCheck->setEnabled(false);
#endif
ui->recordPathEdt->setText(Config::getInstance().getRecordPath());
}
@ -137,14 +137,16 @@ void Dialog::on_startServerBtn_clicked()
outLog("start server...", false);
QString absFilePath;
QString fileDir(ui->recordPathEdt->text().trimmed());
if (!fileDir.isEmpty()) {
QDateTime dateTime = QDateTime::currentDateTime();
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
QString ext = ui->formatBox->currentText().trimmed();
fileName = windowTitle() + fileName + "." + ext;
QDir dir(fileDir);
absFilePath = dir.absoluteFilePath(fileName);
if (ui->recordScreenCheck->isChecked()) {
QString fileDir(ui->recordPathEdt->text().trimmed());
if (!fileDir.isEmpty()) {
QDateTime dateTime = QDateTime::currentDateTime();
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
QString ext = ui->formatBox->currentText().trimmed();
fileName = windowTitle() + fileName + "." + ext;
QDir dir(fileDir);
absFilePath = dir.absoluteFilePath(fileName);
}
}
quint32 bitRate = ui->bitRateBox->currentText().trimmed().toUInt();
@ -155,18 +157,13 @@ void Dialog::on_startServerBtn_clicked()
params.maxSize = videoSize;
params.bitRate = bitRate;
// on devices with Android >= 10, the capture frame rate can be limited
params.maxFps = Config::getInstance().getMaxFps();
params.maxFps = static_cast<quint32>(Config::getInstance().getMaxFps());
params.recordFileName = absFilePath;
params.closeScreen = ui->closeScreenCheck->isChecked();
params.useReverse = ui->useReverseCheck->isChecked();
params.display = !ui->notDisplayCheck->isChecked();
if (ui->gameCheck->isChecked()) {
if (ui->gameBox->currentText().isEmpty()) {
outLog("no keymap script selected", true);
} else {
params.gameScript = getGameScript(ui->gameBox->currentText());
}
}
params.renderExpiredFrames = Config::getInstance().getRenderExpiredFrames();
m_deviceManage.connectDevice(params);
/*
@ -232,6 +229,17 @@ void Dialog::outLog(const QString &log, bool newLine)
});
}
bool Dialog::filterLog(const QString &log)
{
if (log.contains("app_proces")) {
return true;
}
if (log.contains("Unable to set geometry")) {
return true;
}
return false;
}
bool Dialog::checkAdbRun()
{
if (m_adb.isRuning()) {
@ -340,9 +348,15 @@ void Dialog::on_applyScriptBtn_clicked()
m_deviceManage.updateScript(getGameScript(ui->gameBox->currentText()));
}
void Dialog::on_gameCheck_clicked(bool checked)
void Dialog::on_recordScreenCheck_clicked(bool checked)
{
if (checked) {
on_refreshGameScriptBtn_clicked();
if (!checked) {
return;
}
QString fileDir(ui->recordPathEdt->text().trimmed());
if (fileDir.isEmpty()) {
qWarning() << "please select record save path!!!";
ui->recordScreenCheck->setChecked(false);
}
}

View file

@ -21,6 +21,7 @@ public:
~Dialog();
void outLog(const QString& log, bool newLine = true);
bool filterLog(const QString & log);
private slots:
void on_updateDevice_clicked();
@ -50,8 +51,10 @@ private slots:
void on_stopAllServerBtn_clicked();
void on_refreshGameScriptBtn_clicked();
void on_applyScriptBtn_clicked();
void on_gameCheck_clicked(bool checked);
void on_recordScreenCheck_clicked(bool checked);
private:
bool checkAdbRun();

View file

@ -6,119 +6,431 @@
<rect>
<x>0</x>
<y>0</y>
<width>513</width>
<height>495</height>
<width>420</width>
<height>471</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>600</width>
<height>2160</height>
<width>420</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">QtScrcpy</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QGroupBox" name="usbGroupBox">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="configGroupBox">
<property name="title">
<string>USB line</string>
<string>Start Config</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="serialBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>device serial:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QWidget" name="configWidget1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>bit rate:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="bitRateBox">
<property name="toolTip">
<string/>
</property>
<property name="currentText">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>max size:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="maxSizeBox">
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>record format</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="formatBox"/>
</item>
</layout>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="getIPBtn">
<property name="text">
<string>get device IP</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<item>
<widget class="QWidget" name="configWidget2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>record save path:</string>
</property>
<property name="buddy">
<cstring>recordPathEdt</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="recordPathEdt">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="selectRecordPathBtn">
<property name="text">
<string>select path</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="updateDevice">
<property name="text">
<string>refresh devices</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<item>
<widget class="QWidget" name="configWidget4" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="gameBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refreshGameScriptBtn">
<property name="text">
<string>refresh script</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyScriptBtn">
<property name="text">
<string>apply</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="startServerBtn">
<property name="text">
<string>start server</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="stopAllServerBtn">
<property name="text">
<string>stop all server</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="stopServerBtn">
<property name="text">
<string>stop server</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="startAdbdBtn">
<property name="text">
<string>start adbd</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<item>
<widget class="QWidget" name="configWidget3" native="true">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="recordScreenCheck">
<property name="text">
<string>record screen</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="closeScreenCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>screen-off</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="notDisplayCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>background record</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="useReverseCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>reverse connection</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="alwaysTopCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>always on top</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<item>
<widget class="QGroupBox" name="usbGroupBox">
<property name="title">
<string>USB line</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QWidget" name="usbWidget1" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>device serial:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="serialBox"/>
</item>
<item>
<widget class="QPushButton" name="startServerBtn">
<property name="text">
<string>start server</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopServerBtn">
<property name="text">
<string>stop server</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="usbWidget2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="stopAllServerBtn">
<property name="text">
<string>stop all server</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="updateDevice">
<property name="text">
<string>refresh devices</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="getIPBtn">
<property name="text">
<string>get device IP</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="startAdbdBtn">
<property name="text">
<string>start adbd</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="wirelessGroupBox">
<property name="title">
<string>Wireless</string>
</property>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="2,0,0,1,2,0">
<item row="4" column="4">
<widget class="QPushButton" name="wirelessConnectBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>wireless connect</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QLineEdit" name="deviceIpEdt">
<property name="text">
<string/>
@ -131,7 +443,7 @@
</property>
</widget>
</item>
<item row="4" column="2">
<item>
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
@ -150,8 +462,20 @@
</property>
</widget>
</item>
<item row="4" column="3">
<item>
<widget class="QLineEdit" name="devicePortEdt">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
@ -163,10 +487,26 @@
</property>
</widget>
</item>
<item row="4" column="5">
<item>
<widget class="QPushButton" name="wirelessConnectBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>wireless connect</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="wirelessDisConnectBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -182,7 +522,87 @@
</layout>
</widget>
</item>
<item row="5" column="0">
<item>
<widget class="QGroupBox" name="adbGroupBox">
<property name="title">
<string notr="true">adb</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>adb command:</string>
</property>
<property name="buddy">
<cstring>adbCommandEdt</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="adbCommandEdt">
<property name="text">
<string notr="true">devices</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="adbCommandBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>execute</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopAdbBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>terminate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearOut">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>clear</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTextEdit" name="outEdit">
<property name="minimumSize">
<size>
@ -201,232 +621,10 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="adbGroupBox">
<property name="title">
<string notr="true">adb</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>adb command:</string>
</property>
<property name="buddy">
<cstring>adbCommandEdt</cstring>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="stopAdbBtn">
<property name="text">
<string>terminate</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="adbCommandBtn">
<property name="text">
<string>execute</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="adbCommandEdt">
<property name="text">
<string notr="true">devices</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="clearOut">
<property name="text">
<string>clear</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="configGroupBox">
<property name="title">
<string>Start Config</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>bit rate:</string>
</property>
</widget>
</item>
<item row="0" column="9" colspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>record format</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>record save path:</string>
</property>
<property name="buddy">
<cstring>recordPathEdt</cstring>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="QComboBox" name="formatBox"/>
</item>
<item row="3" column="6" colspan="2">
<widget class="QPushButton" name="refreshGameScriptBtn">
<property name="text">
<string>refresh script</string>
</property>
</widget>
</item>
<item row="2" column="9" colspan="3">
<widget class="QCheckBox" name="useReverseCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>reverse connection</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="10" colspan="2">
<widget class="QCheckBox" name="gameCheck">
<property name="text">
<string>auto enable</string>
</property>
</widget>
</item>
<item row="2" column="3" colspan="2">
<widget class="QCheckBox" name="alwaysTopCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>always on top</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="notDisplayCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>background record</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="6" colspan="3">
<widget class="QCheckBox" name="closeScreenCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>screen-off</string>
</property>
</widget>
</item>
<item row="1" column="10" colspan="2">
<widget class="QPushButton" name="selectRecordPathBtn">
<property name="text">
<string>select path</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="6">
<widget class="QComboBox" name="gameBox"/>
</item>
<item row="1" column="3" colspan="7">
<widget class="QLineEdit" name="recordPathEdt">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QComboBox" name="bitRateBox">
<property name="toolTip">
<string/>
</property>
<property name="currentText">
<string/>
</property>
</widget>
</item>
<item row="3" column="8" colspan="2">
<widget class="QPushButton" name="applyScriptBtn">
<property name="text">
<string>apply</string>
</property>
</widget>
</item>
<item row="0" column="7" colspan="2">
<widget class="QComboBox" name="maxSizeBox">
<property name="toolTip">
<string/>
</property>
</widget>
</item>
<item row="0" column="4" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>max size:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<tabstops>
<tabstop>bitRateBox</tabstop>
<tabstop>formatBox</tabstop>
<tabstop>recordPathEdt</tabstop>
<tabstop>selectRecordPathBtn</tabstop>
<tabstop>gameBox</tabstop>
<tabstop>refreshGameScriptBtn</tabstop>
<tabstop>serialBox</tabstop>
<tabstop>startServerBtn</tabstop>
<tabstop>stopServerBtn</tabstop>
<tabstop>stopAllServerBtn</tabstop>
<tabstop>updateDevice</tabstop>
<tabstop>getIPBtn</tabstop>
<tabstop>startAdbdBtn</tabstop>
<tabstop>deviceIpEdt</tabstop>
<tabstop>devicePortEdt</tabstop>
<tabstop>wirelessConnectBtn</tabstop>

View file

@ -10,9 +10,9 @@
#include "mousetap/mousetap.h"
#include "config.h"
Dialog* g_mainDlg = Q_NULLPTR;
static Dialog* g_mainDlg = Q_NULLPTR;
QtMessageHandler g_oldMessageHandler = Q_NULLPTR;
static QtMessageHandler g_oldMessageHandler = Q_NULLPTR;
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
void installTranslator();
@ -91,6 +91,7 @@ void installTranslator() {
static QTranslator translator;
QLocale locale;
QLocale::Language language = locale.language();
//language = QLocale::English;
QString languagePath = ":/i18n/";
switch (language) {
case QLocale::Chinese:
@ -112,7 +113,7 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
}
if (QtDebugMsg < type) {
if (g_mainDlg && g_mainDlg->isVisible() && !msg.contains("app_proces")) {
if (g_mainDlg && g_mainDlg->isVisible() && !g_mainDlg->filterLog(msg)) {
g_mainDlg->outLog(msg);
}
}

Binary file not shown.

View file

@ -16,22 +16,22 @@
<translation type="vanished">file transfer failed</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="115"/>
<location filename="../../device/device.cpp" line="127"/>
<source>install apk</source>
<translation>install apk</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="117"/>
<location filename="../../device/device.cpp" line="129"/>
<source>file transfer</source>
<translation>file transfer</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="120"/>
<location filename="../../device/device.cpp" line="132"/>
<source>wait current %1 to complete</source>
<translation>wait current %1 to complete</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="123"/>
<location filename="../../device/device.cpp" line="135"/>
<source>%1 complete, save in %2</source>
<translation>%1 complete, save in %2</translation>
</message>
@ -41,7 +41,7 @@
<translation type="vanished">%1 complete\n save in %2</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="126"/>
<location filename="../../device/device.cpp" line="138"/>
<source>%1 failed</source>
<translation>%1 failed</translation>
</message>
@ -49,128 +49,132 @@
<context>
<name>Dialog</name>
<message>
<location filename="../../dialog.ui" line="102"/>
<location filename="../../dialog.ui" line="415"/>
<source>Wireless</source>
<translation>Wireless</translation>
</message>
<message>
<location filename="../../dialog.ui" line="114"/>
<location filename="../../dialog.ui" line="499"/>
<source>wireless connect</source>
<translation>wireless connect</translation>
</message>
<message>
<location filename="../../dialog.ui" line="175"/>
<location filename="../../dialog.ui" line="515"/>
<source>wireless disconnect</source>
<translation>wireless disconnect</translation>
</message>
<message>
<location filename="../../dialog.ui" line="254"/>
<location filename="../../dialog.ui" line="32"/>
<source>Start Config</source>
<translation>Start Config</translation>
</message>
<message>
<location filename="../../dialog.ui" line="274"/>
<location filename="../../dialog.ui" line="127"/>
<source>record save path:</source>
<translation>record save path:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="362"/>
<location filename="../../dialog.cpp" line="287"/>
<location filename="../../dialog.ui" line="144"/>
<location filename="../../dialog.cpp" line="294"/>
<source>select path</source>
<translation>select path</translation>
</message>
<message>
<location filename="../../dialog.ui" line="267"/>
<location filename="../../dialog.ui" line="99"/>
<source>record format</source>
<translation>record format:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="72"/>
<location filename="../../dialog.ui" line="214"/>
<source>record screen</source>
<translation>record screen</translation>
</message>
<message>
<location filename="../../dialog.ui" line="372"/>
<source>stop all server</source>
<translation>stop all server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="213"/>
<location filename="../../dialog.ui" line="549"/>
<source>adb command:</source>
<translation>adb command:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="223"/>
<location filename="../../dialog.ui" line="585"/>
<source>terminate</source>
<translation>terminate</translation>
</message>
<message>
<location filename="../../dialog.ui" line="230"/>
<location filename="../../dialog.ui" line="572"/>
<source>execute</source>
<translation>execute</translation>
</message>
<message>
<location filename="../../dialog.ui" line="244"/>
<location filename="../../dialog.ui" line="598"/>
<source>clear</source>
<translation>clear</translation>
</message>
<message>
<location filename="../../dialog.ui" line="300"/>
<location filename="../../dialog.ui" line="256"/>
<source>reverse connection</source>
<translation>reverse connection</translation>
</message>
<message>
<location filename="../../dialog.ui" line="310"/>
<source>auto enable</source>
<translation>auto enable</translation>
<translation type="vanished">auto enable</translation>
</message>
<message>
<location filename="../../dialog.ui" line="339"/>
<location filename="../../dialog.ui" line="240"/>
<source>background record</source>
<translation>background record</translation>
</message>
<message>
<location filename="../../dialog.ui" line="355"/>
<location filename="../../dialog.ui" line="227"/>
<source>screen-off</source>
<translation>screen-off</translation>
</message>
<message>
<location filename="../../dialog.ui" line="392"/>
<location filename="../../dialog.ui" line="189"/>
<source>apply</source>
<translation>apply</translation>
</message>
<message>
<location filename="../../dialog.ui" line="406"/>
<location filename="../../dialog.ui" line="85"/>
<source>max size:</source>
<translation>max size:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="323"/>
<location filename="../../dialog.ui" line="272"/>
<source>always on top</source>
<translation>always on top</translation>
</message>
<message>
<location filename="../../dialog.ui" line="287"/>
<location filename="../../dialog.ui" line="182"/>
<source>refresh script</source>
<translation>refresh script</translation>
</message>
<message>
<location filename="../../dialog.ui" line="42"/>
<location filename="../../dialog.ui" line="389"/>
<source>get device IP</source>
<translation>get device IP</translation>
</message>
<message>
<location filename="../../dialog.ui" line="26"/>
<location filename="../../dialog.ui" line="288"/>
<source>USB line</source>
<translation>USB line</translation>
</message>
<message>
<location filename="../../dialog.ui" line="79"/>
<location filename="../../dialog.ui" line="344"/>
<source>stop server</source>
<translation>stop server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="62"/>
<location filename="../../dialog.ui" line="334"/>
<source>start server</source>
<translation>start server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="35"/>
<location filename="../../dialog.ui" line="324"/>
<source>device serial:</source>
<translation>device serial:</translation>
</message>
@ -179,17 +183,17 @@
<translation type="vanished">Config</translation>
</message>
<message>
<location filename="../../dialog.ui" line="260"/>
<location filename="../../dialog.ui" line="68"/>
<source>bit rate:</source>
<translation>bit rate:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="89"/>
<location filename="../../dialog.ui" line="399"/>
<source>start adbd</source>
<translation>start adbd</translation>
</message>
<message>
<location filename="../../dialog.ui" line="52"/>
<location filename="../../dialog.ui" line="379"/>
<source>refresh devices</source>
<translation>refresh devices</translation>
</message>
@ -280,7 +284,7 @@
<translation type="vanished">file transfer failed</translation>
</message>
<message>
<location filename="../../device/ui/videoform.cpp" line="407"/>
<location filename="../../device/ui/videoform.cpp" line="408"/>
<source>file does not exist</source>
<translation>file does not exist</translation>
</message>

Binary file not shown.

View file

@ -16,22 +16,22 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../device/device.cpp" line="115"/>
<location filename="../../device/device.cpp" line="127"/>
<source>install apk</source>
<translation>apk</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="117"/>
<location filename="../../device/device.cpp" line="129"/>
<source>file transfer</source>
<translation></translation>
</message>
<message>
<location filename="../../device/device.cpp" line="120"/>
<location filename="../../device/device.cpp" line="132"/>
<source>wait current %1 to complete</source>
<translation>%1</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="123"/>
<location filename="../../device/device.cpp" line="135"/>
<source>%1 complete, save in %2</source>
<translation>%1,%2</translation>
</message>
@ -41,7 +41,7 @@
<translation type="vanished">%1\n %2</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="126"/>
<location filename="../../device/device.cpp" line="138"/>
<source>%1 failed</source>
<translation>%1 </translation>
</message>
@ -49,128 +49,132 @@
<context>
<name>Dialog</name>
<message>
<location filename="../../dialog.ui" line="102"/>
<location filename="../../dialog.ui" line="415"/>
<source>Wireless</source>
<translation>线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="114"/>
<location filename="../../dialog.ui" line="499"/>
<source>wireless connect</source>
<translation>线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="175"/>
<location filename="../../dialog.ui" line="515"/>
<source>wireless disconnect</source>
<translation>线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="254"/>
<location filename="../../dialog.ui" line="32"/>
<source>Start Config</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="274"/>
<location filename="../../dialog.ui" line="127"/>
<source>record save path:</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="362"/>
<location filename="../../dialog.cpp" line="287"/>
<location filename="../../dialog.ui" line="144"/>
<location filename="../../dialog.cpp" line="294"/>
<source>select path</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="267"/>
<location filename="../../dialog.ui" line="99"/>
<source>record format</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="72"/>
<location filename="../../dialog.ui" line="214"/>
<source>record screen</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="372"/>
<source>stop all server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="213"/>
<location filename="../../dialog.ui" line="549"/>
<source>adb command:</source>
<translation>adb命令</translation>
</message>
<message>
<location filename="../../dialog.ui" line="223"/>
<location filename="../../dialog.ui" line="585"/>
<source>terminate</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="230"/>
<location filename="../../dialog.ui" line="572"/>
<source>execute</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="244"/>
<location filename="../../dialog.ui" line="598"/>
<source>clear</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="300"/>
<location filename="../../dialog.ui" line="256"/>
<source>reverse connection</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="310"/>
<source>auto enable</source>
<translation></translation>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../dialog.ui" line="339"/>
<location filename="../../dialog.ui" line="240"/>
<source>background record</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="355"/>
<location filename="../../dialog.ui" line="227"/>
<source>screen-off</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="392"/>
<location filename="../../dialog.ui" line="189"/>
<source>apply</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="406"/>
<location filename="../../dialog.ui" line="85"/>
<source>max size:</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="323"/>
<location filename="../../dialog.ui" line="272"/>
<source>always on top</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="287"/>
<location filename="../../dialog.ui" line="182"/>
<source>refresh script</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="42"/>
<location filename="../../dialog.ui" line="389"/>
<source>get device IP</source>
<translation>IP</translation>
</message>
<message>
<location filename="../../dialog.ui" line="26"/>
<location filename="../../dialog.ui" line="288"/>
<source>USB line</source>
<translation>USB线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="79"/>
<location filename="../../dialog.ui" line="344"/>
<source>stop server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="62"/>
<location filename="../../dialog.ui" line="334"/>
<source>start server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="35"/>
<location filename="../../dialog.ui" line="324"/>
<source>device serial:</source>
<translation></translation>
</message>
@ -179,17 +183,17 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../dialog.ui" line="260"/>
<location filename="../../dialog.ui" line="68"/>
<source>bit rate:</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="89"/>
<location filename="../../dialog.ui" line="399"/>
<source>start adbd</source>
<translation>adbd</translation>
</message>
<message>
<location filename="../../dialog.ui" line="52"/>
<location filename="../../dialog.ui" line="379"/>
<source>refresh devices</source>
<translation></translation>
</message>
@ -280,7 +284,7 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../device/ui/videoform.cpp" line="407"/>
<location filename="../../device/ui/videoform.cpp" line="408"/>
<source>file does not exist</source>
<translation></translation>
</message>

View file

@ -12,9 +12,15 @@
#define COMMON_RECORD_KEY "RecordPath"
#define COMMON_RECORD_DEF ""
#define COMMON_PUSHFILE_KEY "PushFilePath"
#define COMMON_PUSHFILE_DEF "/sdcard/"
#define COMMON_SERVER_VERSION_KEY "ServerVersion"
#define COMMON_SERVER_VERSION_DEF "1.12.1"
#define COMMON_SERVER_PATH_KEY "ServerPath"
#define COMMON_SERVER_PATH_DEF "/data/local/tmp/scrcpy-server.jar"
#define COMMON_MAX_FPS_KEY "MaxFps"
#define COMMON_MAX_FPS_DEF 60
@ -24,6 +30,9 @@
#define COMMON_SKIN_KEY "UseSkin"
#define COMMON_SKIN_DEF 1
#define COMMON_RENDER_EXPIRED_FRAMES_KEY "RenderExpiredFrames"
#define COMMON_RENDER_EXPIRED_FRAMES_DEF 0
QString Config::s_configPath = "";
Config::Config(QObject *parent) : QObject(parent)
@ -102,6 +111,33 @@ int Config::getSkin()
return skin;
}
int Config::getRenderExpiredFrames()
{
int renderExpiredFrames = 1;
m_settings->beginGroup(GROUP_COMMON);
renderExpiredFrames = m_settings->value(COMMON_RENDER_EXPIRED_FRAMES_KEY, COMMON_RENDER_EXPIRED_FRAMES_DEF).toInt();
m_settings->endGroup();
return renderExpiredFrames;
}
QString Config::getPushFilePath()
{
QString pushFile;
m_settings->beginGroup(GROUP_COMMON);
pushFile = m_settings->value(COMMON_PUSHFILE_KEY, COMMON_PUSHFILE_DEF).toString();
m_settings->endGroup();
return pushFile;
}
QString Config::getServerPath()
{
QString serverPath;
m_settings->beginGroup(GROUP_COMMON);
serverPath = m_settings->value(COMMON_SERVER_PATH_KEY, COMMON_SERVER_PATH_DEF).toString();
m_settings->endGroup();
return serverPath;
}
QString Config::getTitle()
{
QString title;

View file

@ -17,6 +17,9 @@ public:
int getMaxFps();
int getDesktopOpenGL();
int getSkin();
int getRenderExpiredFrames();
QString getPushFilePath();
QString getServerPath();
private:
explicit Config(QObject *parent = nullptr);

View file

@ -32,7 +32,7 @@ It focuses on:
## Customized key mapping (Windows only)
You can write your own script to map keyboard and mouse actions to touches and clicks of the mobile phone according to your needs. [Here](docs/按键映射说明.md) are the rules.
A script for "PUBG mobile" mapping is provided by default. Once enabled, you can play the game with your keyboard and mouse as the PC version. You can also write your own mapping files for other games according to [writing rules](docs/按键映射说明.md). The default key mapping is as follows:
A script for "PUBG mobile" and TikTok mapping is provided by default. Once enabled, you can play the game with your keyboard and mouse as the PC version. or you can use up/down/left/right direction keys to simulate up/down/left/right sliding. You can also write your own mapping files for other games according to [writing rules](docs/按键映射说明.md). The default key mapping is as follows:
![game](screenshot/game.jpg)
@ -42,8 +42,9 @@ Here is the instruction of adding new customized mapping files.
- Write a customized script and put it in the `keymap` directory
- Click `refresh script` to check whether it can be found
- Select your script
- Connect your phone, start service and click `apply`
- Start the game and press `~` key (left side of the number key 1) to switch to the mapping mode (It can be changed in the script as `switchkey`)
- Press `~` key (left side of the number key 1) to switch to the custom mapping mode (It can be changed in the script as `switchkey`)
- Press the ~ key again to switch back to normal mode
- (For PUBG and similar games) If you want to drive cars with WASD, you need to check the `single rocker mode` in the game setting.

View file

@ -33,7 +33,7 @@ QtScrcpy可以通过USB(或通过TCP/IP)连接Android设备并进行显示和
## 自定义按键映射仅windows平台开启
可以根据需要自己编写脚本将PC键盘按键映射为手机的触摸点击编写规则在[这里](docs/按键映射说明.md)。
默认自带了针对和平精英手游进行键鼠映射的映射脚本,开启后可以用键鼠像玩端游一样玩和平精英手游,你也可以按照[编写规则](docs/按键映射说明.md)编写其他游戏的映射文件,默认按键映射如下:
默认自带了针对和平精英手游和抖音进行键鼠映射的映射脚本,开启平精英手游后可以用键鼠像玩端游一样玩和平精英手游,开启抖音映射以后可以使用上下左右方向键模拟上下左右滑动,你也可以按照[编写规则](docs/按键映射说明.md)编写其他游戏的映射文件,默认按键映射如下:
![game](screenshot/game.jpg)
@ -42,8 +42,9 @@ QtScrcpy可以通过USB(或通过TCP/IP)连接Android设备并进行显示和
自定义按键映射操作方法如下:
- 编写自定义脚本放入keymap目录
- 点击刷新脚本,确保脚本可以被检测到
- 选择需要的脚本
- 连接手机并启动服务之后,点击应用脚本
- 进入游戏场景,按~键数字键1左边切换为游戏映射模式即可体验具体按什么键要看你按键脚本定义的switchKey
- 按~键数字键1左边切换为自定义映射模式即可体验具体按什么键要看你按键脚本定义的switchKey
- 再次按~键切换为正常控制模式
- 要想wasd控制开车记得在载具设置中设置为单摇杆模式

View file

@ -1,13 +1,19 @@
[common]
# 窗口标题
WindowTitle=QtScrcpy
# 录制文件路径
# 录制文件保存路径(必须以/作为分隔符)
RecordPath=
# 推送到安卓设备的文件保存路径(必须以/结尾)
PushFilePath=/sdcard/
# 最大fps仅支持Android 10以上
MaxFps=60
# scrcpy-server的版本号不要修改
ServerVersion=1.12.1
# 是否显示手机皮肤0不显示
UseSkin=1
# 是否渲染过期视频帧(跳过过期视频帧意味着更低的延迟)
RenderExpiredFrames=0
# 视频解码方式:-1 自动0 软解1 dx硬解2 opengl硬解
UseDesktopOpenGL=-1
# scrcpy-server的版本号不要修改
ServerVersion=1.12.1
# scrcpy-server推送到安卓设备的路径
ServerPath=/data/local/tmp/scrcpy-server.jar

View file

@ -3,18 +3,16 @@
# TODO
## 低优先级
- 中文输入server需要改为apk作为一个输入法暂不实现或者有其他方式案件注入方式例如搜狗手机输入法可以监听当前注入
- [跳过帧改为动态配置,而不是静态编译](https://github.com/Genymobile/scrcpy/commit/ebccb9f6cc111e8acfbe10d656cac5c1f1b744a0)
- [单独线程统计帧率](https://github.com/Genymobile/scrcpy/commit/e2a272bf99ecf48fcb050177113f903b3fb323c4)
- text转换 https://github.com/Genymobile/scrcpy/commit/c916af0984f72a60301d13fa8ef9a85112f54202?tdsourcetag=s_pctim_aiomsg
- ui提供show touch设置
## 中优先级
- [截屏保存为jpg](https://blog.csdn.net/m0_37684310/article/details/77950390)
- 自动打包脚本
- 脚本
- 群控
- 竖屏全屏不拉伸画面
- 分辨率码率可自定义
- 软解
- opengles 3.0
## 高优先级

View file

@ -16,7 +16,7 @@
- switchKey切换自定义按键映射的开关键默认为普通映射需要使用这个按键在普通映射和自定义映射之间切换。
- mouseMoveMap鼠标移动映射鼠标的移动将被映射为以startPos为起点以鼠标移动方向为移动方向的手指拖动操作。
- mouseMoveMap鼠标移动映射鼠标的移动将被映射为以startPos为起点以鼠标移动方向为移动方向的手指拖动操作(开启鼠标移动映射以后会隐藏鼠标,限制鼠标移动范围)
一般在FPS手游中用来调整人物视野。
- startPos 手指拖动起始点
- speedRatio 鼠标移动映射为手指拖动的比例,可以控制鼠标灵敏度
@ -26,8 +26,9 @@
一般按键映射有如下几种类型:
- type 按键映射的类型每个keyMapNodes中的元素都需要指明可以是如下类型
- KMT_CLICK 普通点击,键盘按下模拟为手指按下,键盘抬起映射为手指抬起
- KMT_CLICK_TWICE 两次点击,键盘按下模拟为手指按下再抬起,键盘抬起映射为手指按下再抬起
- KMT_CLICK 普通点击,按键按下模拟为手指按下,按键抬起模拟为手指抬起
- KMT_CLICK_TWICE 两次点击,按键按下模拟为手指按下再抬起,按键抬起模拟为手指按下再抬起
- KMT_DRAG 拖拽,按键按下模拟为手指按下并拖动一段距离,按键抬起模拟为手指抬起
- KMT_STEER_WHEEL 方向盘映射专用于FPS游戏中移动人物脚步的方向盘的映射需要4个按键来配合。
不同按键映射类型的专有属性说明:
@ -41,6 +42,11 @@
- key 要映射的按键码
- pos 模拟触摸的位置
- KMT_DRAG
- key 要映射的按键码
- startPos 模拟触摸拖动的开始位置
- endPos 模拟触摸拖动的结束位置
- KMT_STEER_WHEEL
- centerPos 方向盘中心点
- leftKey 左方向的按键控制

View file

@ -7,7 +7,8 @@
},
"speedRatio": 10
},
"keyMapNodes": [{
"keyMapNodes": [
{
"comment": "方向盘",
"type": "KMT_STEER_WHEEL",
"centerPos": {

67
keymap/tiktok.json Normal file
View file

@ -0,0 +1,67 @@
{
"switchKey": "Key_QuoteLeft",
"keyMapNodes": [
{
"comment": "暂停/继续",
"type": "KMT_CLICK",
"key": "Key_Space",
"pos": {
"x": 0.5,
"y": 0.5
},
"switchMap": false
},
{
"comment": "上滑",
"type": "KMT_DRAG",
"key": "Key_Up",
"startPos": {
"x": 0.5,
"y": 0.7
},
"endPos": {
"x": 0.5,
"y": 0.3
}
},
{
"comment": "下滑",
"type": "KMT_DRAG",
"key": "Key_Down",
"startPos": {
"x": 0.5,
"y": 0.3
},
"endPos": {
"x": 0.5,
"y": 0.7
}
},
{
"comment": "左滑",
"type": "KMT_DRAG",
"key": "Key_Left",
"startPos": {
"x": 0.7,
"y": 0.5
},
"endPos": {
"x": 0.3,
"y": 0.5
}
},
{
"comment": "右滑",
"type": "KMT_DRAG",
"key": "Key_Right",
"startPos": {
"x": 0.3,
"y": 0.5
},
"endPos": {
"x": 0.7,
"y": 0.5
}
}
]
}