mirror of
https://github.com/AkiChase/scrcpy-mask
synced 2024-11-14 05:21:42 +08:00
Scrcpy Mask v0.4.0 (#31)
* feat(adb): remove adb resource * feat(scrcpy-mask-server): use custom scrcpy-server * feat(Device): remove screen size input * feat(hotkey): add resize listener * Scrcpy Mask v0.4.0
This commit is contained in:
parent
ca01405881
commit
e5f27bc00c
3
.github/workflows/publish.yml
vendored
3
.github/workflows/publish.yml
vendored
@ -1,5 +1,4 @@
|
||||
name: "publish"
|
||||
|
||||
name: "Multi platform compile"
|
||||
on:
|
||||
push:
|
||||
# 匹配特定标签 (refs/tags)
|
||||
|
@ -2,7 +2,13 @@
|
||||
|
||||
为了实现电脑控制安卓设备,本人使用 Tarui + Vue 3 + Rust 开发了一款跨平台桌面客户端。该客户端能够提供可视化的鼠标和键盘按键映射配置。通过按键映射实现了实现类似安卓模拟器的多点触控操作,具有毫秒级响应速度。该工具可广泛用于电脑控制安卓设备玩手游等等,提供流畅的触控体验。
|
||||
|
||||
本项目仅实现了 Scrcpy 控制协议,**不提供投屏功能**。因为投屏会存在延迟和模糊问题,本项目另辟蹊径,直接放弃投屏,而使用透明的蒙版显示窗口背后的内容(可以使用 AVD 、手机厂商提供的低延迟投屏等),从根本上杜绝了 Scrcpy 的投屏体验差的问题。
|
||||
本人对 Scrcpy 项目的开发者表示深深的敬意和感谢。Scrcpy 是一个强大而高效的开源工具,极大地方便了对 Android 设备的控制。本项目的实现基于 Scrcpy 的优秀架构,进行了鼠标键盘控制的优化和调整。
|
||||
|
||||
**本项目不提供投屏功能,不提供投屏功能,不提供投屏功能!**本项目仅实现了 Scrcpy 的控制协议。
|
||||
|
||||
原因是投屏会存在延迟和模糊问题,本项目另辟蹊径,直接放弃投屏,而使用透明的蒙版显示窗口背后的内容(可以使用 AVD 、手机厂商提供的低延迟投屏等),从根本上杜绝了 Scrcpy 的投屏体验差的问题。
|
||||
|
||||
除此之外,为了更好的支持 Scrcpy Mask 与安卓设备交互,本人对 scrcpy-server 进行了一些修改,在此扩展出了一个分支项目 [scrcpy-mask-server](https://github.com/AkiChase/scrcpy-mask-server)
|
||||
|
||||
## 特性
|
||||
|
||||
|
@ -4,7 +4,13 @@
|
||||
|
||||
To achieve computer control of Android devices, I developed a cross-platform desktop client using Tarui + Vue 3 + Rust. This client provides visual mouse and keyboard mapping configuration, enabling multi-touch operations similar to Android emulators through key mapping, with millisecond-level response time. This tool can be widely used for controlling Android devices from computers to play mobile games, providing a smooth touch experience.
|
||||
|
||||
This project only implements the Scrcpy control protocol and **does not provide Screen mirroring**. Because screen mirroring may involve latency and blurriness issues, this project takes a different approach by directly abandoning screen mirroring and instead using a transparent mask to display the content behind the window (which can be AVD, low-latency screen mirroring provided by your phone manufacturers, etc.), Completely eliminates the problem of poor screen casting experience inherent in Scrcpy.
|
||||
I express my deep respect and gratitude to the developers of the Scrcpy project. Scrcpy is a powerful and efficient open-source tool that greatly facilitates control over Android devices. This project is built upon the excellent architecture of Scrcpy, with optimizations and adjustments for mouse and keyboard control.
|
||||
|
||||
**This project does not provide screen mirroring functionality—let me emphasize, it does not provide screen mirroring functionality!** It only implements the Scrcpy control protocol.
|
||||
|
||||
Because screen mirroring may involve latency and blurriness issues, this project takes a different approach by directly abandoning screen mirroring and instead using a transparent mask to display the content behind the window (which can be AVD, low-latency screen mirroring provided by your phone manufacturers, etc.), Completely eliminates the problem of poor screen casting experience inherent in Scrcpy.
|
||||
|
||||
Furthermore, to better support interaction between Scrcpy Mask and Android devices, I have made some modifications to the scrcpy-server, leading to the creation of a separate branch project called [scrcpy-mask-server](https://github.com/AkiChase/scrcpy-mask-server).
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "scrcpy-mask",
|
||||
"private": true,
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scrcpy-mask"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["AkiChase"]
|
||||
edition = "2021"
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src-tauri/resource/scrcpy-mask-server-v2.4
Executable file
BIN
src-tauri/resource/scrcpy-mask-server-v2.4
Executable file
Binary file not shown.
Binary file not shown.
@ -1,7 +1,5 @@
|
||||
use crate::resource::{ResHelper, ResourceName};
|
||||
use std::{
|
||||
io::BufRead,
|
||||
path::PathBuf,
|
||||
process::{Child, Command, Stdio},
|
||||
};
|
||||
|
||||
@ -18,8 +16,8 @@ pub struct Device {
|
||||
|
||||
impl Device {
|
||||
/// execute "adb push" to push file from src to des
|
||||
pub fn cmd_push(res_dir: &PathBuf, id: &str, src: &str, des: &str) -> Result<String> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_push(id: &str, src: &str, des: &str) -> Result<String> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
let res = adb_command
|
||||
.args(&["-s", id, "push", src, des])
|
||||
.output()
|
||||
@ -28,8 +26,8 @@ impl Device {
|
||||
}
|
||||
|
||||
/// execute "adb reverse" to reverse the device port to local port
|
||||
pub fn cmd_reverse(res_dir: &PathBuf, id: &str, remote: &str, local: &str) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_reverse(id: &str, remote: &str, local: &str) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["-s", id, "reverse", remote, local])
|
||||
.output()
|
||||
@ -38,8 +36,8 @@ impl Device {
|
||||
}
|
||||
|
||||
/// execute "adb forward" to forward the local port to the device
|
||||
pub fn cmd_forward(res_dir: &PathBuf, id: &str, local: &str, remote: &str) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_forward(id: &str, local: &str, remote: &str) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["-s", id, "forward", local, remote])
|
||||
.output()
|
||||
@ -48,8 +46,8 @@ impl Device {
|
||||
}
|
||||
|
||||
/// execute "adb shell" to execute shell command on the device
|
||||
pub fn cmd_shell(res_dir: &PathBuf, id: &str, shell_args: &[&str]) -> Result<Child> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_shell(id: &str, shell_args: &[&str]) -> Result<Child> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
let mut args = vec!["-s", id, "shell"];
|
||||
args.extend_from_slice(shell_args);
|
||||
Ok(adb_command
|
||||
@ -60,8 +58,8 @@ impl Device {
|
||||
}
|
||||
|
||||
/// execute "adb shell wm size" to get screen size
|
||||
pub fn cmd_screen_size(res_dir: &PathBuf, id: &str) -> Result<(u32, u32)> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_screen_size(id: &str) -> Result<(u32, u32)> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
let output = adb_command
|
||||
.args(&["-s", id, "shell", "wm", "size"])
|
||||
.output()
|
||||
@ -86,22 +84,19 @@ pub struct Adb;
|
||||
/// Module to execute adb command and fetch output.
|
||||
/// But some output of command won't be output, like adb service startup information.
|
||||
impl Adb {
|
||||
fn cmd_base(res_dir: &PathBuf) -> Command {
|
||||
pub fn cmd_base() -> Command {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let mut cmd = Command::new(ResHelper::get_file_path(res_dir, ResourceName::Adb));
|
||||
let mut cmd = Command::new("adb");
|
||||
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
|
||||
cmd
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
Command::new(ResHelper::get_file_path(res_dir, ResourceName::Adb))
|
||||
return cmd;
|
||||
}
|
||||
Command::new("adb")
|
||||
}
|
||||
|
||||
/// execute "adb devices" and return devices list
|
||||
pub fn cmd_devices(res_dir: &PathBuf) -> Result<Vec<Device>> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_devices() -> Result<Vec<Device>> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
let output = adb_command
|
||||
.args(&["devices"])
|
||||
.output()
|
||||
@ -128,8 +123,8 @@ impl Adb {
|
||||
}
|
||||
|
||||
/// execute "adb kill-server"
|
||||
pub fn cmd_kill_server(res_dir: &PathBuf) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_kill_server() -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["kill-server"])
|
||||
.output()
|
||||
@ -138,8 +133,8 @@ impl Adb {
|
||||
}
|
||||
|
||||
/// execute "adb reverse --remove-all"
|
||||
pub fn cmd_reverse_remove(res_dir: &PathBuf) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_reverse_remove() -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["reverse", " --remove-all"])
|
||||
.output()
|
||||
@ -148,8 +143,8 @@ impl Adb {
|
||||
}
|
||||
|
||||
/// execute "adb forward --remove-all"
|
||||
pub fn cmd_forward_remove(res_dir: &PathBuf) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_forward_remove() -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["forward", " --remove-all"])
|
||||
.output()
|
||||
@ -158,8 +153,8 @@ impl Adb {
|
||||
}
|
||||
|
||||
/// execute "adb start-server"
|
||||
pub fn cmd_start_server(res_dir: &PathBuf) -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_start_server() -> Result<()> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
adb_command
|
||||
.args(&["start-server"])
|
||||
.output()
|
||||
@ -167,8 +162,8 @@ impl Adb {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd_connect(res_dir: &PathBuf, address: &str) -> Result<String> {
|
||||
let mut adb_command = Adb::cmd_base(res_dir);
|
||||
pub fn cmd_connect(address: &str) -> Result<String> {
|
||||
let mut adb_command = Adb::cmd_base();
|
||||
let output = adb_command
|
||||
.args(&["connect", address])
|
||||
.output()
|
||||
@ -178,10 +173,3 @@ impl Adb {
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t() {
|
||||
let res_dir = PathBuf::from("/Users/akichase/Projects/github/scrcpy-mask/src-tauri/resource/");
|
||||
let res = Adb::cmd_connect(&res_dir, "127.0.0.1:1234").unwrap();
|
||||
println!("{}", res)
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ use std::{io::BufRead, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
adb::{Adb, Device},
|
||||
resource::{ResHelper, ResourceName}, share,
|
||||
resource::{ResHelper, ResourceName},
|
||||
share,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -22,35 +23,34 @@ impl ScrcpyClient {
|
||||
ResHelper::get_scrcpy_version()
|
||||
}
|
||||
|
||||
pub fn adb_devices(res_dir: &PathBuf) -> Result<Vec<Device>> {
|
||||
Adb::cmd_devices(res_dir)
|
||||
pub fn adb_devices() -> Result<Vec<Device>> {
|
||||
Adb::cmd_devices()
|
||||
}
|
||||
|
||||
pub fn adb_restart_server(res_dir: &PathBuf) -> Result<()> {
|
||||
Adb::cmd_kill_server(res_dir)?;
|
||||
Adb::cmd_start_server(res_dir)?;
|
||||
pub fn adb_restart_server() -> Result<()> {
|
||||
Adb::cmd_kill_server()?;
|
||||
Adb::cmd_start_server()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn adb_reverse_remove(res_dir: &PathBuf) -> Result<()> {
|
||||
Adb::cmd_reverse_remove(res_dir)
|
||||
pub fn adb_reverse_remove() -> Result<()> {
|
||||
Adb::cmd_reverse_remove()
|
||||
}
|
||||
|
||||
pub fn adb_forward_remove(res_dir: &PathBuf) -> Result<()> {
|
||||
Adb::cmd_forward_remove(res_dir)
|
||||
pub fn adb_forward_remove() -> Result<()> {
|
||||
Adb::cmd_forward_remove()
|
||||
}
|
||||
|
||||
// get the screen size of the device
|
||||
pub fn get_device_screen_size(res_dir: &PathBuf, id: &str) -> Result<(u32, u32)> {
|
||||
Device::cmd_screen_size(res_dir, id)
|
||||
pub fn get_device_screen_size(id: &str) -> Result<(u32, u32)> {
|
||||
Device::cmd_screen_size(id)
|
||||
}
|
||||
|
||||
/// push server file to current device
|
||||
pub fn push_server_file(res_dir: &PathBuf, id: &str) -> Result<()> {
|
||||
pub fn push_server_file(dir: &PathBuf, id: &str) -> Result<()> {
|
||||
let info = Device::cmd_push(
|
||||
res_dir,
|
||||
id,
|
||||
&ResHelper::get_file_path(res_dir, ResourceName::ScrcpyServer).to_string_lossy(),
|
||||
&ResHelper::get_file_path(dir, ResourceName::ScrcpyServer).to_string_lossy(),
|
||||
"/data/local/tmp/scrcpy-server.jar",
|
||||
)?;
|
||||
|
||||
@ -59,9 +59,8 @@ impl ScrcpyClient {
|
||||
}
|
||||
|
||||
/// forward the local port to the device
|
||||
pub fn forward_server_port(res_dir: &PathBuf, id: &str, scid: &str, port: u16) -> Result<()> {
|
||||
pub fn forward_server_port(id: &str, scid: &str, port: u16) -> Result<()> {
|
||||
Device::cmd_forward(
|
||||
res_dir,
|
||||
id,
|
||||
&format!("tcp:{}", port),
|
||||
&format!("localabstract:scrcpy_{}", scid),
|
||||
@ -71,9 +70,8 @@ impl ScrcpyClient {
|
||||
}
|
||||
|
||||
/// reverse the device port to the local port
|
||||
pub fn reverse_server_port(res_dir: &PathBuf, id: &str, scid: &str, port: u16) -> Result<()> {
|
||||
pub fn reverse_server_port(id: &str, scid: &str, port: u16) -> Result<()> {
|
||||
Device::cmd_reverse(
|
||||
res_dir,
|
||||
id,
|
||||
&format!("localabstract:scrcpy_{}", scid),
|
||||
&format!("tcp:{}", port),
|
||||
@ -83,14 +81,8 @@ impl ScrcpyClient {
|
||||
}
|
||||
|
||||
/// spawn a new thread to start scrcpy server
|
||||
pub fn shell_start_server(
|
||||
res_dir: &PathBuf,
|
||||
id: &str,
|
||||
scid: &str,
|
||||
version: &str,
|
||||
) -> Result<()> {
|
||||
pub fn shell_start_server(id: &str, scid: &str, version: &str) -> Result<()> {
|
||||
let mut child = Device::cmd_shell(
|
||||
res_dir,
|
||||
id,
|
||||
&[
|
||||
"CLASSPATH=/data/local/tmp/scrcpy-server.jar",
|
||||
|
@ -13,9 +13,8 @@ use tauri::Manager;
|
||||
|
||||
#[tauri::command]
|
||||
/// get devices info list
|
||||
fn adb_devices(app: tauri::AppHandle) -> Result<Vec<Device>, String> {
|
||||
let dir = app.path().resource_dir().unwrap().join("resource");
|
||||
match Adb::cmd_devices(&dir) {
|
||||
fn adb_devices() -> Result<Vec<Device>, String> {
|
||||
match Adb::cmd_devices() {
|
||||
Ok(devices) => Ok(devices),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
@ -23,15 +22,8 @@ fn adb_devices(app: tauri::AppHandle) -> Result<Vec<Device>, String> {
|
||||
|
||||
#[tauri::command]
|
||||
/// forward local port to the device port
|
||||
fn forward_server_port(
|
||||
app: tauri::AppHandle,
|
||||
id: String,
|
||||
scid: String,
|
||||
port: u16,
|
||||
) -> Result<(), String> {
|
||||
let dir = app.path().resource_dir().unwrap().join("resource");
|
||||
|
||||
match ScrcpyClient::forward_server_port(&dir, &id, &scid, port) {
|
||||
fn forward_server_port(id: String, scid: String, port: u16) -> Result<(), String> {
|
||||
match ScrcpyClient::forward_server_port(&id, &scid, port) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
@ -66,12 +58,11 @@ fn start_scrcpy_server(
|
||||
scid.clone(),
|
||||
));
|
||||
|
||||
let dir = app.path().resource_dir().unwrap().join("resource");
|
||||
let version = ScrcpyClient::get_scrcpy_version();
|
||||
|
||||
// start scrcpy server
|
||||
tokio::spawn(async move {
|
||||
ScrcpyClient::shell_start_server(&dir, &id, &scid, &version).unwrap();
|
||||
ScrcpyClient::shell_start_server(&id, &scid, &version).unwrap();
|
||||
});
|
||||
|
||||
// connect to scrcpy server
|
||||
@ -131,9 +122,8 @@ fn get_cur_client_info() -> Result<Option<share::ClientInfo>, String> {
|
||||
|
||||
#[tauri::command]
|
||||
/// get device screen size
|
||||
fn get_device_screen_size(id: String, app: tauri::AppHandle) -> Result<(u32, u32), String> {
|
||||
let dir = app.path().resource_dir().unwrap().join("resource");
|
||||
match ScrcpyClient::get_device_screen_size(&dir, &id) {
|
||||
fn get_device_screen_size(id: String) -> Result<(u32, u32), String> {
|
||||
match ScrcpyClient::get_device_screen_size(&id) {
|
||||
Ok(size) => Ok(size),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
@ -141,9 +131,8 @@ fn get_device_screen_size(id: String, app: tauri::AppHandle) -> Result<(u32, u32
|
||||
|
||||
#[tauri::command]
|
||||
/// connect to wireless device
|
||||
fn adb_connect(address: String, app: tauri::AppHandle) -> Result<String, String> {
|
||||
let dir = app.path().resource_dir().unwrap().join("resource");
|
||||
match Adb::cmd_connect(&dir, &address) {
|
||||
fn adb_connect(address: String) -> Result<String, String> {
|
||||
match Adb::cmd_connect(&address) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
@ -160,6 +149,14 @@ fn load_default_keyconfig(app: tauri::AppHandle) -> Result<String, String> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn check_adb_available() -> Result<(), String> {
|
||||
match Adb::cmd_base().output() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tauri::Builder::default()
|
||||
@ -241,7 +238,8 @@ async fn main() {
|
||||
get_cur_client_info,
|
||||
get_device_screen_size,
|
||||
adb_connect,
|
||||
load_default_keyconfig
|
||||
load_default_keyconfig,
|
||||
check_adb_available
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
@ -2,7 +2,6 @@ use anyhow::{anyhow, Ok, Result};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub enum ResourceName {
|
||||
Adb,
|
||||
ScrcpyServer,
|
||||
DefaultKeyConfig,
|
||||
}
|
||||
@ -13,7 +12,9 @@ pub struct ResHelper {
|
||||
|
||||
impl ResHelper {
|
||||
pub fn res_init(res_dir: &PathBuf) -> Result<()> {
|
||||
for name in [ResourceName::Adb, ResourceName::ScrcpyServer] {
|
||||
let res = [ResourceName::ScrcpyServer, ResourceName::DefaultKeyConfig];
|
||||
|
||||
for name in res {
|
||||
let file_path = ResHelper::get_file_path(res_dir, name);
|
||||
if !file_path.exists() {
|
||||
return Err(anyhow!(format!(
|
||||
@ -27,14 +28,7 @@ impl ResHelper {
|
||||
}
|
||||
pub fn get_file_path(dir: &PathBuf, file_name: ResourceName) -> PathBuf {
|
||||
match file_name {
|
||||
#[cfg(target_os = "windows")]
|
||||
ResourceName::Adb => dir.join("adb-win.exe"),
|
||||
#[cfg(target_os = "linux")]
|
||||
ResourceName::Adb => dir.join("adb-linux"),
|
||||
#[cfg(target_os = "macos")]
|
||||
ResourceName::Adb => dir.join("adb-mac"),
|
||||
|
||||
ResourceName::ScrcpyServer => dir.join("scrcpy-server-v2.4"),
|
||||
ResourceName::ScrcpyServer => dir.join("scrcpy-mask-server-v2.4"),
|
||||
ResourceName::DefaultKeyConfig => dir.join("default-key-config.json"),
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,12 @@ async fn read_socket(
|
||||
}
|
||||
let device_name = std::str::from_utf8(&buf[..end]).unwrap();
|
||||
// update device name for share
|
||||
share::CLIENT_INFO.lock().unwrap().as_mut().unwrap().device_name = device_name.to_string();
|
||||
share::CLIENT_INFO
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.device_name = device_name.to_string();
|
||||
|
||||
let msg = json!({
|
||||
"type": "MetaData",
|
||||
@ -149,6 +154,20 @@ async fn handle_device_message(
|
||||
let mut buf: Vec<u8> = vec![0; size as usize];
|
||||
reader.read_exact(&mut buf).await?;
|
||||
}
|
||||
// 设备旋转
|
||||
DeviceMsgType::DeviceMsgTypeRotation => {
|
||||
let rotation = reader.read_u16().await?;
|
||||
let width = reader.read_i32().await?;
|
||||
let height = reader.read_i32().await?;
|
||||
let msg = json!({
|
||||
"type": "DeviceRotation",
|
||||
"rotation": rotation,
|
||||
"width": width,
|
||||
"height": height
|
||||
})
|
||||
.to_string();
|
||||
device_reply_sender.send(msg).await?;
|
||||
}
|
||||
};
|
||||
anyhow::Ok(())
|
||||
}
|
||||
@ -181,6 +200,8 @@ async fn recv_front_msg(
|
||||
// 处理Scrcpy Mask命令
|
||||
if let Some(cmd_type) = ScrcpyMaskCmdType::from_i64(front_msg_type) {
|
||||
if let ScrcpyMaskCmdType::Shutdown = cmd_type {
|
||||
*share::CLIENT_INFO.lock().unwrap() = None;
|
||||
|
||||
drop(write_half);
|
||||
println!("Drop TcpStream writer");
|
||||
app.unlisten(listen_handler);
|
||||
@ -197,7 +218,7 @@ async fn recv_front_msg(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("fc-command非法");
|
||||
eprintln!("fc-command invalid!");
|
||||
eprintln!("{:?}", payload);
|
||||
}
|
||||
}
|
||||
@ -212,6 +233,7 @@ enum DeviceMsgType {
|
||||
DeviceMsgTypeClipboard,
|
||||
DeviceMsgTypeAckClipboard,
|
||||
DeviceMsgTypeUhidOutput,
|
||||
DeviceMsgTypeRotation,
|
||||
}
|
||||
|
||||
impl DeviceMsgType {
|
||||
@ -220,6 +242,7 @@ impl DeviceMsgType {
|
||||
0 => Some(Self::DeviceMsgTypeClipboard),
|
||||
1 => Some(Self::DeviceMsgTypeAckClipboard),
|
||||
2 => Some(Self::DeviceMsgTypeUhidOutput),
|
||||
3 => Some(Self::DeviceMsgTypeRotation),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"productName": "scrcpy-mask",
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"identifier": "com.akichase.mask",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
@ -30,6 +30,10 @@
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [
|
||||
"resource/default-key-config.json",
|
||||
"resource/scrcpy-mask-server-v2.4"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"bundle": {
|
||||
"resources": [
|
||||
"resource/default-key-config.json",
|
||||
"resource/scrcpy-server-v2.4",
|
||||
"resource/adb-linux"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"bundle": {
|
||||
"resources": [
|
||||
"resource/default-key-config.json",
|
||||
"resource/scrcpy-server-v2.4",
|
||||
"resource/adb-mac"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"bundle": {
|
||||
"resources": [
|
||||
"resource/default-key-config.json",
|
||||
"resource/scrcpy-server-v2.4",
|
||||
"resource/adb-win.exe",
|
||||
"resource/AdbWinApi.dll",
|
||||
"resource/AdbWinUsbApi.dll"
|
||||
]
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@ import {
|
||||
} from "../invoke";
|
||||
import {
|
||||
NH4,
|
||||
NP,
|
||||
NInput,
|
||||
NInputNumber,
|
||||
NButton,
|
||||
@ -30,7 +29,6 @@ import {
|
||||
NEmpty,
|
||||
NTooltip,
|
||||
NFlex,
|
||||
NFormItem,
|
||||
NIcon,
|
||||
NSpin,
|
||||
NScrollbar,
|
||||
@ -42,7 +40,6 @@ import {
|
||||
} from "naive-ui";
|
||||
import { CloseCircle, InformationCircle, Refresh } from "@vicons/ionicons5";
|
||||
import { UnlistenFn, listen } from "@tauri-apps/api/event";
|
||||
import { Store } from "@tauri-apps/plugin-store";
|
||||
import { shutdown } from "../frontcommand/scrcpyMaskCmd";
|
||||
import { useGlobalStore } from "../store/global";
|
||||
import { useI18n } from "vue-i18n";
|
||||
@ -57,10 +54,9 @@ const port = ref(27183);
|
||||
const wireless_address = ref("");
|
||||
const ws_address = ref("");
|
||||
|
||||
const localStore = new Store("store.bin");
|
||||
|
||||
//#region listener
|
||||
let deviceWaitForMetadataTask: ((deviceName: string) => void) | null = null;
|
||||
let deviceWaitForScreenSizeTask: ((w: number, h: number) => void) | null = null;
|
||||
|
||||
let unlisten: UnlistenFn | undefined;
|
||||
onMounted(async () => {
|
||||
@ -77,6 +73,15 @@ onMounted(async () => {
|
||||
case "ClipboardSetAck":
|
||||
console.log("ClipboardSetAck", payload.sequence);
|
||||
break;
|
||||
case "DeviceRotation":
|
||||
if (deviceWaitForScreenSizeTask) {
|
||||
deviceWaitForScreenSizeTask(payload.width, payload.height);
|
||||
} else {
|
||||
store.screenSizeW = payload.width;
|
||||
store.screenSizeH = payload.height;
|
||||
message.info("设备旋转");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown reply", payload);
|
||||
break;
|
||||
@ -216,24 +221,12 @@ async function deviceControl() {
|
||||
port.value = 27183;
|
||||
}
|
||||
|
||||
if (!(store.screenSizeW > 0) || !(store.screenSizeH > 0)) {
|
||||
message.error(t("pages.Device.deviceControl.inputScreenSize"));
|
||||
store.screenSizeW = 0;
|
||||
store.screenSizeH = 0;
|
||||
store.hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
if (store.controledDevice) {
|
||||
message.error(t("pages.Device.deviceControl.closeCurDevice"));
|
||||
store.hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
localStore.set("screenSize", {
|
||||
sizeW: store.screenSizeW,
|
||||
sizeH: store.screenSizeH,
|
||||
});
|
||||
message.info(t("pages.Device.deviceControl.controlInfo"));
|
||||
|
||||
const device = devices.value[rowIndex];
|
||||
@ -263,11 +256,26 @@ async function deviceControl() {
|
||||
deviceName,
|
||||
deviceID: device.id,
|
||||
};
|
||||
nextTick(() => {
|
||||
deviceWaitForMetadataTask = null;
|
||||
if (!deviceWaitForScreenSizeTask) {
|
||||
nextTick(() => {
|
||||
clearTimeout(id);
|
||||
store.hideLoading();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// add cb for screen size
|
||||
deviceWaitForScreenSizeTask = (w: number, h: number) => {
|
||||
store.screenSizeW = w;
|
||||
store.screenSizeH = h;
|
||||
deviceWaitForScreenSizeTask = null;
|
||||
if (!deviceWaitForMetadataTask) {
|
||||
nextTick(() => {
|
||||
clearTimeout(id);
|
||||
store.hideLoading();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -296,7 +304,12 @@ async function onMenuSelect(key: string) {
|
||||
|
||||
async function refreshDevices() {
|
||||
store.showLoading();
|
||||
try {
|
||||
devices.value = await adbDevices();
|
||||
} catch (e) {
|
||||
message.error(t("pages.Device.adbDeviceError"));
|
||||
console.error(e);
|
||||
}
|
||||
store.hideLoading();
|
||||
}
|
||||
|
||||
@ -368,26 +381,6 @@ function closeWS() {
|
||||
$t("pages.Device.wsConnect")
|
||||
}}</NButton>
|
||||
</NInputGroup>
|
||||
<NH4 prefix="bar">{{ $t("pages.Device.deviceSize.title") }}</NH4>
|
||||
<NFlex justify="left" align="center">
|
||||
<NFormItem :label="$t('pages.Device.deviceSize.width')">
|
||||
<NInputNumber
|
||||
v-model:value="store.screenSizeW"
|
||||
:placeholder="$t('pages.Device.deviceSize.widthPlaceholder')"
|
||||
:min="0"
|
||||
:disabled="store.controledDevice !== null"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('pages.Device.deviceSize.height')">
|
||||
<NInputNumber
|
||||
v-model:value="store.screenSizeH"
|
||||
:placeholder="$t('pages.Device.deviceSize.heightPlaceholder')"
|
||||
:min="0"
|
||||
:disabled="store.controledDevice !== null"
|
||||
/>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
<NP>{{ $t("pages.Device.deviceSize.tip") }}</NP>
|
||||
<NH4 prefix="bar">{{ $t("pages.Device.controledDevice") }}</NH4>
|
||||
<div class="controled-device-list">
|
||||
<NEmpty
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
clearShortcuts,
|
||||
listenToEvent,
|
||||
unlistenToEvent,
|
||||
updateScreenSizeAndMaskArea,
|
||||
} from "../hotkey";
|
||||
import { KeyMappingConfig, KeySteeringWheel } from "../keyMappingConfig";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
@ -20,6 +19,7 @@ import { AndroidKeycode } from "../frontcommand/android";
|
||||
import { Store } from "@tauri-apps/plugin-store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { SendKeyAction, sendKey } from "../frontcommand/scrcpyMaskCmd";
|
||||
import { checkAdbAvailable } from "../invoke";
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useGlobalStore();
|
||||
@ -43,15 +43,11 @@ onActivated(async () => {
|
||||
const maskElement = document.getElementById("maskElement") as HTMLElement;
|
||||
|
||||
if (store.controledDevice) {
|
||||
updateScreenSizeAndMaskArea(
|
||||
[store.screenSizeW, store.screenSizeH],
|
||||
[maskElement.clientWidth, maskElement.clientHeight]
|
||||
);
|
||||
|
||||
if (
|
||||
applyShortcuts(
|
||||
maskElement,
|
||||
store.keyMappingConfigList[store.curKeyMappingIndex],
|
||||
store,
|
||||
message,
|
||||
t
|
||||
)
|
||||
@ -64,23 +60,25 @@ onActivated(async () => {
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await checkAdb();
|
||||
await loadLocalStore();
|
||||
store.checkUpdate = checkUpdate;
|
||||
store.showInputBox = showInputBox;
|
||||
if (store.checkUpdateAtStart) checkUpdate();
|
||||
});
|
||||
|
||||
async function loadLocalStore() {
|
||||
const localStore = new Store("store.bin");
|
||||
// loading screenSize from local store
|
||||
const screenSize = await localStore.get<{ sizeW: number; sizeH: number }>(
|
||||
"screenSize"
|
||||
);
|
||||
if (screenSize !== null) {
|
||||
store.screenSizeW = screenSize.sizeW;
|
||||
store.screenSizeH = screenSize.sizeH;
|
||||
async function checkAdb() {
|
||||
try {
|
||||
await checkAdbAvailable();
|
||||
} catch (e) {
|
||||
message.error(t("pages.Mask.checkAdb", [e]), {
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLocalStore() {
|
||||
const localStore = new Store("store.bin");
|
||||
// loading keyMappingConfigList from local store
|
||||
let keyMappingConfigList = await localStore.get<KeyMappingConfig[]>(
|
||||
"keyMappingConfigList"
|
||||
|
136
src/hotkey.ts
136
src/hotkey.ts
@ -24,17 +24,18 @@ import {
|
||||
import { useGlobalStore } from "./store/global";
|
||||
import { LogicalPosition, getCurrent } from "@tauri-apps/api/window";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { UnlistenFn } from "@tauri-apps/api/event";
|
||||
|
||||
function clientxToPosx(clientx: number) {
|
||||
return clientx < 70
|
||||
? 0
|
||||
: Math.floor((clientx - 70) * (screenSizeW / maskSizeW));
|
||||
: Math.floor((clientx - 70) * (store.screenSizeW / maskSizeW));
|
||||
}
|
||||
|
||||
function clientyToPosy(clienty: number) {
|
||||
return clienty < 30
|
||||
? 0
|
||||
: Math.floor((clienty - 30) * (screenSizeH / maskSizeH));
|
||||
: Math.floor((clienty - 30) * (store.screenSizeH / maskSizeH));
|
||||
}
|
||||
|
||||
function clientxToPosOffsetx(clientx: number, posx: number, scale = 1) {
|
||||
@ -51,7 +52,7 @@ function clientPosToSkillOffset(
|
||||
clientPos: { x: number; y: number },
|
||||
range: number
|
||||
): { offsetX: number; offsetY: number } {
|
||||
const maxLength = (120 / maskSizeH) * screenSizeH;
|
||||
const maxLength = (120 / maskSizeH) * store.screenSizeH;
|
||||
const centerX = maskSizeW * 0.5;
|
||||
const centerY = maskSizeH * 0.5;
|
||||
|
||||
@ -95,7 +96,7 @@ function calculateMacroPosX(
|
||||
relativeSizeW: number
|
||||
): number {
|
||||
if (typeof posX === "number") {
|
||||
return Math.round(posX * (screenSizeW / relativeSizeW));
|
||||
return Math.round(posX * (store.screenSizeW / relativeSizeW));
|
||||
}
|
||||
if (typeof posX === "string") {
|
||||
return clientxToPosx(mouseX);
|
||||
@ -103,7 +104,7 @@ function calculateMacroPosX(
|
||||
if (posX[0] === "mouse") {
|
||||
return (
|
||||
clientxToPosx(mouseX) +
|
||||
Math.round(posX[1] * (screenSizeW / relativeSizeW))
|
||||
Math.round(posX[1] * (store.screenSizeW / relativeSizeW))
|
||||
);
|
||||
} else {
|
||||
throw new Error("Invalid pos");
|
||||
@ -117,7 +118,7 @@ function calculateMacroPosY(
|
||||
relativeSizeH: number
|
||||
): number {
|
||||
if (typeof posY === "number") {
|
||||
return Math.round(posY * (screenSizeH / relativeSizeH));
|
||||
return Math.round(posY * (store.screenSizeH / relativeSizeH));
|
||||
}
|
||||
if (typeof posY === "string") {
|
||||
return clientyToPosy(mouseY);
|
||||
@ -125,7 +126,7 @@ function calculateMacroPosY(
|
||||
if (posY[0] === "mouse") {
|
||||
return (
|
||||
clientyToPosy(mouseY) +
|
||||
Math.round(posY[1] * (screenSizeH / relativeSizeH))
|
||||
Math.round(posY[1] * (store.screenSizeH / relativeSizeH))
|
||||
);
|
||||
} else {
|
||||
throw new Error("Invalid pos");
|
||||
@ -157,8 +158,8 @@ function addObservationShortcuts(
|
||||
) {
|
||||
let observationMouseX = 0;
|
||||
let observationMouseY = 0;
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
addShortcut(
|
||||
key,
|
||||
async () => {
|
||||
@ -195,8 +196,8 @@ function addTapShortcuts(
|
||||
posY: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
addShortcut(
|
||||
key,
|
||||
async () => {
|
||||
@ -216,8 +217,8 @@ function addCancelSkillShortcuts(
|
||||
posY: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
addShortcut(
|
||||
key,
|
||||
async () => {
|
||||
@ -259,8 +260,8 @@ function addTriggerWhenPressedSkillShortcuts(
|
||||
rangeOrTime: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
if (directional) {
|
||||
addShortcut(
|
||||
key,
|
||||
@ -276,8 +277,8 @@ function addTriggerWhenPressedSkillShortcuts(
|
||||
action: SwipeAction.Default,
|
||||
pointerId,
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: [
|
||||
{ x: posX, y: posY },
|
||||
@ -316,8 +317,8 @@ function addTriggerWhenDoublePressedSkillShortcuts(
|
||||
range: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
doublePressedDownKey.set(key, false);
|
||||
addShortcut(
|
||||
key,
|
||||
@ -333,8 +334,8 @@ function addTriggerWhenDoublePressedSkillShortcuts(
|
||||
action: SwipeAction.NoUp,
|
||||
pointerId,
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: [
|
||||
{ x: posX, y: posY },
|
||||
@ -392,8 +393,8 @@ function addDirectionlessSkillShortcuts(
|
||||
posY: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
addShortcut(
|
||||
key,
|
||||
// down
|
||||
@ -410,8 +411,8 @@ function addDirectionlessSkillShortcuts(
|
||||
action: TouchAction.Up,
|
||||
pointerId,
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: {
|
||||
x: posX,
|
||||
@ -442,8 +443,8 @@ function addDirectionalSkillShortcuts(
|
||||
range: number,
|
||||
pointerId: number
|
||||
) {
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
addShortcut(
|
||||
key,
|
||||
// down
|
||||
@ -458,8 +459,8 @@ function addDirectionalSkillShortcuts(
|
||||
action: SwipeAction.NoUp,
|
||||
pointerId,
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: [
|
||||
{ x: posX, y: posY },
|
||||
@ -514,8 +515,8 @@ function addSteeringWheelKeyboardShortcuts(
|
||||
let loopFlag = false;
|
||||
let curPosX = 0;
|
||||
let curPosY = 0;
|
||||
posX = Math.round((posX / relativeSize.w) * screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * screenSizeH);
|
||||
posX = Math.round((posX / relativeSize.w) * store.screenSizeW);
|
||||
posY = Math.round((posY / relativeSize.h) * store.screenSizeH);
|
||||
|
||||
// calculate the end coordinates of the eight directions of the direction wheel
|
||||
let offsetHalf = Math.round(offset / 1.414);
|
||||
@ -657,18 +658,18 @@ function addSightShortcuts(
|
||||
const sightClientX = 70 + sightKeyMapping.posX;
|
||||
const sightClientY = 30 + sightKeyMapping.posY;
|
||||
const sightDeviceX = Math.round(
|
||||
(sightKeyMapping.posX / relativeSize.w) * screenSizeW
|
||||
(sightKeyMapping.posX / relativeSize.w) * store.screenSizeW
|
||||
);
|
||||
const sightDeviceY = Math.round(
|
||||
(sightKeyMapping.posY / relativeSize.h) * screenSizeH
|
||||
(sightKeyMapping.posY / relativeSize.h) * store.screenSizeH
|
||||
);
|
||||
|
||||
const fireDeviceX = fireKeyMapping
|
||||
? Math.round((fireKeyMapping.posX / relativeSize.w) * screenSizeW)
|
||||
? Math.round((fireKeyMapping.posX / relativeSize.w) * store.screenSizeW)
|
||||
: 0;
|
||||
|
||||
const fireDeviceY = fireKeyMapping
|
||||
? Math.round((fireKeyMapping.posY / relativeSize.h) * screenSizeH)
|
||||
? Math.round((fireKeyMapping.posY / relativeSize.h) * store.screenSizeH)
|
||||
: 0;
|
||||
|
||||
const removeShortcut = (key: string) => {
|
||||
@ -917,22 +918,6 @@ function addSightShortcuts(
|
||||
});
|
||||
}
|
||||
|
||||
let screenSizeW: number;
|
||||
let screenSizeH: number;
|
||||
let maskSizeW: number;
|
||||
let maskSizeH: number;
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
let maskElement: HTMLElement;
|
||||
let message: ReturnType<typeof useMessage>;
|
||||
let t: ReturnType<typeof useI18n>["t"];
|
||||
|
||||
const downKeyMap: Map<string, boolean> = new Map();
|
||||
const downKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const loopDownKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const upKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const cancelAbleKeyList: string[] = [];
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
event.preventDefault();
|
||||
if (event.repeat) return;
|
||||
@ -1166,8 +1151,8 @@ async function execMacro(
|
||||
action: swipeAction,
|
||||
pointerId: cmd.args[1],
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: calculateMacroPosList(cmd.args[2], relativeSize),
|
||||
intervalBetweenPos: cmd.args[3],
|
||||
@ -1356,8 +1341,8 @@ async function touchX(
|
||||
action,
|
||||
pointerId,
|
||||
screen: {
|
||||
w: screenSizeW,
|
||||
h: screenSizeH,
|
||||
w: store.screenSizeW,
|
||||
h: store.screenSizeH,
|
||||
},
|
||||
pos: {
|
||||
x: posX,
|
||||
@ -1395,28 +1380,51 @@ export function clearShortcuts() {
|
||||
loopDownKeyCBMap.clear();
|
||||
upKeyCBMap.clear();
|
||||
cancelAbleKeyList.length = 0;
|
||||
}
|
||||
|
||||
export function updateScreenSizeAndMaskArea(
|
||||
screenSize: [number, number],
|
||||
maskArea: [number, number]
|
||||
) {
|
||||
screenSizeW = screenSize[0];
|
||||
screenSizeH = screenSize[1];
|
||||
maskSizeW = maskArea[0];
|
||||
maskSizeH = maskArea[1];
|
||||
// unlisten to resize
|
||||
unlistenResize();
|
||||
}
|
||||
|
||||
export function applyShortcuts(
|
||||
element: HTMLElement,
|
||||
keyMappingConfig: KeyMappingConfig,
|
||||
globalStore: ReturnType<typeof useGlobalStore>,
|
||||
messageAPI: ReturnType<typeof useMessage>,
|
||||
i18nT: ReturnType<typeof useI18n>["t"]
|
||||
) {
|
||||
store = globalStore;
|
||||
maskElement = element;
|
||||
message = messageAPI;
|
||||
t = i18nT;
|
||||
|
||||
maskSizeW = maskElement.clientWidth;
|
||||
maskSizeH = maskElement.clientHeight;
|
||||
// listen to resize to update mask size
|
||||
getCurrent()
|
||||
.onResized(() => {
|
||||
maskSizeW = maskElement.clientWidth;
|
||||
maskSizeH = maskElement.clientHeight;
|
||||
})
|
||||
.then((f) => (unlistenResize = f));
|
||||
|
||||
addClickShortcuts("M0", 0);
|
||||
|
||||
return applyKeyMappingConfigShortcuts(keyMappingConfig);
|
||||
}
|
||||
|
||||
let maskSizeW: number;
|
||||
let maskSizeH: number;
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
let store: ReturnType<typeof useGlobalStore>;
|
||||
let maskElement: HTMLElement;
|
||||
let message: ReturnType<typeof useMessage>;
|
||||
let t: ReturnType<typeof useI18n>["t"];
|
||||
|
||||
let unlistenResize: UnlistenFn;
|
||||
|
||||
const downKeyMap: Map<string, boolean> = new Map();
|
||||
const downKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const loopDownKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const upKeyCBMap: Map<string, () => Promise<void>> = new Map();
|
||||
const cancelAbleKeyList: string[] = [];
|
||||
|
@ -14,9 +14,8 @@
|
||||
"screen": "Get screen size"
|
||||
},
|
||||
"deviceControl": {
|
||||
"inputScreenSize": "Please enter the screen size of the current control device correctly",
|
||||
"closeCurDevice": "Please close the current control device first",
|
||||
"controlInfo": "The screen size has been saved and the control service is starting. Please keep the device screen on.",
|
||||
"controlInfo": "The control service is starting. Please keep the device screen on.",
|
||||
"connectTimeout": "Device connection timeout"
|
||||
},
|
||||
"deviceGetScreenSize": "Device screen size: ",
|
||||
@ -25,14 +24,7 @@
|
||||
"wireless": "Wireless connection",
|
||||
"wirelessPlaceholder": "Wireless connection address",
|
||||
"connect": "Connect",
|
||||
"deviceSize": {
|
||||
"title": "Device screen size",
|
||||
"width": "Width",
|
||||
"widthPlaceholder": "Screen width",
|
||||
"height": "Height",
|
||||
"heightPlaceholder": "Screen height",
|
||||
"tip": "Tip: Please enter the screen size of the current control device correctly. This is a necessary parameter to successfully send touch events."
|
||||
},
|
||||
"deviceSize": {},
|
||||
"controledDevice": "Controlled device",
|
||||
"availableDevice": "Available devices",
|
||||
"noControledDevice": "No Controled Device",
|
||||
@ -42,7 +34,8 @@
|
||||
"wsAddress": "Websocket address",
|
||||
"inputWsAddress": "Please enter the Websocket address",
|
||||
"wsClose": "Close",
|
||||
"wsConnect": "Control"
|
||||
"wsConnect": "Control",
|
||||
"adbDeviceError": "Unable to get available devices"
|
||||
},
|
||||
"Mask": {
|
||||
"inputBoxPlaceholder": "Input text and then press enter/esc",
|
||||
@ -62,7 +55,8 @@
|
||||
"content": "Please go to the device page to control any device",
|
||||
"positiveText": "To control"
|
||||
},
|
||||
"sightMode": "Mouse is locked, press {0} to unlock"
|
||||
"sightMode": "Mouse is locked, press {0} to unlock",
|
||||
"checkAdb": "adb is not available and the software cannot run normally. Please ensure that adb is installed on the system and added to the Path environment variable correctly: {0}"
|
||||
},
|
||||
"Setting": {
|
||||
"tabs": {
|
||||
|
@ -13,9 +13,8 @@
|
||||
"screen": "获取屏幕尺寸"
|
||||
},
|
||||
"deviceControl": {
|
||||
"inputScreenSize": "请正确输入当前控制设备的屏幕尺寸",
|
||||
"closeCurDevice": "请先关闭当前控制设备",
|
||||
"controlInfo": "屏幕尺寸已保存,正在启动控制服务,请保持设备亮屏",
|
||||
"controlInfo": "正在启动控制服务,请保持设备亮屏",
|
||||
"connectTimeout": "设备连接超时"
|
||||
},
|
||||
"deviceGetScreenSize": "设备屏幕尺寸为:",
|
||||
@ -25,14 +24,7 @@
|
||||
"wireless": "无线连接",
|
||||
"wirelessPlaceholder": "无线连接地址",
|
||||
"connect": "连接",
|
||||
"deviceSize": {
|
||||
"title": "设备屏幕尺寸",
|
||||
"width": "宽度",
|
||||
"widthPlaceholder": "屏幕宽度",
|
||||
"heightPlaceholder": "屏幕高度",
|
||||
"height": "高度",
|
||||
"tip": "提示:请正确输入当前控制设备的屏幕尺寸,这是成功发送触摸事件的必要参数"
|
||||
},
|
||||
"deviceSize": {},
|
||||
"controledDevice": "受控设备",
|
||||
"noControledDevice": "无受控设备",
|
||||
"availableDevice": "可用设备",
|
||||
@ -42,7 +34,8 @@
|
||||
"externalControl": "外部控制",
|
||||
"wsAddress": "Websocket 地址",
|
||||
"wsClose": "断开",
|
||||
"wsConnect": "控制"
|
||||
"wsConnect": "控制",
|
||||
"adbDeviceError": "无法获取可用设备"
|
||||
},
|
||||
"Mask": {
|
||||
"keyconfigException": "按键方案异常,请删除此方案",
|
||||
@ -62,7 +55,8 @@
|
||||
"positiveText": "去控制"
|
||||
},
|
||||
"inputBoxPlaceholder": "输入文本后按Enter/Esc",
|
||||
"sightMode": "鼠标已锁定, 按 {0} 键解锁"
|
||||
"sightMode": "鼠标已锁定, 按 {0} 键解锁",
|
||||
"checkAdb": "adb不可用,软件无法正常运行,请确保系统已安装adb,并正确添加到了Path环境变量中: {0}"
|
||||
},
|
||||
"Setting": {
|
||||
"tabs": {
|
||||
|
@ -51,4 +51,8 @@ export async function loadDefaultKeyconfig(): Promise<string> {
|
||||
return await invoke("load_default_keyconfig");
|
||||
}
|
||||
|
||||
export async function checkAdbAvailable(): Promise<void>{
|
||||
return await invoke("check_adb_available");
|
||||
}
|
||||
|
||||
export type { Device };
|
||||
|
@ -71,9 +71,10 @@ export const useGlobalStore = defineStore("global", () => {
|
||||
|
||||
const externalControlled = ref(false);
|
||||
|
||||
// persistent storage
|
||||
const screenSizeW: Ref<number> = ref(0);
|
||||
const screenSizeH: Ref<number> = ref(0);
|
||||
|
||||
// persistent storage
|
||||
const keyMappingConfigList: Ref<KeyMappingConfig[]> = ref([]);
|
||||
const curKeyMappingIndex = ref(0);
|
||||
const maskButton = ref({
|
||||
@ -84,14 +85,14 @@ export const useGlobalStore = defineStore("global", () => {
|
||||
|
||||
return {
|
||||
// persistent storage
|
||||
screenSizeW,
|
||||
screenSizeH,
|
||||
keyMappingConfigList,
|
||||
curKeyMappingIndex,
|
||||
maskButton,
|
||||
checkUpdateAtStart,
|
||||
externalControlled,
|
||||
// in-memory storage
|
||||
screenSizeW,
|
||||
screenSizeH,
|
||||
showLoading,
|
||||
hideLoading,
|
||||
showLoadingRef,
|
||||
|
Loading…
Reference in New Issue
Block a user