Compare commits

...

7 commits
v3.1.2 ... dev

Author SHA1 Message Date
Leonardo Chen
02ffb264c9 fix: windows build error
Some checks failed
Windows / Build (push) Has been cancelled
MacOS / Build (push) Has been cancelled
Ubuntu / Build (push) Has been cancelled
2025-04-10 08:42:47 +08:00
barry
314bd4f613 ui: update i18
Some checks failed
MacOS / Build (push) Has been cancelled
Ubuntu / Build (push) Has been cancelled
Windows / Build (push) Has been cancelled
2025-03-09 15:51:50 +08:00
barry
6f0f9447da feat: add for QuickAssistant 2025-03-09 15:46:12 +08:00
barry
cfe79c7d5a feat: config support set language 2025-03-09 15:40:06 +08:00
barry
dbf25166ea feat: add for QuickAssistant 2025-03-09 15:27:31 +08:00
Liu Jinchang
f5cccac0df feat: add IP history record feature
- Implement IP address history storage
- Add mechanism to record connection timestamps
- Ensure unique IP entries in history

Log: Add functionality to store and track IP address history

Issue: https://github.com/barry-ran/QtScrcpy/issues/1075
2025-03-06 14:18:13 +08:00
rankun
224f04ffa0 feat: add star badge 2025-03-04 17:21:22 +08:00
18 changed files with 243 additions and 31 deletions

View file

@ -115,9 +115,14 @@ int main(int argc, char *argv[])
"following address:");
qInfo() << QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion());
qInfo() << QObject::tr("If you need more professional screen projection control software, you can try the following software:");
qInfo() << QObject::tr("If you need more professional batch control mirror software, you can try the following software:");
qInfo() << QString(QObject::tr("QuickMirror") + " <https://lrbnfell4p.feishu.cn/drive/folder/KviYfz5uFlpUT8dXgdjccmfUnse>");
qInfo() << QObject::tr("If you need more professional game keymap mirror software, you can try the following software:");
qInfo() << QString(QObject::tr("QuickAssistant") + " <https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh>");
qInfo() << QObject::tr("You can contact me with telegram <https://t.me/+Ylf_5V_rDCMyODQ1>");
int ret = a.exec();
delete g_mainDlg;
@ -132,7 +137,13 @@ void installTranslator()
static QTranslator translator;
QLocale locale;
QLocale::Language language = locale.language();
//language = QLocale::English;
if (Config::getInstance().getLanguage() == "zh_CN") {
language = QLocale::Chinese;
} else if (Config::getInstance().getLanguage() == "en_US") {
language = QLocale::English;
}
QString languagePath = ":/i18n/";
switch (language) {
case QLocale::Chinese:

Binary file not shown.

View file

@ -31,6 +31,10 @@
<source>select path</source>
<translation>select path</translation>
</message>
<message>
<source>Clear History</source>
<translation>Clear History</translation>
</message>
</context>
<context>
<name>QObject</name>
@ -38,14 +42,26 @@
<source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source>
<translation>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</translation>
</message>
<message>
<source>If you need more professional screen projection control software, you can try the following software:</source>
<translation>If you need more professional screen projection control software, you can try the following software:</translation>
</message>
<message>
<source>QuickMirror</source>
<translation>QuickMirror</translation>
</message>
<message>
<source>If you need more professional batch control mirror software, you can try the following software:</source>
<translation>If you need more professional batch control mirror software, you can try the following software:</translation>
</message>
<message>
<source>If you need more professional game keymap mirror software, you can try the following software:</source>
<translation>If you need more professional game keymap mirror software, you can try the following software:</translation>
</message>
<message>
<source>QuickAssistant</source>
<translation>QuickAssistant</translation>
</message>
<message>
<source>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</source>
<translation>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</translation>
</message>
</context>
<context>
<name>ToolForm</name>

Binary file not shown.

View file

@ -31,6 +31,10 @@
<source>select path</source>
<translation></translation>
</message>
<message>
<source>Clear History</source>
<translation></translation>
</message>
</context>
<context>
<name>QObject</name>
@ -38,14 +42,26 @@
<source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source>
<translation>使</translation>
</message>
<message>
<source>If you need more professional screen projection control software, you can try the following software:</source>
<translation></translation>
</message>
<message>
<source>QuickMirror</source>
<translation></translation>
</message>
<message>
<source>If you need more professional batch control mirror software, you can try the following software:</source>
<translation></translation>
</message>
<message>
<source>If you need more professional game keymap mirror software, you can try the following software:</source>
<translation></translation>
</message>
<message>
<source>QuickAssistant</source>
<translation></translation>
</message>
<message>
<source>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</source>
<translation>QQ群联系我 &lt;901736468&gt;</translation>
</message>
</context>
<context>
<name>ToolForm</name>

View file

@ -82,21 +82,21 @@ Dialog::Dialog(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
log = "ip not find, connect to wifi?";
break;
}
ui->deviceIpEdt->setText(ip);
ui->deviceIpEdt->setEditText(ip);
} else if (args.contains("ifconfig") && args.contains("wlan0")) {
QString ip = m_adb.getDeviceIPFromStdOut();
if (ip.isEmpty()) {
log = "ip not find, connect to wifi?";
break;
}
ui->deviceIpEdt->setText(ip);
ui->deviceIpEdt->setEditText(ip);
} else if (args.contains("ip -o a")) {
QString ip = m_adb.getDeviceIPByIpFromStdOut();
if (ip.isEmpty()) {
log = "ip not find, connect to wifi?";
break;
}
ui->deviceIpEdt->setText(ip);
ui->deviceIpEdt->setEditText(ip);
}
break;
}
@ -164,6 +164,16 @@ void Dialog::initUI()
ui->lockOrientationBox->addItem("180");
ui->lockOrientationBox->addItem("270");
ui->lockOrientationBox->setCurrentIndex(0);
// 加载IP历史记录
loadIpHistory();
// 为deviceIpEdt添加右键菜单
if (ui->deviceIpEdt->lineEdit()) {
ui->deviceIpEdt->lineEdit()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->deviceIpEdt->lineEdit(), &QWidget::customContextMenuRequested,
this, &Dialog::showIpEditMenu);
}
}
void Dialog::updateBootConfig(bool toView)
@ -216,6 +226,12 @@ void Dialog::updateBootConfig(bool toView)
config.autoUpdateDevice = ui->autoUpdatecheckBox->isChecked();
config.showToolbar = ui->showToolbar->isChecked();
// 保存当前IP到历史记录
QString currentIp = ui->deviceIpEdt->currentText().trimmed();
if (!currentIp.isEmpty()) {
saveIpHistory(currentIp);
}
Config::getInstance().setUserBootConfig(config);
}
}
@ -344,7 +360,7 @@ void Dialog::on_wirelessConnectBtn_clicked()
if (checkAdbRun()) {
return;
}
QString addr = ui->deviceIpEdt->text().trimmed();
QString addr = ui->deviceIpEdt->currentText().trimmed();
if (!ui->devicePortEdt->text().isEmpty()) {
addr += ":";
addr += ui->devicePortEdt->text().trimmed();
@ -356,6 +372,12 @@ void Dialog::on_wirelessConnectBtn_clicked()
return;
}
// 保存IP历史记录 - 只保存IP部分,不包含端口
QString ip = addr.split(":").first();
if (!ip.isEmpty()) {
saveIpHistory(ip);
}
outLog("wireless connect...", false);
QStringList adbArgs;
adbArgs << "connect";
@ -516,7 +538,7 @@ void Dialog::on_wirelessDisConnectBtn_clicked()
if (checkAdbRun()) {
return;
}
QString addr = ui->deviceIpEdt->text().trimmed();
QString addr = ui->deviceIpEdt->currentText().trimmed();
outLog("wireless disconnect...", false);
QStringList adbArgs;
adbArgs << "disconnect";
@ -767,3 +789,45 @@ void Dialog::on_autoUpdatecheckBox_toggled(bool checked)
m_autoUpdatetimer.stop();
}
}
void Dialog::loadIpHistory()
{
QStringList ipList = Config::getInstance().getIpHistory();
ui->deviceIpEdt->clear();
ui->deviceIpEdt->addItems(ipList);
ui->deviceIpEdt->setContentsMargins(0, 0, 0, 0);
if (ui->deviceIpEdt->lineEdit()) {
ui->deviceIpEdt->lineEdit()->setMaxLength(128);
ui->deviceIpEdt->lineEdit()->setPlaceholderText("192.168.0.1");
}
}
void Dialog::saveIpHistory(const QString &ip)
{
if (ip.isEmpty()) {
return;
}
Config::getInstance().saveIpHistory(ip);
// 更新ComboBox
loadIpHistory();
ui->deviceIpEdt->setCurrentText(ip);
}
void Dialog::showIpEditMenu(const QPoint &pos)
{
QMenu *menu = ui->deviceIpEdt->lineEdit()->createStandardContextMenu();
menu->addSeparator();
QAction *clearHistoryAction = new QAction(tr("Clear History"), menu);
connect(clearHistoryAction, &QAction::triggered, this, [this]() {
Config::getInstance().clearIpHistory();
loadIpHistory();
});
menu->addAction(clearHistoryAction);
menu->exec(ui->deviceIpEdt->lineEdit()->mapToGlobal(pos));
delete menu;
}

View file

@ -67,6 +67,8 @@ private slots:
void on_autoUpdatecheckBox_toggled(bool checked);
void showIpEditMenu(const QPoint &pos);
private:
bool checkAdbRun();
void initUI();
@ -78,6 +80,8 @@ private:
int findDeviceFromeSerialBox(bool wifi);
quint32 getBitRate();
const QString &getServerPath();
void loadIpHistory();
void saveIpHistory(const QString &ip);
protected:
void closeEvent(QCloseEvent *event);

View file

@ -1059,22 +1059,25 @@
<number>5</number>
</property>
<item>
<widget class="QLineEdit" name="deviceIpEdt">
<widget class="QComboBox" name="deviceIpEdt">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/>
</property>
<property name="maxLength">
<number>128</number>
</property>
<property name="placeholderText">
<string notr="true">192.168.0.1</string>
</property>
</widget>
</item>
<item>

View file

@ -13,6 +13,10 @@
#include <QWindow>
#include <QtWidgets/QHBoxLayout>
#if defined(Q_OS_WIN32)
#include <Windows.h>
#endif
#include "config.h"
#include "iconhelper.h"
#include "qyuvopenglwidget.h"

View file

@ -11,6 +11,9 @@
#define GROUP_COMMON "common"
// config
#define COMMON_LANGUAGE_KEY "Language"
#define COMMON_LANGUAGE_DEF "Auto"
#define COMMON_TITLE_KEY "WindowTitle"
#define COMMON_TITLE_DEF QCoreApplication::applicationName()
@ -108,6 +111,11 @@
#define SERIAL_NICK_NAME_KEY "NickName"
#define SERIAL_NICK_NAME_DEF "Phone"
// IP history
#define IP_HISTORY_KEY "IpHistory"
#define IP_HISTORY_DEF ""
#define IP_HISTORY_MAX 10
QString Config::s_configPath = "";
Config::Config(QObject *parent) : QObject(parent)
@ -364,6 +372,15 @@ void Config::deleteGroup(const QString &serial)
m_userData->remove(serial);
}
QString Config::getLanguage()
{
QString language;
m_settings->beginGroup(GROUP_COMMON);
language = m_settings->value(COMMON_LANGUAGE_KEY, COMMON_LANGUAGE_DEF).toString();
m_settings->endGroup();
return language;
}
QString Config::getTitle()
{
QString title;
@ -372,3 +389,34 @@ QString Config::getTitle()
m_settings->endGroup();
return title;
}
void Config::saveIpHistory(const QString &ip)
{
QStringList ipList = getIpHistory();
// 移除已存在的相同IP避免重复
ipList.removeAll(ip);
// 将新IP添加到开头
ipList.prepend(ip);
// 限制历史记录数量
while (ipList.size() > IP_HISTORY_MAX) {
ipList.removeLast();
}
m_userData->setValue(IP_HISTORY_KEY, ipList);
m_userData->sync();
}
QStringList Config::getIpHistory()
{
QStringList ipList = m_userData->value(IP_HISTORY_KEY, IP_HISTORY_DEF).toStringList();
return ipList;
}
void Config::clearIpHistory()
{
m_userData->remove(IP_HISTORY_KEY);
m_userData->sync();
}

View file

@ -34,6 +34,7 @@ public:
static Config &getInstance();
// config
QString getLanguage();
QString getTitle();
QString getServerVersion();
int getMaxFps();
@ -62,6 +63,11 @@ public:
void deleteGroup(const QString &serial);
// IP history methods
void saveIpHistory(const QString &ip);
QStringList getIpHistory();
void clearIpHistory();
private:
explicit Config(QObject *parent = nullptr);
const QString &getConfigPath();

View file

@ -7,6 +7,7 @@
![license](https://img.shields.io/badge/license-Apache2.0-blue.svg)
![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg)
![star](https://img.shields.io/github/stars/barry-ran/QtScrcpy.svg)
[中文用户?点我查看中文介绍](README_zh.md)
@ -54,9 +55,7 @@ You can write your script to map keyboard and mouse actions to touches and click
Script for TikTok and some other games are provided by default. Once enabled, you can play the game with your keyboard and mouse. The default key mapping for PUBG Mobile is as follows:
![game](screenshot/game.jpg)
[Here is a video demonstration playing PUBG Mobile.](http://mp.weixin.qq.com/mp/video?__biz=MzU1NTg5MjYyNw==&mid=100000015&sn=3e301fdc5a364bd16d6207fa674bc8b3&vid=wxv_968792362971430913)
![game](screenshot/game.png)
Instruction for adding new customized mapping files.
@ -68,6 +67,22 @@ Instruction for adding new customized mapping files.
- Press the ~ key again to switch back to normal mode
- (For games such as PUBG Mobile) If you want to move vehicles with the STEER_WHEEL keys, you need to set the move mode to `single rocker mode`.
If you don't know how to manually write mapping rules, you can also use the `QuickAssistant` developed by the author
QuickAssistant Features&Functions:
- Play Android mobile games smoothly through keyboard and mouse
- Interface based editing of key mapping script
- Support pausing the computer screen and using only keyboard and mouse operations
- Screenshot&Recording of Mobile Screen
- Simple batch control
- Android 11+supports playing mobile audio on computers (under development...)
- Mobile app installation free
- Fast and instant connection
- Low latency: USB screen mirroring 1080p latency is within 30ms, which is lower than all screen mirroring software on the market in terms of latency at the same resolution and smoothness
- Low CPU usage: pure C++development, high-performance GPU video rendering
- High resolution: adjustable, maximum support for native resolution of Android terminals
- Telegram Grouphttps://t.me/+EnQNmb47C_liYmRl
- [QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
## Group control
You can control all your phones at the same time.

View file

@ -6,6 +6,8 @@
![license](https://img.shields.io/badge/license-Apache2.0-blue.svg)
![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg)
![star](https://img.shields.io/github/stars/barry-ran/QtScrcpy.svg)
![star](https://gitcode.com/barry-ran/QtScrcpy/star/badge.svg)
[Speaks English? Click me for English introduction.](README.md)
@ -53,9 +55,7 @@ QtScrcpy 可以通过 USB / 网络连接Android设备并进行显示和控制
默认自带了针对和平精英手游和抖音进行键鼠映射的映射脚本,开启平精英手游后可以用键鼠像玩端游一样玩和平精英手游,开启抖音映射以后可以使用上下左右方向键模拟上下左右滑动,你也可以按照[编写规则](docs/KeyMapDes_zh.md)编写其他游戏的映射文件,默认按键映射如下:
![game](screenshot/game.jpg)
[这里有玩和平精英的视频演示](http://mp.weixin.qq.com/mp/video?__biz=MzU1NTg5MjYyNw==&mid=100000015&sn=3e301fdc5a364bd16d6207fa674bc8b3&vid=wxv_968792362971430913&idx=1&vidsn=eec329cc13c3e24c187dc9b4d5eb8760&fromid=1&scene=20&xtrack=1&clicktime=1567346543&sessionid=1567346375&subscene=92&ascene=0&fasttmpl_type=0&fasttmpl_fullversion=4730859-zh_CN-zip&fasttmpl_flag=0&realreporttime=1567346543910#wechat_redirect)
![game](screenshot/game.png)
自定义按键映射操作方法如下:
- 编写自定义脚本放入 keymap 目录
@ -66,6 +66,22 @@ QtScrcpy 可以通过 USB / 网络连接Android设备并进行显示和控制
- 再次按~键切换为正常控制模式
- (对于和平精英等游戏)若想使用方向盘控制载具,记得在载具设置中设置为单摇杆模式
如果不会自己手写映射规则,也可以去使用作者开发的`极限手游助手`
极限手游助手功能&特点:
- 通过键盘鼠标畅玩安卓手机游戏
- 按键映射脚本界面化编辑
- 支持暂停电脑端画面,只使用键鼠操作
- 截图&录制手机画面
- 简单批量控制
- 安卓11+支持电脑播放手机音频(开发中...
- 手机端免安装App
- 极速秒连接
- 低延迟usb投屏1080p延迟在30ms以内在相同分辨率流畅度情况下比市面上所有投屏软件延迟都低
- cpu占用率低纯C++开发高性能GPU视频渲染
- 高分辨率:可调节,最大支持安卓终端的原生分辨率
- [QQ交流群901736468](https://qm.qq.com/q/wRJJaWLWc8)
- [极限手游助手说明文档](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
## 批量操作
你可以同时控制所有的手机

View file

@ -1,4 +1,6 @@
[common]
# 语言 Auto=自动zh_CN=简体中文en_US=English
Language=Auto
# 窗口标题
WindowTitle=QtScrcpy
# 推送到安卓设备的文件保存路径(必须以/结尾)

View file

@ -76,7 +76,11 @@ Description of the unique attributes of different key mapping types:
## Visual Key Mapping Tool
A web-based GUI tool is available to help you create and manage key mappings visually: [ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
1. Just use [QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
![game](../screenshot/game.png)
2. A web-based GUI tool is available to help you create and manage key mappings visually: [ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![ScrcpyKeyMapper Screenshot](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png)

View file

@ -75,8 +75,11 @@
- downOffset 按下下方向键后模拟拖动到相对centerPos位置水平偏下downOffset处
## 可视化按键映射工具
1. 直接使用[QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
现在有一个基于Web的GUI工具可以帮助你直观地创建和管理按键映射[ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![game](../screenshot/game.png)
2. 还有一个基于Web的GUI工具可以帮助你直观地创建和管理按键映射[ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![ScrcpyKeyMapper截图](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

BIN
screenshot/game.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 KiB