mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-22 12:34:58 +00:00
commit
a0819d8e39
17 changed files with 107 additions and 32 deletions
4
.github/workflows/macos.yml
vendored
4
.github/workflows/macos.yml
vendored
|
@ -42,7 +42,9 @@ jobs:
|
|||
- name: Build MacOS
|
||||
env:
|
||||
ENV_QT_PATH: ${{ env.qt-install-path }}
|
||||
run: ci/mac/build_for_mac.sh release
|
||||
run: |
|
||||
python ci/generate-version.py
|
||||
ci/mac/build_for_mac.sh release
|
||||
# 获取ref最后一个/后的内容
|
||||
- name: Get the version
|
||||
shell: bash
|
||||
|
|
4
.github/workflows/ubuntu.yml
vendored
4
.github/workflows/ubuntu.yml
vendored
|
@ -45,4 +45,6 @@ jobs:
|
|||
- name: Build Ubuntu
|
||||
env:
|
||||
ENV_QT_PATH: ${{ env.qt-install-path }}
|
||||
run: ci/linux/build_for_ubuntu.sh release
|
||||
run: |
|
||||
python ci/generate-version.py
|
||||
ci/linux/build_for_ubuntu.sh release
|
||||
|
|
1
.github/workflows/windows.yml
vendored
1
.github/workflows/windows.yml
vendored
|
@ -71,6 +71,7 @@ jobs:
|
|||
ENV_VCVARSALL: ${{ env.vcvarsall-path }}
|
||||
ENV_QT_PATH: ${{ env.qt-install-path }}
|
||||
run: |
|
||||
call python ci\generate-version.py
|
||||
call "ci\win\build_for_win.bat" release ${{ matrix.msvc-arch }}
|
||||
# 获取ref最后一个/后的内容
|
||||
- name: Get the version
|
||||
|
|
|
@ -26,6 +26,12 @@ msvc{
|
|||
QMAKE_CFLAGS += -source-charset:utf-8
|
||||
QMAKE_CXXFLAGS += -source-charset:utf-8
|
||||
}
|
||||
|
||||
# warning as error
|
||||
#4566 https://github.com/Chuyu-Team/VC-LTL/issues/27
|
||||
*g++*: QMAKE_CXXFLAGS += -Werror
|
||||
*msvc*: QMAKE_CXXFLAGS += /WX /wd4566
|
||||
|
||||
# 源码
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
|
@ -56,10 +62,18 @@ INCLUDEPATH += \
|
|||
$$PWD/devicemanage \
|
||||
$$PWD/fontawesome
|
||||
|
||||
# 统一版本号入口,只修改这一个地方即可
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 3
|
||||
VERSION_PATCH = 1
|
||||
# 如果变量没有定义
|
||||
# !defined(TEST_VAR, var) {
|
||||
# message("test")
|
||||
# }
|
||||
|
||||
# 从文件读取版本号
|
||||
CAT_VERSION = $$cat($$PWD/version)
|
||||
# 拆分出版本号
|
||||
VERSION_MAJOR = $$section(CAT_VERSION, ., 0, 0)
|
||||
VERSION_MINOR = $$section(CAT_VERSION, ., 1, 1)
|
||||
VERSION_PATCH = $$section(CAT_VERSION, ., 2, 2)
|
||||
message("version:" $${VERSION_MAJOR}.$${VERSION_MINOR}.$${VERSION_PATCH})
|
||||
|
||||
# qmake变量的方式定义版本号
|
||||
VERSION = $${VERSION_MAJOR}.$${VERSION_MINOR}.$${VERSION_PATCH}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QProcess>
|
||||
|
||||
#include "adbprocess.h"
|
||||
#include "config.h"
|
||||
|
||||
QString AdbProcess::s_adbPath = "";
|
||||
|
||||
|
@ -25,9 +26,14 @@ const QString &AdbProcess::getAdbPath()
|
|||
if (s_adbPath.isEmpty()) {
|
||||
s_adbPath = QString::fromLocal8Bit(qgetenv("QTSCRCPY_ADB_PATH"));
|
||||
QFileInfo fileInfo(s_adbPath);
|
||||
if (s_adbPath.isEmpty() || !fileInfo.isFile()) {
|
||||
s_adbPath = Config::getInstance().getAdbPath();
|
||||
}
|
||||
fileInfo = s_adbPath;
|
||||
if (s_adbPath.isEmpty() || !fileInfo.isFile()) {
|
||||
s_adbPath = QCoreApplication::applicationDirPath() + "/adb";
|
||||
}
|
||||
qInfo("adb path: %s", QDir(s_adbPath).absolutePath().toUtf8().data());
|
||||
}
|
||||
return s_adbPath;
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ QByteArray ControlMsg::serializeData()
|
|||
BufferUtil::write32(buffer, m_data.injectKeycode.metastate);
|
||||
break;
|
||||
case CMT_INJECT_TEXT:
|
||||
BufferUtil::write16(buffer, strlen(m_data.injectText.text));
|
||||
BufferUtil::write16(buffer, static_cast<quint32>(strlen(m_data.injectText.text)));
|
||||
buffer.write(m_data.injectText.text, strlen(m_data.injectText.text));
|
||||
break;
|
||||
case CMT_INJECT_TOUCH: {
|
||||
|
@ -124,7 +124,7 @@ QByteArray ControlMsg::serializeData()
|
|||
BufferUtil::write32(buffer, m_data.injectScroll.vScroll);
|
||||
break;
|
||||
case CMT_SET_CLIPBOARD:
|
||||
BufferUtil::write16(buffer, strlen(m_data.setClipboard.text));
|
||||
BufferUtil::write16(buffer, static_cast<quint32>(strlen(m_data.setClipboard.text)));
|
||||
buffer.write(m_data.setClipboard.text, strlen(m_data.setClipboard.text));
|
||||
break;
|
||||
case CMT_SET_SCREEN_POWER_MODE:
|
||||
|
|
|
@ -29,7 +29,6 @@ static const GLfloat coordinate[] = {
|
|||
|
||||
// 纹理坐标,存储4个xy坐标
|
||||
// 坐标范围为[0,1],左下角为 0,0
|
||||
// TODO 为什么这个顺序指定四个顶点?顶点坐标和纹理坐标如何映射的?
|
||||
0.0f,
|
||||
1.0f,
|
||||
1.0f,
|
||||
|
@ -62,15 +61,21 @@ static QString s_fragShader = R"(
|
|||
{
|
||||
vec3 yuv;
|
||||
vec3 rgb;
|
||||
// SDL2-2.0.10\src\render\opengl\SDL_shaders_gl.c BT709_SHADER_CONSTANTS
|
||||
|
||||
// SDL2 BT709_SHADER_CONSTANTS
|
||||
// https://github.com/spurious/SDL-mirror/blob/4ddd4c445aa059bb127e101b74a8c5b59257fbe2/src/render/opengl/SDL_shaders_gl.c#L102
|
||||
const vec3 Rcoeff = vec3(1.1644, 0.000, 1.7927);
|
||||
const vec3 Gcoeff = vec3(1.1644, -0.2132, -0.5329);
|
||||
const vec3 Bcoeff = vec3(1.1644, 2.1124, 0.000);
|
||||
|
||||
// 根据指定的纹理textureY和坐标textureOut来采样
|
||||
yuv.x = texture2D(textureY, textureOut).r;
|
||||
yuv.y = texture2D(textureU, textureOut).r - 0.5;
|
||||
yuv.z = texture2D(textureV, textureOut).r - 0.5;
|
||||
|
||||
// 采样完转为rgb
|
||||
// 减少一些亮度
|
||||
yuv.x = yuv.x - 0.0625;
|
||||
rgb.r = dot(yuv, Rcoeff);
|
||||
rgb.g = dot(yuv, Gcoeff);
|
||||
rgb.b = dot(yuv, Bcoeff);
|
||||
|
@ -220,7 +225,7 @@ void QYUVOpenGLWidget::initTextures()
|
|||
// 设置st方向上纹理超出坐标时的显示策略
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width(), m_frameSize.height(), 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_frameSize.width(), m_frameSize.height(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenTextures(1, &m_texture[1]);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
|
||||
|
@ -228,7 +233,7 @@ void QYUVOpenGLWidget::initTextures()
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width() / 2, m_frameSize.height() / 2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_frameSize.width() / 2, m_frameSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenTextures(1, &m_texture[2]);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture[2]);
|
||||
|
@ -238,7 +243,7 @@ void QYUVOpenGLWidget::initTextures()
|
|||
// 设置st方向上纹理超出坐标时的显示策略
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width() / 2, m_frameSize.height() / 2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_frameSize.width() / 2, m_frameSize.height() / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
m_textureInited = true;
|
||||
}
|
||||
|
@ -249,7 +254,7 @@ void QYUVOpenGLWidget::deInitTextures()
|
|||
glDeleteTextures(3, m_texture);
|
||||
}
|
||||
|
||||
memset(m_texture, 0, 3);
|
||||
memset(m_texture, 0, sizeof(m_texture));
|
||||
m_textureInited = false;
|
||||
}
|
||||
|
||||
|
@ -262,7 +267,7 @@ void QYUVOpenGLWidget::updateTexture(GLuint texture, quint32 textureType, quint8
|
|||
|
||||
makeCurrent();
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), GL_RED, GL_UNSIGNED_BYTE, pixels);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride));
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
|
||||
doneCurrent();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define BUFSIZE 0x10000
|
||||
#define HEADER_SIZE 12
|
||||
#define NO_PTS UINT64_C(-1)
|
||||
#define NO_PTS UINT64_MAX
|
||||
|
||||
typedef qint32 (*ReadPacketFunc)(void *, quint8 *, qint32);
|
||||
|
||||
|
@ -28,6 +28,7 @@ static void avLogCallback(void *avcl, int level, const char *fmt, va_list vl)
|
|||
case AV_LOG_PANIC:
|
||||
case AV_LOG_FATAL:
|
||||
qFatal("%s", localFmt.toUtf8().data());
|
||||
break;
|
||||
case AV_LOG_ERROR:
|
||||
qCritical() << localFmt.toUtf8();
|
||||
break;
|
||||
|
@ -70,14 +71,14 @@ void Stream::setDecoder(Decoder *decoder)
|
|||
|
||||
static quint32 bufferRead32be(quint8 *buf)
|
||||
{
|
||||
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
return static_cast<quint32>((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
|
||||
}
|
||||
|
||||
static quint64 bufferRead64be(quint8 *buf)
|
||||
{
|
||||
quint32 msb = bufferRead32be(buf);
|
||||
quint32 lsb = bufferRead32be(&buf[4]);
|
||||
return ((quint64)msb << 32) | lsb;
|
||||
return (static_cast<quint64>(msb) << 32) | lsb;
|
||||
}
|
||||
|
||||
void Stream::setVideoSocket(VideoSocket *videoSocket)
|
||||
|
@ -230,16 +231,16 @@ bool Stream::recvPacket(AVPacket *packet)
|
|||
|
||||
quint64 pts = bufferRead64be(header);
|
||||
quint32 len = bufferRead32be(&header[8]);
|
||||
Q_ASSERT(pts == static_cast<quint64>(NO_PTS) || (pts & 0x8000000000000000) == 0);
|
||||
Q_ASSERT(pts == NO_PTS || (pts & 0x8000000000000000) == 0);
|
||||
Q_ASSERT(len);
|
||||
|
||||
if (av_new_packet(packet, len)) {
|
||||
if (av_new_packet(packet, static_cast<int>(len))) {
|
||||
qCritical("Could not allocate packet");
|
||||
return false;
|
||||
}
|
||||
|
||||
r = recvData(packet->data, len);
|
||||
if (r < 0 || ((uint32_t)r) < len) {
|
||||
r = recvData(packet->data, static_cast<qint32>(len));
|
||||
if (r < 0 || static_cast<quint32>(r) < len) {
|
||||
av_packet_unref(packet);
|
||||
return false;
|
||||
}
|
||||
|
@ -272,7 +273,7 @@ bool Stream::pushPacket(AVPacket *packet)
|
|||
m_hasPending = true;
|
||||
}
|
||||
|
||||
memcpy(m_pending.data + offset, packet->data, packet->size);
|
||||
memcpy(m_pending.data + offset, packet->data, static_cast<unsigned int>(packet->size));
|
||||
|
||||
if (!isConfig) {
|
||||
// prepare the concat packet to send to the decoder
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include "winres.h"
|
||||
|
||||
// 图标
|
||||
IDI_ICON1 ICON "QtScrcpy.ico"
|
||||
|
||||
// 版本信息
|
||||
// 为了FileDescription的中文不乱码,中文系统上本文件需要gbk编码,英文系统上本文件需要utf8编码
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH
|
||||
PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH
|
||||
|
@ -22,7 +20,7 @@ BEGIN
|
|||
BLOCK "080404b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "RanKun"
|
||||
VALUE "FileDescription", "安卓实时同屏软件"
|
||||
VALUE "FileDescription", "安卓实时同屏软件"
|
||||
VALUE "FileVersion", VERSION_RC_STR
|
||||
VALUE "LegalCopyright", "Copyright (C) RanKun 2018-2038. All rights reserved."
|
||||
VALUE "ProductName", "QtScrcpy"
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#define COMMON_RENDER_EXPIRED_FRAMES_KEY "RenderExpiredFrames"
|
||||
#define COMMON_RENDER_EXPIRED_FRAMES_DEF 0
|
||||
|
||||
#define COMMON_ADB_PATH_KEY "AdbPath"
|
||||
#define COMMON_ADB_PATH_DEF ""
|
||||
|
||||
// user data
|
||||
#define COMMON_RECORD_KEY "RecordPath"
|
||||
#define COMMON_RECORD_DEF ""
|
||||
|
@ -253,6 +256,15 @@ QString Config::getServerPath()
|
|||
return serverPath;
|
||||
}
|
||||
|
||||
QString Config::getAdbPath()
|
||||
{
|
||||
QString adbPath;
|
||||
m_settings->beginGroup(GROUP_COMMON);
|
||||
adbPath = m_settings->value(COMMON_ADB_PATH_KEY, COMMON_ADB_PATH_DEF).toString();
|
||||
m_settings->endGroup();
|
||||
return adbPath;
|
||||
}
|
||||
|
||||
QString Config::getTitle()
|
||||
{
|
||||
QString title;
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
int getRenderExpiredFrames();
|
||||
QString getPushFilePath();
|
||||
QString getServerPath();
|
||||
QString getAdbPath();
|
||||
|
||||
// user data
|
||||
QString getRecordPath();
|
||||
|
|
1
QtScrcpy/version
Normal file
1
QtScrcpy/version
Normal file
|
@ -0,0 +1 @@
|
|||
0.0.0
|
|
@ -32,7 +32,7 @@ It focuses on:
|
|||
|
||||

|
||||
|
||||
## Customized key mapping (Windows only)
|
||||
## Customized key mapping (Windows&MacOS 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" 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:
|
||||
|
|
|
@ -33,7 +33,7 @@ QtScrcpy可以通过USB(或通过TCP/IP)连接Android设备,并进行显示和
|
|||
|
||||

|
||||
|
||||
## 自定义按键映射(仅windows平台开启)
|
||||
## 自定义按键映射(仅windows&MacOS平台开启)
|
||||
可以根据需要,自己编写脚本将PC键盘按键映射为手机的触摸点击,编写规则在[这里](docs/按键映射说明.md)。
|
||||
|
||||
默认自带了针对和平精英手游和抖音进行键鼠映射的映射脚本,开启平精英手游后可以用键鼠像玩端游一样玩和平精英手游,开启抖音映射以后可以使用上下左右方向键模拟上下左右滑动,你也可以按照[编写规则](docs/按键映射说明.md)编写其他游戏的映射文件,默认按键映射如下:
|
||||
|
|
20
ci/generate-version.py
Normal file
20
ci/generate-version.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import sys
|
||||
import os
|
||||
|
||||
if __name__ == '__main__':
|
||||
p = os.popen('git rev-list --tags --max-count=1')
|
||||
commit = p.read()
|
||||
p.close()
|
||||
|
||||
p = os.popen('git describe --tags ' + commit)
|
||||
tag = p.read()
|
||||
p.close()
|
||||
|
||||
# print('get tag:', tag)
|
||||
|
||||
version = str(tag[1:])
|
||||
version_file = os.path.abspath(os.path.join(os.path.dirname(__file__), "../QtScrcpy/version"))
|
||||
file=open(version_file, 'w')
|
||||
file.write(version)
|
||||
file.close()
|
||||
sys.exit(0)
|
|
@ -1,8 +1,6 @@
|
|||
[common]
|
||||
# 窗口标题
|
||||
WindowTitle=QtScrcpy
|
||||
# 录制文件保存路径(必须以/作为分隔符)
|
||||
RecordPath=
|
||||
# 推送到安卓设备的文件保存路径(必须以/结尾)
|
||||
PushFilePath=/sdcard/
|
||||
# 最大fps(仅支持Android 10以上)
|
||||
|
@ -15,3 +13,5 @@ UseDesktopOpenGL=-1
|
|||
ServerVersion=1.12.1
|
||||
# scrcpy-server推送到安卓设备的路径
|
||||
ServerPath=/data/local/tmp/scrcpy-server.jar
|
||||
# 自定义adb路径,例如D:/android/tools/adb.exe
|
||||
AdbPath=
|
||||
|
|
12
docs/FAQ.md
12
docs/FAQ.md
|
@ -6,6 +6,18 @@
|
|||
## 支持声音(软件不做支持)
|
||||
[关于转发安卓声音到PC的讨论](https://github.com/Genymobile/scrcpy/issues/14#issuecomment-543204526)
|
||||
|
||||
## 画面不清晰
|
||||
在Windows上,您可能需要配置缩放行为。
|
||||
|
||||
QtScrcpy.exe>属性>兼容性>更改高DPI设置>覆盖高DPI缩放行为>由以下人员执行缩放:应用程序。
|
||||
|
||||
如果视频窗口大小远远小于设备屏幕的大小,则画面会不清晰。这在文字上尤其明显
|
||||
|
||||
## 玩和平精英上下车操作会失效
|
||||
这是由于游戏中上车会创建新的界面,导致鼠标触摸点失效,目前技术上没有好的解决办法
|
||||
|
||||
可以通过`连续按两次~键(数字键1左边)`来恢复,这是目前最好的办法。
|
||||
|
||||
## 无法输入中文
|
||||
手机端安装搜狗输入法/QQ输入法就可以支持输入中文了
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue