fix conflicts

This commit is contained in:
Asur4s
2023-01-12 00:35:39 +08:00
244 changed files with 8727 additions and 3173 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -21,7 +21,7 @@ pub use context_send::*;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "t", content = "c")]
pub enum ClipbaordFile {
pub enum ClipboardFile {
MonitorReady,
FormatList {
format_list: Vec<(i32, String)>,
@@ -61,8 +61,8 @@ struct ConnEnabled {
struct MsgChannel {
peer_id: String,
conn_id: i32,
sender: UnboundedSender<ClipbaordFile>,
receiver: Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>>,
sender: UnboundedSender<ClipboardFile>,
receiver: Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>,
}
#[derive(PartialEq)]
@@ -89,7 +89,7 @@ pub fn get_client_conn_id(peer_id: &str) -> Option<i32> {
pub fn get_rx_cliprdr_client(
peer_id: &str,
) -> (i32, Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>>) {
) -> (i32, Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>>) {
let mut lock = VEC_MSG_CHANNEL.write().unwrap();
match lock.iter().find(|x| x.peer_id == peer_id.to_owned()) {
Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()),
@@ -110,7 +110,7 @@ pub fn get_rx_cliprdr_client(
}
}
pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>> {
pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<ClipboardFile>>> {
let mut lock = VEC_MSG_CHANNEL.write().unwrap();
match lock.iter().find(|x| x.conn_id == conn_id) {
Some(msg_channel) => msg_channel.receiver.clone(),
@@ -131,7 +131,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<C
}
#[inline]
fn send_data(conn_id: i32, data: ClipbaordFile) {
fn send_data(conn_id: i32, data: ClipboardFile) {
// no need to handle result here
if let Some(msg_channel) = VEC_MSG_CHANNEL
.read()
@@ -157,28 +157,28 @@ pub fn empty_clipboard(context: &mut Box<CliprdrClientContext>, conn_id: i32) ->
pub fn server_clip_file(
context: &mut Box<CliprdrClientContext>,
conn_id: i32,
msg: ClipbaordFile,
msg: ClipboardFile,
) -> u32 {
match msg {
ClipbaordFile::MonitorReady => {
ClipboardFile::MonitorReady => {
log::debug!("server_monitor_ready called");
let ret = server_monitor_ready(context, conn_id);
log::debug!("server_monitor_ready called, return {}", ret);
ret
}
ClipbaordFile::FormatList { format_list } => {
ClipboardFile::FormatList { format_list } => {
log::debug!("server_format_list called");
let ret = server_format_list(context, conn_id, format_list);
log::debug!("server_format_list called, return {}", ret);
ret
}
ClipbaordFile::FormatListResponse { msg_flags } => {
ClipboardFile::FormatListResponse { msg_flags } => {
log::debug!("format_list_response called");
let ret = server_format_list_response(context, conn_id, msg_flags);
log::debug!("server_format_list_response called, return {}", ret);
ret
}
ClipbaordFile::FormatDataRequest {
ClipboardFile::FormatDataRequest {
requested_format_id,
} => {
log::debug!("format_data_request called");
@@ -186,7 +186,7 @@ pub fn server_clip_file(
log::debug!("server_format_data_request called, return {}", ret);
ret
}
ClipbaordFile::FormatDataResponse {
ClipboardFile::FormatDataResponse {
msg_flags,
format_data,
} => {
@@ -195,7 +195,7 @@ pub fn server_clip_file(
log::debug!("server_format_data_response called, return {}", ret);
ret
}
ClipbaordFile::FileContentsRequest {
ClipboardFile::FileContentsRequest {
stream_id,
list_index,
dw_flags,
@@ -221,7 +221,7 @@ pub fn server_clip_file(
log::debug!("server_file_contents_request called, return {}", ret);
ret
}
ClipbaordFile::FileContentsResponse {
ClipboardFile::FileContentsResponse {
msg_flags,
stream_id,
requested_data,
@@ -492,7 +492,7 @@ extern "C" fn client_format_list(
}
conn_id = (*clip_format_list).connID as i32;
}
let data = ClipbaordFile::FormatList { format_list };
let data = ClipboardFile::FormatList { format_list };
// no need to handle result here
if conn_id == 0 {
VEC_MSG_CHANNEL
@@ -519,7 +519,7 @@ extern "C" fn client_format_list_response(
conn_id = (*format_list_response).connID as i32;
msg_flags = (*format_list_response).msgFlags as i32;
}
let data = ClipbaordFile::FormatListResponse { msg_flags };
let data = ClipboardFile::FormatListResponse { msg_flags };
send_data(conn_id, data);
0
@@ -537,7 +537,7 @@ extern "C" fn client_format_data_request(
conn_id = (*format_data_request).connID as i32;
requested_format_id = (*format_data_request).requestedFormatId as i32;
}
let data = ClipbaordFile::FormatDataRequest {
let data = ClipboardFile::FormatDataRequest {
requested_format_id,
};
// no need to handle result here
@@ -568,7 +568,7 @@ extern "C" fn client_format_data_response(
.to_vec();
}
}
let data = ClipbaordFile::FormatDataResponse {
let data = ClipboardFile::FormatDataResponse {
msg_flags,
format_data,
};
@@ -614,7 +614,7 @@ extern "C" fn client_file_contents_request(
clip_data_id = (*file_contents_request).clipDataId as i32;
}
let data = ClipbaordFile::FileContentsRequest {
let data = ClipboardFile::FileContentsRequest {
stream_id,
list_index,
dw_flags,
@@ -653,7 +653,7 @@ extern "C" fn client_file_contents_response(
.to_vec();
}
}
let data = ClipbaordFile::FileContentsResponse {
let data = ClipboardFile::FileContentsResponse {
msg_flags,
stream_id,
requested_data,

View File

@@ -795,11 +795,11 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData(IDataObject *Thi
}
static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc(IDataObject *This,
FORMATETC *pformatectIn,
FORMATETC *pformatetcIn,
FORMATETC *pformatetcOut)
{
(void)This;
(void)pformatectIn;
(void)pformatetcIn;
if (!pformatetcOut)
return E_INVALIDARG;

View File

@@ -1,7 +1,7 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "gdb",

View File

@@ -22,8 +22,8 @@ appveyor = { repository = "pythoneer/enigo-85xiy" }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
log = "0.4"
rdev = { git = "https://github.com/asur4s/rdev" }
tfc = { git = "https://github.com/asur4s/The-Fat-Controller" }
rdev = { git = "https://github.com/fufesou/rdev" }
tfc = { git = "https://github.com/fufesou/The-Fat-Controller" }
hbb_common = { path = "../hbb_common" }
[features]

View File

@@ -1,9 +1,9 @@
# Appveyor configuration template for Rust using rustup for Rust installation
# AppVeyor configuration template for Rust using rustup for Rust installation
# https://github.com/starkat99/appveyor-rust
## Operating System (VM environment) ##
# Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets.
# Rust needs at least Visual Studio 2013 AppVeyor OS for MSVC targets.
os: Visual Studio 2015
## Build Matrix ##
@@ -83,7 +83,7 @@ environment:
### Allowed failures ###
# See Appveyor documentation for specific details. In short, place any channel or targets you wish
# See AppVeyor documentation for specific details. In short, place any channel or targets you wish
# to allow build failures on (usually nightly at least is a wise choice). This will prevent a build
# or test failure in the matching channels/targets from failing the entire build.
matrix:
@@ -95,7 +95,7 @@ matrix:
## Install Script ##
# This is the most important part of the Appveyor configuration. This installs the version of Rust
# This is the most important part of the AppVeyor configuration. This installs the version of Rust
# specified by the 'channel' and 'target' environment variables from the build matrix. This uses
# rustup to install Rust.
#
@@ -110,7 +110,7 @@ install:
## Build Script ##
# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
# 'cargo test' takes care of building for us, so disable AppVeyor's build stage. This prevents
# the "directory does not contain a project or solution file" error.
build: false

View File

@@ -23,15 +23,18 @@ fn main() {
enigo.mouse_click(MouseButton::Left);
thread::sleep(wait_time);
enigo.mouse_scroll_x(2);
thread::sleep(wait_time);
#[cfg(not(target_os = "macos"))]
{
enigo.mouse_scroll_x(2);
thread::sleep(wait_time);
enigo.mouse_scroll_x(-2);
thread::sleep(wait_time);
enigo.mouse_scroll_x(-2);
thread::sleep(wait_time);
enigo.mouse_scroll_y(2);
thread::sleep(wait_time);
enigo.mouse_scroll_y(2);
thread::sleep(wait_time);
enigo.mouse_scroll_y(-2);
thread::sleep(wait_time);
enigo.mouse_scroll_y(-2);
thread::sleep(wait_time);
}
}

View File

@@ -19,9 +19,9 @@
//! or any other "special" key on the Linux, macOS and Windows operating system.
//!
//! Possible use cases could be for testing user interfaces on different
//! plattforms,
//! platforms,
//! building remote control applications or just automating tasks for user
//! interfaces unaccessible by a public API or scripting laguage.
//! interfaces unaccessible by a public API or scripting language.
//!
//! For the keyboard there are currently two modes you can use. The first mode
//! is represented by the [key_sequence]() function
@@ -104,6 +104,10 @@ pub enum MouseButton {
Middle,
/// Right mouse button
Right,
/// Back mouse button
Back,
/// Forward mouse button
Forward,
/// Scroll up button
ScrollUp,
@@ -202,7 +206,7 @@ pub trait MouseControllable {
/// Click a mouse button
///
/// it's esentially just a consecutive invokation of
/// it's essentially just a consecutive invocation of
/// [mouse_down](trait.MouseControllable.html#tymethod.mouse_down) followed
/// by a [mouse_up](trait.MouseControllable.html#tymethod.mouse_up). Just
/// for
@@ -447,8 +451,9 @@ pub trait KeyboardControllable {
where
Self: Sized,
{
self.key_sequence_parse_try(sequence)
.expect("Could not parse sequence");
if let Err(..) = self.key_sequence_parse_try(sequence) {
println!("Could not parse sequence");
}
}
/// Same as key_sequence_parse except returns any errors
fn key_sequence_parse_try(&mut self, sequence: &str) -> Result<(), dsl::ParseError>
@@ -463,7 +468,7 @@ pub trait KeyboardControllable {
/// Emits keystrokes such that the given string is inputted.
///
/// You can use many unicode here like: ❤️. This works
/// regadless of the current keyboardlayout.
/// regardless of the current keyboardlayout.
///
/// # Example
///

View File

@@ -13,7 +13,7 @@ pub struct Enigo {
is_x11: bool,
tfc: Option<TFC_Context>,
custom_keyboard: Option<CustomKeyboard>,
cutsom_mouse: Option<CustomMouce>,
custom_mouse: Option<CustomMouce>,
}
impl Enigo {
@@ -21,7 +21,7 @@ impl Enigo {
pub fn delay(&self) -> u64 {
self.xdo.delay()
}
/// Set delay of xdo implemetation.
/// Set delay of xdo implementation.
pub fn set_delay(&mut self, delay: u64) {
self.xdo.set_delay(delay)
}
@@ -31,7 +31,7 @@ impl Enigo {
}
/// Set custom mouse.
pub fn set_custom_mouse(&mut self, custom_mouse: CustomMouce) {
self.cutsom_mouse = Some(custom_mouse)
self.custom_mouse = Some(custom_mouse)
}
/// Get custom keyboard.
pub fn get_custom_keyboard(&mut self) -> &mut Option<CustomKeyboard> {
@@ -39,7 +39,7 @@ impl Enigo {
}
/// Get custom mouse.
pub fn get_custom_mouse(&mut self) -> &mut Option<CustomMouce> {
&mut self.cutsom_mouse
&mut self.custom_mouse
}
fn tfc_key_down_or_up(&mut self, key: Key, down: bool, up: bool) -> bool {
@@ -88,12 +88,18 @@ impl Default for Enigo {
Self {
is_x11,
tfc: if is_x11 {
Some(TFC_Context::new().expect("kbd context error"))
match TFC_Context::new() {
Ok(ctx) => Some(ctx),
Err(..) => {
println!("kbd context error");
None
}
}
} else {
None
},
custom_keyboard: None,
cutsom_mouse: None,
custom_mouse: None,
xdo: EnigoXdo::default(),
}
}
@@ -112,7 +118,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_move_to(x, y);
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_move_to(x, y)
}
}
@@ -121,7 +127,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_move_relative(x, y);
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_move_relative(x, y)
}
}
@@ -130,7 +136,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_down(button)
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_down(button)
} else {
Ok(())
@@ -141,7 +147,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_up(button)
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_up(button)
}
}
@@ -150,7 +156,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_click(button)
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_click(button)
}
}
@@ -159,7 +165,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_scroll_x(length)
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_scroll_x(length)
}
}
@@ -168,7 +174,7 @@ impl MouseControllable for Enigo {
if self.is_x11 {
self.xdo.mouse_scroll_y(length)
} else {
if let Some(mouse) = &mut self.cutsom_mouse {
if let Some(mouse) = &mut self.custom_mouse {
mouse.mouse_scroll_y(length)
}
}
@@ -177,6 +183,7 @@ impl MouseControllable for Enigo {
fn get_led_state(key: Key) -> bool {
let led_file = match key {
// FIXME: the file may be /sys/class/leds/input2 or input5 ...
Key::CapsLock => "/sys/class/leds/input1::capslock/brightness",
Key::NumLock => "/sys/class/leds/input1::numlock/brightness",
_ => {

View File

@@ -57,6 +57,8 @@ fn mousebutton(button: MouseButton) -> c_int {
MouseButton::ScrollDown => 5,
MouseButton::ScrollLeft => 6,
MouseButton::ScrollRight => 7,
MouseButton::Back => 8,
MouseButton::Forward => 9,
}
}
@@ -391,8 +393,9 @@ impl KeyboardControllable for EnigoXdo {
where
Self: Sized,
{
self.key_sequence_parse_try(sequence)
.expect("Could not parse sequence");
if let Err(..) = self.key_sequence_parse_try(sequence) {
println!("Could not parse sequence");
}
}
fn key_sequence_parse_try(&mut self, sequence: &str) -> Result<(), crate::dsl::ParseError>

View File

@@ -40,6 +40,7 @@ const BUF_LEN: usize = 4;
#[allow(improper_ctypes)]
#[allow(non_snake_case)]
#[link(name = "ApplicationServices", kind = "framework")]
#[link(name = "Carbon", kind = "framework")]
extern "C" {
fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8;
fn TISCopyCurrentKeyboardInputSource() -> TISInputSourceRef;
@@ -68,7 +69,7 @@ extern "C" {
) -> Boolean;
fn CGEventPost(tapLocation: CGEventTapLocation, event: *mut MyCGEvent);
// Actually return CFDataRef which is const here, but for coding convienence, return *mut c_void
// Actually return CFDataRef which is const here, but for coding convenience, return *mut c_void
fn TISGetInputSourceProperty(source: TISInputSourceRef, property: *const c_void)
-> *mut c_void;
// not present in servo/core-graphics
@@ -225,7 +226,10 @@ impl MouseControllable for Enigo {
MouseButton::Left => (CGMouseButton::Left, CGEventType::LeftMouseDown),
MouseButton::Middle => (CGMouseButton::Center, CGEventType::OtherMouseDown),
MouseButton::Right => (CGMouseButton::Right, CGEventType::RightMouseDown),
_ => unimplemented!(),
_ => {
log::info!("Unsupported button {:?}", button);
return Ok(());
},
};
let dest = CGPoint::new(current_x as f64, current_y as f64);
if let Some(src) = self.event_source.as_ref() {
@@ -248,7 +252,10 @@ impl MouseControllable for Enigo {
MouseButton::Left => (CGMouseButton::Left, CGEventType::LeftMouseUp),
MouseButton::Middle => (CGMouseButton::Center, CGEventType::OtherMouseUp),
MouseButton::Right => (CGMouseButton::Right, CGEventType::RightMouseUp),
_ => unimplemented!(),
_ => {
log::info!("Unsupported button {:?}", button);
return;
},
};
let dest = CGPoint::new(current_x as f64, current_y as f64);
if let Some(src) = self.event_source.as_ref() {

View File

@@ -56,6 +56,20 @@ fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
input.type_ = INPUT_KEYBOARD;
unsafe {
let dst_ptr = (&mut input.u as *mut _) as *mut u8;
let flags = match vk as _ {
winapi::um::winuser::VK_HOME |
winapi::um::winuser::VK_UP |
winapi::um::winuser::VK_PRIOR |
winapi::um::winuser::VK_LEFT |
winapi::um::winuser::VK_RIGHT |
winapi::um::winuser::VK_END |
winapi::um::winuser::VK_DOWN |
winapi::um::winuser::VK_NEXT |
winapi::um::winuser::VK_INSERT |
winapi::um::winuser::VK_DELETE => flags | winapi::um::winuser::KEYEVENTF_EXTENDEDKEY,
_ => flags,
};
let k = KEYBDINPUT {
wVk: vk,
wScan: scan,
@@ -134,9 +148,18 @@ impl MouseControllable for Enigo {
MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
_ => unimplemented!(),
MouseButton::Back => MOUSEEVENTF_XDOWN,
MouseButton::Forward => MOUSEEVENTF_XDOWN,
_ => {
log::info!("Unsupported button {:?}", button);
return Ok(());
}
},
match button {
MouseButton::Back => XBUTTON1 as _,
MouseButton::Forward => XBUTTON2 as _,
_ => 0,
},
0,
0,
0,
);
@@ -155,9 +178,18 @@ impl MouseControllable for Enigo {
MouseButton::Left => MOUSEEVENTF_LEFTUP,
MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
MouseButton::Right => MOUSEEVENTF_RIGHTUP,
_ => unimplemented!(),
MouseButton::Back => MOUSEEVENTF_XUP,
MouseButton::Forward => MOUSEEVENTF_XUP,
_ => {
log::info!("Unsupported button {:?}", button);
return;
}
},
match button {
MouseButton::Back => XBUTTON1 as _,
MouseButton::Forward => XBUTTON2 as _,
_ => 0,
},
0,
0,
0,
);

View File

@@ -40,7 +40,7 @@ message DisplayInfo {
int32 height = 4;
string name = 5;
bool online = 6;
bool cursor_embeded = 7;
bool cursor_embedded = 7;
}
message PortForward {
@@ -420,7 +420,7 @@ message SwitchDisplay {
sint32 y = 3;
int32 width = 4;
int32 height = 5;
bool cursor_embeded = 6;
bool cursor_embedded = 6;
}
message PermissionInfo {
@@ -445,7 +445,7 @@ enum ImageQuality {
}
message VideoCodecState {
enum PerferCodec {
enum PreferCodec {
Auto = 0;
VPX = 1;
H264 = 2;
@@ -455,7 +455,7 @@ message VideoCodecState {
int32 score_vpx = 1;
int32 score_h264 = 2;
int32 score_h265 = 3;
PerferCodec perfer = 4;
PreferCodec prefer = 4;
}
message OptionMessage {
@@ -503,7 +503,7 @@ message AudioFrame {
// Notify peer to show message box.
message MessageBox {
// Message type. Refer to flutter/lib/commom.dart/msgBox().
// Message type. Refer to flutter/lib/common.dart/msgBox().
string msgtype = 1;
string title = 2;
// English

View File

@@ -1,7 +1,7 @@
use std::{
collections::HashMap,
fs,
net::{IpAddr, Ipv4Addr, SocketAddr},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
path::{Path, PathBuf},
sync::{Arc, Mutex, RwLock},
time::SystemTime,
@@ -511,8 +511,12 @@ impl Config {
}
#[inline]
pub fn get_any_listen_addr() -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
pub fn get_any_listen_addr(is_ipv4: bool) -> SocketAddr {
if is_ipv4 {
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
} else {
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
}
}
pub fn get_rendezvous_server() -> String {
@@ -993,6 +997,8 @@ pub struct LocalConfig {
#[serde(default)]
remote_id: String, // latest used one
#[serde(default)]
kb_layout_type: String,
#[serde(default)]
size: Size,
#[serde(default)]
pub fav: Vec<String>,
@@ -1012,6 +1018,16 @@ impl LocalConfig {
Config::store_(self, "_local");
}
pub fn get_kb_layout_type() -> String {
LOCAL_CONFIG.read().unwrap().kb_layout_type.clone()
}
pub fn set_kb_layout_type(kb_layout_type: String) {
let mut config = LOCAL_CONFIG.write().unwrap();
config.kb_layout_type = kb_layout_type;
config.store();
}
pub fn get_size() -> Size {
LOCAL_CONFIG.read().unwrap().size
}

View File

@@ -578,7 +578,7 @@ impl TransferJob {
///
/// [`Note`]
/// Conditions:
/// 1. Files are not waiting for comfirmation by peers.
/// 1. Files are not waiting for confirmation by peers.
#[inline]
pub fn job_completed(&self) -> bool {
// has no error, Condition 2

View File

@@ -10,7 +10,7 @@ pub use protos::rendezvous as rendezvous_proto;
use std::{
fs::File,
io::{self, BufRead},
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
path::Path,
time::{self, SystemTime, UNIX_EPOCH},
};
@@ -67,6 +67,21 @@ macro_rules! allow_err {
} else {
}
};
($e:expr, $($arg:tt)*) => {
if let Err(err) = $e {
log::debug!(
"{:?}, {}, {}:{}:{}:{}",
err,
format_args!($($arg)*),
module_path!(),
file!(),
line!(),
column!()
);
} else {
}
};
}
#[inline]
@@ -103,13 +118,31 @@ impl AddrMangle {
}
bytes[..(16 - n_padding)].to_vec()
}
_ => {
panic!("Only support ipv4");
SocketAddr::V6(addr_v6) => {
let mut x = addr_v6.ip().octets().to_vec();
let port: [u8; 2] = addr_v6.port().to_le_bytes();
x.push(port[0]);
x.push(port[1]);
x
}
}
}
pub fn decode(bytes: &[u8]) -> SocketAddr {
if bytes.len() > 16 {
if bytes.len() != 18 {
return Config::get_any_listen_addr(false);
}
#[allow(invalid_value)]
let mut tmp: [u8; 2] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
tmp.copy_from_slice(&bytes[16..]);
let port = u16::from_le_bytes(tmp);
#[allow(invalid_value)]
let mut tmp: [u8; 16] = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
tmp.copy_from_slice(&bytes[..16]);
let ip = std::net::Ipv6Addr::from(tmp);
return SocketAddr::new(IpAddr::V6(ip), port);
}
let mut padded = [0u8; 16];
padded[..bytes.len()].copy_from_slice(&bytes);
let number = u128::from_le_bytes(padded);
@@ -250,5 +283,61 @@ mod tests {
fn test_mangle() {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8::1]:8080".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
let addr = "[2001:db8:ff::1111]:80".parse::<SocketAddr>().unwrap();
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
}
#[test]
fn test_allow_err() {
allow_err!(Err("test err") as Result<(), &str>);
allow_err!(
Err("test err with msg") as Result<(), &str>,
"prompt {}",
"failed"
);
}
}
#[inline]
pub fn is_ipv4_str(id: &str) -> bool {
regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+(:\d+)?$")
.unwrap()
.is_match(id)
}
#[inline]
pub fn is_ipv6_str(id: &str) -> bool {
regex::Regex::new(r"^((([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4})|(\[([a-fA-F0-9]{1,4}:{1,2})+[a-fA-F0-9]{1,4}\]:\d+))$")
.unwrap()
.is_match(id)
}
#[inline]
pub fn is_ip_str(id: &str) -> bool {
is_ipv4_str(id) || is_ipv6_str(id)
}
#[cfg(test)]
mod test_lib {
use super::*;
#[test]
fn test_ipv6() {
assert_eq!(is_ipv6_str("1:2:3"), true);
assert_eq!(is_ipv6_str("[ab:2:3]:12"), true);
assert_eq!(is_ipv6_str("[ABEF:2a:3]:12"), true);
assert_eq!(is_ipv6_str("[ABEG:2a:3]:12"), false);
assert_eq!(is_ipv6_str("1[ab:2:3]:12"), false);
assert_eq!(is_ipv6_str("1.1.1.1"), false);
assert_eq!(is_ip_str("1.1.1.1"), true);
assert_eq!(is_ipv6_str("1:2:"), false);
assert_eq!(is_ipv6_str("1:2::0"), true);
assert_eq!(is_ipv6_str("[1:2::0]:1"), true);
assert_eq!(is_ipv6_str("[1:2::0]:"), false);
assert_eq!(is_ipv6_str("1:2::0]:1"), false);
}
}

View File

@@ -1,15 +1,15 @@
use crate::ResultType;
lazy_static::lazy_static! {
pub static ref DISTRO: Disto = Disto::new();
pub static ref DISTRO: Distro = Distro::new();
}
pub struct Disto {
pub struct Distro {
pub name: String,
pub version_id: String,
}
impl Disto {
impl Distro {
fn new() -> Self {
let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release".to_owned())
.unwrap_or_default()
@@ -74,7 +74,7 @@ fn get_display_server_of_session(session: &str) -> String {
} else {
"".to_owned()
};
if display_server.is_empty() {
if display_server.is_empty() || display_server == "tty" {
// loginctl has not given the expected output. try something else.
if let Ok(sestype) = std::env::var("XDG_SESSION_TYPE") {
display_server = sestype;

View File

@@ -9,31 +9,52 @@ use std::net::SocketAddr;
use tokio::net::ToSocketAddrs;
use tokio_socks::{IntoTargetAddr, TargetAddr};
fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
use std::net::ToSocketAddrs;
host.to_socket_addrs()?
.filter(|x| x.is_ipv4())
.next()
.context("Failed to solve")
#[inline]
pub fn check_port<T: std::string::ToString>(host: T, port: i32) -> String {
let host = host.to_string();
if crate::is_ipv6_str(&host) {
if host.starts_with("[") {
return host;
}
return format!("[{}]:{}", host, port);
}
if !host.contains(":") {
return format!("{}:{}", host, port);
}
return host;
}
pub fn get_target_addr(host: &str) -> ResultType<TargetAddr<'static>> {
let addr = match Config::get_network_type() {
NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?,
NetworkType::ProxySocks => host.into_target_addr()?,
#[inline]
pub fn increase_port<T: std::string::ToString>(host: T, offset: i32) -> String {
let host = host.to_string();
if crate::is_ipv6_str(&host) {
if host.starts_with("[") {
let tmp: Vec<&str> = host.split("]:").collect();
if tmp.len() == 2 {
let port: i32 = tmp[1].parse().unwrap_or(0);
if port > 0 {
return format!("{}]:{}", tmp[0], port + offset);
}
}
}
} else if host.contains(":") {
let tmp: Vec<&str> = host.split(":").collect();
if tmp.len() == 2 {
let port: i32 = tmp[1].parse().unwrap_or(0);
if port > 0 {
return format!("{}:{}", tmp[0], port + offset);
}
}
}
.to_owned();
Ok(addr)
return host;
}
pub fn test_if_valid_server(host: &str) -> String {
let mut host = host.to_owned();
if !host.contains(":") {
host = format!("{}:{}", host, 0);
}
let host = check_port(host, 0);
use std::net::ToSocketAddrs;
match Config::get_network_type() {
NetworkType::Direct => match to_socket_addr(&host) {
NetworkType::Direct => match host.to_socket_addrs() {
Err(err) => err.to_string(),
Ok(_) => "".to_owned(),
},
@@ -44,33 +65,126 @@ pub fn test_if_valid_server(host: &str) -> String {
}
}
pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>(
pub trait IsResolvedSocketAddr {
fn resolve(&self) -> Option<&SocketAddr>;
}
impl IsResolvedSocketAddr for SocketAddr {
fn resolve(&self) -> Option<&SocketAddr> {
Some(&self)
}
}
impl IsResolvedSocketAddr for String {
fn resolve(&self) -> Option<&SocketAddr> {
None
}
}
impl IsResolvedSocketAddr for &str {
fn resolve(&self) -> Option<&SocketAddr> {
None
}
}
#[inline]
pub async fn connect_tcp<
't,
T: IntoTargetAddr<'t> + ToSocketAddrs + IsResolvedSocketAddr + std::fmt::Display,
>(
target: T,
local: SocketAddr,
ms_timeout: u64,
) -> ResultType<FramedStream> {
let target_addr = target.into_target_addr()?;
connect_tcp_local(target, None, ms_timeout).await
}
pub async fn connect_tcp_local<
't,
T: IntoTargetAddr<'t> + ToSocketAddrs + IsResolvedSocketAddr + std::fmt::Display,
>(
target: T,
local: Option<SocketAddr>,
ms_timeout: u64,
) -> ResultType<FramedStream> {
if let Some(conf) = Config::get_socks() {
FramedStream::connect(
return FramedStream::connect(
conf.proxy.as_str(),
target_addr,
target,
local,
conf.username.as_str(),
conf.password.as_str(),
ms_timeout,
)
.await
} else {
let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?
.filter(|x| x.is_ipv4())
.next()
.context("Invalid target addr, no valid ipv4 address can be resolved.")?;
Ok(FramedStream::new(addr, local, ms_timeout).await?)
.await;
}
if let Some(target) = target.resolve() {
if let Some(local) = local {
if local.is_ipv6() && target.is_ipv4() {
let target = query_nip_io(&target).await?;
return Ok(FramedStream::new(target, Some(local), ms_timeout).await?);
}
}
}
Ok(FramedStream::new(target, local, ms_timeout).await?)
}
#[inline]
pub fn is_ipv4(target: &TargetAddr<'_>) -> bool {
match target {
TargetAddr::Ip(addr) => addr.is_ipv4(),
_ => true,
}
}
pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
#[inline]
pub async fn query_nip_io(addr: &SocketAddr) -> ResultType<SocketAddr> {
tokio::net::lookup_host(format!("{}.nip.io:{}", addr.ip(), addr.port()))
.await?
.filter(|x| x.is_ipv6())
.next()
.context("Failed to get ipv6 from nip.io")
}
#[inline]
pub fn ipv4_to_ipv6(addr: String, ipv4: bool) -> String {
if !ipv4 && crate::is_ipv4_str(&addr) {
if let Some(ip) = addr.split(":").next() {
return addr.replace(ip, &format!("{}.nip.io", ip));
}
}
addr
}
async fn test_target(target: &str) -> ResultType<SocketAddr> {
if let Ok(Ok(s)) = super::timeout(1000, tokio::net::TcpStream::connect(target)).await {
if let Ok(addr) = s.peer_addr() {
return Ok(addr);
}
}
tokio::net::lookup_host(target)
.await?
.next()
.context(format!("Failed to look up host for {}", target))
}
#[inline]
pub async fn new_udp_for(
target: &str,
ms_timeout: u64,
) -> ResultType<(FramedSocket, TargetAddr<'static>)> {
let (ipv4, target) = if NetworkType::Direct == Config::get_network_type() {
let addr = test_target(target).await?;
(addr.is_ipv4(), addr.into_target_addr()?)
} else {
(true, target.into_target_addr()?)
};
Ok((
new_udp(Config::get_any_listen_addr(ipv4), ms_timeout).await?,
target.to_owned(),
))
}
async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
match Config::get_socks() {
None => Ok(FramedSocket::new(local).await?),
Some(conf) => {
@@ -87,9 +201,82 @@ pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<
}
}
pub async fn rebind_udp<T: ToSocketAddrs>(local: T) -> ResultType<Option<FramedSocket>> {
match Config::get_network_type() {
NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)),
_ => Ok(None),
pub async fn rebind_udp_for(
target: &str,
) -> ResultType<Option<(FramedSocket, TargetAddr<'static>)>> {
if Config::get_network_type() != NetworkType::Direct {
return Ok(None);
}
let addr = test_target(target).await?;
let v4 = addr.is_ipv4();
Ok(Some((
FramedSocket::new(Config::get_any_listen_addr(v4)).await?,
addr.into_target_addr()?.to_owned(),
)))
}
#[cfg(test)]
mod tests {
use std::net::ToSocketAddrs;
use super::*;
#[test]
fn test_nat64() {
test_nat64_async();
}
#[tokio::main(flavor = "current_thread")]
async fn test_nat64_async() {
assert_eq!(ipv4_to_ipv6("1.1.1.1".to_owned(), true), "1.1.1.1");
assert_eq!(ipv4_to_ipv6("1.1.1.1".to_owned(), false), "1.1.1.1.nip.io");
assert_eq!(
ipv4_to_ipv6("1.1.1.1:8080".to_owned(), false),
"1.1.1.1.nip.io:8080"
);
assert_eq!(
ipv4_to_ipv6("rustdesk.com".to_owned(), false),
"rustdesk.com"
);
if ("rustdesk.com:80")
.to_socket_addrs()
.unwrap()
.next()
.unwrap()
.is_ipv6()
{
assert!(query_nip_io(&"1.1.1.1:80".parse().unwrap())
.await
.unwrap()
.is_ipv6());
return;
}
assert!(query_nip_io(&"1.1.1.1:80".parse().unwrap()).await.is_err());
}
#[test]
fn test_test_if_valid_server() {
assert!(!test_if_valid_server("a").is_empty());
// on Linux, "1" is resolved to "0.0.0.1"
assert!(test_if_valid_server("1.1.1.1").is_empty());
assert!(test_if_valid_server("1.1.1.1:1").is_empty());
}
#[test]
fn test_check_port() {
assert_eq!(check_port("[1:2]:12", 32), "[1:2]:12");
assert_eq!(check_port("1:2", 32), "[1:2]:32");
assert_eq!(check_port("z1:2", 32), "z1:2");
assert_eq!(check_port("1.1.1.1", 32), "1.1.1.1:32");
assert_eq!(check_port("1.1.1.1:32", 32), "1.1.1.1:32");
assert_eq!(check_port("test.com:32", 0), "test.com:32");
assert_eq!(increase_port("[1:2]:12", 1), "[1:2]:13");
assert_eq!(increase_port("1.2.2.4:12", 1), "1.2.2.4:13");
assert_eq!(increase_port("1.2.2.4", 1), "1.2.2.4");
assert_eq!(increase_port("test.com", 1), "test.com");
assert_eq!(increase_port("test.com:13", 4), "test.com:17");
assert_eq!(increase_port("1:13", 4), "1:13");
assert_eq!(increase_port("22:1:13", 4), "22:1:13");
assert_eq!(increase_port("z1:2", 1), "z1:3");
}
}

View File

@@ -5,7 +5,7 @@ use protobuf::Message;
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
use std::{
io::{self, Error, ErrorKind},
net::SocketAddr,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
@@ -73,73 +73,79 @@ fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std:
}
impl FramedStream {
pub async fn new<T1: ToSocketAddrs, T2: ToSocketAddrs>(
remote_addr: T1,
local_addr: T2,
pub async fn new<T: ToSocketAddrs + std::fmt::Display>(
remote_addr: T,
local_addr: Option<SocketAddr>,
ms_timeout: u64,
) -> ResultType<Self> {
for local_addr in lookup_host(&local_addr).await? {
for remote_addr in lookup_host(&remote_addr).await? {
let stream = super::timeout(
ms_timeout,
new_socket(local_addr, true)?.connect(remote_addr),
)
.await??;
stream.set_nodelay(true).ok();
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
for remote_addr in lookup_host(&remote_addr).await? {
let local = if let Some(addr) = local_addr {
addr
} else {
crate::config::Config::get_any_listen_addr(remote_addr.is_ipv4())
};
if let Ok(socket) = new_socket(local, true) {
if let Ok(Ok(stream)) =
super::timeout(ms_timeout, socket.connect(remote_addr)).await
{
stream.set_nodelay(true).ok();
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
}
}
}
bail!("could not resolve to any address");
bail!(format!("Failed to connect to {}", remote_addr));
}
pub async fn connect<'a, 't, P, T1, T2>(
pub async fn connect<'a, 't, P, T>(
proxy: P,
target: T1,
local: T2,
target: T,
local_addr: Option<SocketAddr>,
username: &'a str,
password: &'a str,
ms_timeout: u64,
) -> ResultType<Self>
where
P: ToProxyAddrs,
T1: IntoTargetAddr<'t>,
T2: ToSocketAddrs,
T: IntoTargetAddr<'t>,
{
if let Some(local) = lookup_host(&local).await?.next() {
if let Some(proxy) = proxy.to_proxy_addrs().next().await {
let stream =
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??;
stream.set_nodelay(true).ok();
let stream = if username.trim().is_empty() {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_socket(stream, target),
)
.await??
} else {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_password_and_socket(
stream, target, username, password,
),
)
.await??
};
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
if let Some(Ok(proxy)) = proxy.to_proxy_addrs().next().await {
let local = if let Some(addr) = local_addr {
addr
} else {
crate::config::Config::get_any_listen_addr(proxy.is_ipv4())
};
};
let stream =
super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy)).await??;
stream.set_nodelay(true).ok();
let stream = if username.trim().is_empty() {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_socket(stream, target),
)
.await??
} else {
super::timeout(
ms_timeout,
Socks5Stream::connect_with_password_and_socket(
stream, target, username, password,
),
)
.await??
};
let addr = stream.local_addr()?;
return Ok(Self(
Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
addr,
None,
0,
));
}
bail!("could not resolve to any address");
}
@@ -252,6 +258,38 @@ pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<
}
}
pub async fn listen_any(port: u16) -> ResultType<TcpListener> {
if let Ok(mut socket) = TcpSocket::new_v6() {
#[cfg(unix)]
{
use std::os::unix::io::{FromRawFd, IntoRawFd};
let raw_fd = socket.into_raw_fd();
let sock2 = unsafe { socket2::Socket::from_raw_fd(raw_fd) };
sock2.set_only_v6(false).ok();
socket = unsafe { TcpSocket::from_raw_fd(sock2.into_raw_fd()) };
}
#[cfg(windows)]
{
use std::os::windows::prelude::{FromRawSocket, IntoRawSocket};
let raw_socket = socket.into_raw_socket();
let sock2 = unsafe { socket2::Socket::from_raw_socket(raw_socket) };
sock2.set_only_v6(false).ok();
socket = unsafe { TcpSocket::from_raw_socket(sock2.into_raw_socket()) };
}
if socket
.bind(SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port))
.is_ok()
{
if let Ok(l) = socket.listen(DEFAULT_BACKLOG) {
return Ok(l);
}
}
}
let s = TcpSocket::new_v4()?;
s.bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port))?;
Ok(s.listen(DEFAULT_BACKLOG)?)
}
impl Unpin for DynTcpStream {}
impl AsyncRead for DynTcpStream {

View File

@@ -49,7 +49,7 @@ impl FramedSocket {
#[allow(clippy::never_loop)]
pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
for addr in addr.to_socket_addrs()?.filter(|x| x.is_ipv4()) {
for addr in addr.to_socket_addrs()? {
let socket = new_socket(addr, true, 0)?.into_udp_socket();
return Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(socket)?,
@@ -63,7 +63,7 @@ impl FramedSocket {
addr: T,
buf_size: usize,
) -> ResultType<Self> {
for addr in addr.to_socket_addrs()?.filter(|x| x.is_ipv4()) {
for addr in addr.to_socket_addrs()? {
return Ok(Self::Direct(UdpFramed::new(
UdpSocket::from_std(new_socket(addr, false, buf_size)?.into_udp_socket())?,
BytesCodec::new(),
@@ -164,4 +164,13 @@ impl FramedSocket {
None
}
}
pub fn is_ipv4(&self) -> bool {
if let FramedSocket::Direct(x) = self {
if let Ok(v) = x.get_ref().local_addr() {
return v.is_ipv4();
}
}
true
}
}

View File

@@ -4,7 +4,10 @@ use std::{
path::PathBuf,
};
#[cfg(windows)]
const BIN_DATA: &[u8] = include_bytes!("../data.bin");
#[cfg(not(windows))]
const BIN_DATA: &[u8] = &[];
// 4bytes
const LENGTH: usize = 4;
const IDENTIFIER_LENGTH: usize = 8;
@@ -71,7 +74,7 @@ impl BinaryReader {
assert!(BIN_DATA.len() > IDENTIFIER_LENGTH, "bin data invalid!");
let mut iden = String::from_utf8_lossy(&BIN_DATA[base..base + IDENTIFIER_LENGTH]);
if iden != "rustdesk" {
panic!("bin file is not vaild!");
panic!("bin file is not valid!");
}
base += IDENTIFIER_LENGTH;
loop {
@@ -118,7 +121,7 @@ impl BinaryReader {
(parsed, executable)
}
#[cfg(unix)]
#[cfg(linux)]
pub fn configure_permission(&self, prefix: &PathBuf) {
use std::os::unix::prelude::PermissionsExt;

View File

@@ -30,7 +30,7 @@ fn setup(reader: BinaryReader, dir: Option<PathBuf>, clear: bool) -> Option<Path
for file in reader.files.iter() {
file.write_to_file(&dir);
}
#[cfg(unix)]
#[cfg(linux)]
reader.configure_permission(&dir);
Some(dir.join(&reader.exe))
}

View File

@@ -13,7 +13,7 @@ lazy_static! {
pub struct Capturer {
display: Display,
bgra: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {

View File

@@ -23,7 +23,7 @@ use hbb_common::{
use hbb_common::{
config::{Config2, PeerConfig},
lazy_static,
message_proto::video_codec_state::PerferCodec,
message_proto::video_codec_state::PreferCodec,
};
#[cfg(feature = "hwcodec")]
@@ -149,29 +149,29 @@ impl Encoder {
&& states.iter().all(|(_, s)| s.score_h265 > 0);
// Preference first
let mut preference = PerferCodec::Auto;
let mut preference = PreferCodec::Auto;
let preferences: Vec<_> = states
.iter()
.filter(|(_, s)| {
s.perfer == PerferCodec::VPX.into()
|| s.perfer == PerferCodec::H264.into() && enabled_h264
|| s.perfer == PerferCodec::H265.into() && enabled_h265
s.prefer == PreferCodec::VPX.into()
|| s.prefer == PreferCodec::H264.into() && enabled_h264
|| s.prefer == PreferCodec::H265.into() && enabled_h265
})
.map(|(_, s)| s.perfer)
.map(|(_, s)| s.prefer)
.collect();
if preferences.len() > 0 && preferences.iter().all(|&p| p == preferences[0]) {
preference = preferences[0].enum_value_or(PerferCodec::Auto);
preference = preferences[0].enum_value_or(PreferCodec::Auto);
}
match preference {
PerferCodec::VPX => *name.lock().unwrap() = None,
PerferCodec::H264 => {
PreferCodec::VPX => *name.lock().unwrap() = None,
PreferCodec::H264 => {
*name.lock().unwrap() = best.h264.map_or(None, |c| Some(c.name))
}
PerferCodec::H265 => {
PreferCodec::H265 => {
*name.lock().unwrap() = best.h265.map_or(None, |c| Some(c.name))
}
PerferCodec::Auto => {
PreferCodec::Auto => {
// score encoder
let mut score_vpx = SCORE_VPX;
let mut score_h264 = best.h264.as_ref().map_or(0, |c| c.score);
@@ -218,7 +218,7 @@ impl Encoder {
#[inline]
pub fn current_hw_encoder_name() -> Option<String> {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
return HwEncoder::current_name().lock().unwrap().clone();
} else {
return None;
@@ -229,7 +229,7 @@ impl Encoder {
pub fn supported_encoding() -> (bool, bool) {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let best = HwEncoder::best();
(
best.h264.as_ref().map_or(false, |c| c.score > 0),
@@ -246,18 +246,18 @@ impl Encoder {
impl Decoder {
pub fn video_codec_state(_id: &str) -> VideoCodecState {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let best = HwDecoder::best();
return VideoCodecState {
score_vpx: SCORE_VPX,
score_h264: best.h264.map_or(0, |c| c.score),
score_h265: best.h265.map_or(0, |c| c.score),
perfer: Self::codec_preference(_id).into(),
prefer: Self::codec_preference(_id).into(),
..Default::default()
};
}
#[cfg(feature = "mediacodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let score_h264 = if H264_DECODER_SUPPORT.load(std::sync::atomic::Ordering::SeqCst) {
92
} else {
@@ -272,7 +272,7 @@ impl Decoder {
score_vpx: SCORE_VPX,
score_h264,
score_h265,
perfer: Self::codec_preference(_id).into(),
prefer: Self::codec_preference(_id).into(),
..Default::default()
};
}
@@ -287,11 +287,19 @@ impl Decoder {
Decoder {
vpx,
#[cfg(feature = "hwcodec")]
hw: HwDecoder::new_decoders(),
hw: if enable_hwcodec_option() {
HwDecoder::new_decoders()
} else {
HwDecoders::default()
},
#[cfg(feature = "hwcodec")]
i420: vec![],
#[cfg(feature = "mediacodec")]
media_codec: MediaCodecDecoder::new_decoders(),
media_codec: if enable_hwcodec_option() {
MediaCodecDecoder::new_decoders()
} else {
MediaCodecDecoders::default()
},
}
}
@@ -397,25 +405,25 @@ impl Decoder {
}
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
fn codec_preference(id: &str) -> PerferCodec {
fn codec_preference(id: &str) -> PreferCodec {
let codec = PeerConfig::load(id)
.options
.get("codec-preference")
.map_or("".to_owned(), |c| c.to_owned());
if codec == "vp9" {
PerferCodec::VPX
PreferCodec::VPX
} else if codec == "h264" {
PerferCodec::H264
PreferCodec::H264
} else if codec == "h265" {
PerferCodec::H265
PreferCodec::H265
} else {
PerferCodec::Auto
PreferCodec::Auto
}
}
}
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
fn check_hwcodec_config() -> bool {
fn enable_hwcodec_option() -> bool {
if let Some(v) = Config2::get().options.get("enable-hwcodec") {
return v != "N";
}

View File

@@ -16,7 +16,7 @@ use hwcodec::{
ffmpeg::{CodecInfo, CodecInfos, DataFormat},
AVPixelFormat,
Quality::{self, *},
RateContorl::{self, *},
RateControl::{self, *},
};
use std::sync::{Arc, Mutex};
@@ -31,7 +31,7 @@ const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_YUV420P;
pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30];
const DEFAULT_GOP: i32 = 60;
const DEFAULT_HW_QUALITY: Quality = Quality_Default;
const DEFAULT_RC: RateContorl = RC_DEFAULT;
const DEFAULT_RC: RateControl = RC_DEFAULT;
pub struct HwEncoder {
encoder: Encoder,
@@ -94,7 +94,7 @@ impl EncoderApi for HwEncoder {
frames.push(EncodedVideoFrame {
data: Bytes::from(frame.data),
pts: frame.pts as _,
key:frame.key == 1,
key: frame.key == 1,
..Default::default()
});
}
@@ -175,6 +175,7 @@ pub struct HwDecoder {
pub info: CodecInfo,
}
#[derive(Default)]
pub struct HwDecoders {
pub h264: Option<HwDecoder>,
pub h265: Option<HwDecoder>,
@@ -292,8 +293,8 @@ pub fn check_config() {
quality: DEFAULT_HW_QUALITY,
rc: DEFAULT_RC,
};
let encoders = CodecInfo::score(Encoder::avaliable_encoders(ctx));
let decoders = CodecInfo::score(Decoder::avaliable_decoders());
let encoders = CodecInfo::score(Encoder::available_encoders(ctx));
let decoders = CodecInfo::score(Decoder::available_decoders());
if let Ok(old_encoders) = get_config(CFG_KEY_ENCODER) {
if let Ok(old_decoders) = get_config(CFG_KEY_DECODER) {

View File

@@ -37,6 +37,7 @@ impl Deref for MediaCodecDecoder {
}
}
#[derive(Default)]
pub struct MediaCodecDecoders {
pub h264: Option<MediaCodecDecoder>,
pub h265: Option<MediaCodecDecoder>,

View File

@@ -44,8 +44,8 @@ pub mod record;
mod vpx;
#[inline]
pub fn would_block_if_equal(old: &mut Vec<u128>, b: &[u8]) -> std::io::Result<()> {
let b = unsafe { std::slice::from_raw_parts::<u128>(b.as_ptr() as _, b.len() / 16) };
pub fn would_block_if_equal(old: &mut Vec<u8>, b: &[u8]) -> std::io::Result<()> {
// does this really help?
if b == &old[..] {
return Err(std::io::ErrorKind::WouldBlock.into());
}
@@ -72,16 +72,16 @@ pub fn is_x11() -> bool {
#[cfg(x11)]
#[inline]
pub fn is_cursor_embeded() -> bool {
pub fn is_cursor_embedded() -> bool {
if is_x11() {
x11::IS_CURSOR_EMBEDED
x11::IS_CURSOR_EMBEDDED
} else {
wayland::IS_CURSOR_EMBEDED
wayland::IS_CURSOR_EMBEDDED
}
}
#[cfg(not(x11))]
#[inline]
pub fn is_cursor_embeded() -> bool {
pub fn is_cursor_embedded() -> bool {
false
}

View File

@@ -8,7 +8,7 @@ pub struct Capturer {
frame: Arc<Mutex<Option<quartz::Frame>>>,
use_yuv: bool,
i420: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {

View File

@@ -4,7 +4,7 @@ use std::{io, sync::RwLock, time::Duration};
pub struct Capturer(Display, Box<dyn Recorder>, bool, Vec<u8>);
pub const IS_CURSOR_EMBEDED: bool = true;
pub const IS_CURSOR_EMBEDDED: bool = true;
lazy_static::lazy_static! {
static ref MAP_ERR: RwLock<Option<fn(err: String)-> io::Error>> = Default::default();
@@ -50,6 +50,12 @@ impl TraitCapturer for Capturer {
} else {
x
})),
PixelProvider::RGB0(w, h, x) => Ok(Frame(if self.2 {
crate::common::rgba_to_i420(w as _, h as _, &x, &mut self.3);
&self.3[..]
} else {
x
})),
PixelProvider::NONE => Err(std::io::ErrorKind::WouldBlock.into()),
_ => Err(map_err("Invalid data")),
}

View File

@@ -3,7 +3,7 @@ use std::{io, ops, time::Duration};
pub struct Capturer(x11::Capturer);
pub const IS_CURSOR_EMBEDED: bool = false;
pub const IS_CURSOR_EMBEDDED: bool = false;
impl Capturer {
pub fn new(display: Display, yuv: bool) -> io::Result<Capturer> {

View File

@@ -339,7 +339,7 @@ impl CapturerMag {
}
// Register the host window class. See the MSDN documentation of the
// Magnification API for more infomation.
// Magnification API for more information.
let wcex = WNDCLASSEXA {
cbSize: size_of::<WNDCLASSEXA>() as _,
style: 0,

View File

@@ -50,7 +50,7 @@ pub struct Capturer {
rotated: Vec<u8>,
gdi_capturer: Option<CapturerGDI>,
gdi_buffer: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {
@@ -262,7 +262,7 @@ impl Capturer {
_ => {
return Err(io::Error::new(
io::ErrorKind::Other,
"Unknown roration".to_string(),
"Unknown rotation".to_string(),
));
}
};

View File

@@ -13,6 +13,7 @@ impl Display {
pub fn online() -> Result<Vec<Display>, CGError> {
unsafe {
#[allow(invalid_value)]
let mut arr: [u32; 16] = mem::MaybeUninit::uninit().assume_init();
let mut len: u32 = 0;

View File

@@ -4,6 +4,7 @@ use std::error::Error;
pub enum PixelProvider<'a> {
// 8 bits per color
RGB(usize, usize, &'a [u8]),
RGB0(usize, usize, &'a [u8]),
BGR0(usize, usize, &'a [u8]),
// width, height, stride
BGR0S(usize, usize, usize, &'a [u8]),
@@ -14,6 +15,7 @@ impl<'a> PixelProvider<'a> {
pub fn size(&self) -> (usize, usize) {
match self {
PixelProvider::RGB(w, h, _) => (*w, *h),
PixelProvider::RGB0(w, h, _) => (*w, *h),
PixelProvider::BGR0(w, h, _) => (*w, *h),
PixelProvider::BGR0S(w, h, _, _) => (*w, *h),
PixelProvider::NONE => (0, 0),

View File

@@ -117,12 +117,13 @@ impl Capturable for PipeWireCapturable {
pub struct PipeWireRecorder {
buffer: Option<gst::MappedBuffer<gst::buffer::Readable>>,
buffer_cropped: Vec<u8>,
pix_fmt: String,
is_cropped: bool,
pipeline: gst::Pipeline,
appsink: AppSink,
width: usize,
height: usize,
saved_raw_data: Vec<u128>, // for faster compare and copy
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl PipeWireRecorder {
@@ -144,19 +145,27 @@ impl PipeWireRecorder {
pipeline.add_many(&[&src, &sink])?;
src.link(&sink)?;
let appsink = sink
.dynamic_cast::<AppSink>()
.map_err(|_| GStreamerError("Sink element is expected to be an appsink!".into()))?;
appsink.set_caps(Some(&gst::Caps::new_simple(
let mut caps = gst::Caps::new_empty();
caps.merge_structure(gst::structure::Structure::new(
"video/x-raw",
&[("format", &"BGRx")],
)));
));
caps.merge_structure(gst::structure::Structure::new(
"video/x-raw",
&[("format", &"RGBx")],
));
appsink.set_caps(Some(&caps));
pipeline.set_state(gst::State::Playing)?;
Ok(Self {
pipeline,
appsink,
buffer: None,
pix_fmt: "".into(),
width: 0,
height: 0,
buffer_cropped: vec![],
@@ -181,6 +190,11 @@ impl Recorder for PipeWireRecorder {
let h: i32 = cap.get_value("height")?.get_some()?;
let w = w as usize;
let h = h as usize;
self.pix_fmt = cap
.get::<&str>("format")?
.ok_or("Failed to get pixel format")?
.to_string();
let buf = sample
.get_buffer_owned()
.ok_or_else(|| GStreamerError("Failed to get owned buffer.".into()))?;
@@ -241,15 +255,22 @@ impl Recorder for PipeWireRecorder {
if self.buffer.is_none() {
return Err(Box::new(GStreamerError("No buffer available!".into())));
}
Ok(PixelProvider::BGR0(
self.width,
self.height,
if self.is_cropped {
self.buffer_cropped.as_slice()
} else {
self.buffer.as_ref().unwrap().as_slice()
},
))
let buf = if self.is_cropped {
self.buffer_cropped.as_slice()
} else {
self.buffer
.as_ref()
.ok_or("Failed to get buffer as ref")?
.as_slice()
};
match self.pix_fmt.as_str() {
"BGRx" => Ok(PixelProvider::BGR0(self.width, self.height, buf)),
"RGBx" => Ok(PixelProvider::RGB0(self.width, self.height, buf)),
_ => Err(Box::new(GStreamerError(format!(
"Unreachable! Unknown pix_fmt, {}",
&self.pix_fmt
)))),
}
}
}

View File

@@ -14,7 +14,7 @@ pub struct Capturer {
size: usize,
use_yuv: bool,
yuv: Vec<u8>,
saved_raw_data: Vec<u128>, // for faster compare and copy
saved_raw_data: Vec<u8>, // for faster compare and copy
}
impl Capturer {

View File

@@ -66,7 +66,7 @@ const char* GetLastMsg()
BOOL InstallUpdate(LPCWSTR fullInfPath, PBOOL rebootRequired)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
// UpdateDriverForPlugAndPlayDevicesW may return FALSE while driver was successfully installed...
if (FALSE == UpdateDriverForPlugAndPlayDevicesW(
@@ -96,7 +96,7 @@ BOOL InstallUpdate(LPCWSTR fullInfPath, PBOOL rebootRequired)
BOOL Uninstall(LPCWSTR fullInfPath, PBOOL rebootRequired)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
if (FALSE == DiUninstallDriverW(
NULL,
@@ -122,7 +122,7 @@ BOOL Uninstall(LPCWSTR fullInfPath, PBOOL rebootRequired)
BOOL IsDeviceCreated(PBOOL created)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
HDEVINFO hardwareDeviceInfo = SetupDiGetClassDevs(
&GUID_DEVINTERFACE_IDD_DRIVER_DEVICE,
@@ -181,7 +181,7 @@ BOOL IsDeviceCreated(PBOOL created)
BOOL DeviceCreate(PHSWDEVICE hSwDevice)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
if (*hSwDevice != NULL)
{
@@ -221,7 +221,7 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice)
SW_DEVICE_CREATE_INFO createInfo = { 0 };
PCWSTR description = L"RustDesk Idd Driver";
// These match the Pnp id's in the inf file so OS will load the driver when the device is created
// These match the Pnp id's in the inf file so OS will load the driver when the device is created
PCWSTR instanceId = L"RustDeskIddDriver";
PCWSTR hardwareIds = L"RustDeskIddDriver\0\0";
PCWSTR compatibleIds = L"RustDeskIddDriver\0\0";
@@ -274,7 +274,7 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice)
VOID DeviceClose(HSWDEVICE hSwDevice)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
if (hSwDevice != INVALID_HANDLE_VALUE && hSwDevice != NULL)
{
@@ -284,7 +284,7 @@ VOID DeviceClose(HSWDEVICE hSwDevice)
BOOL MonitorPlugIn(UINT index, UINT edid, INT retries)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
if (retries < 0)
{
@@ -359,7 +359,7 @@ BOOL MonitorPlugIn(UINT index, UINT edid, INT retries)
BOOL MonitorPlugOut(UINT index)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
HANDLE hDevice = DeviceOpenHandle();
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
@@ -400,7 +400,7 @@ BOOL MonitorPlugOut(UINT index)
BOOL MonitorModesUpdate(UINT index, UINT modeCount, PMonitorMode modes)
{
SetLastMsg("Sucess");
SetLastMsg("Success");
HANDLE hDevice = DeviceOpenHandle();
if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
@@ -721,7 +721,7 @@ Clean0:
// https://stackoverflow.com/questions/67164846/createfile-fails-unless-i-disable-enable-my-device
HANDLE DeviceOpenHandle()
{
SetLastMsg("Sucess");
SetLastMsg("Success");
// const int maxDevPathLen = 256;
TCHAR devicePath[256] = { 0 };

View File

@@ -14,7 +14,7 @@ extern "C" {
* @param rebootRequired [out] Indicates whether a restart is required.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
*
* @see GetLastMsg#GetLastMsg
*/
BOOL InstallUpdate(LPCTSTR fullInfPath, PBOOL rebootRequired);
@@ -34,11 +34,11 @@ BOOL Uninstall(LPCTSTR fullInfPath, PBOOL rebootRequired);
/**
* @brief Check if RustDeskIddDriver device is created before.
* The driver device(adapter) should be single instance.
*
*
* @param created [out] Indicates whether the device is created before.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
*
* @see GetLastMsg#GetLastMsg
*
*/
@@ -47,12 +47,12 @@ BOOL IsDeviceCreated(PBOOL created);
/**
* @brief Create device.
* Only one device should be created.
* If device is installed ealier, this function returns FALSE.
*
* If device is installed earlier, this function returns FALSE.
*
* @param hSwDevice [out] Handler of software device, used by DeviceCreate(). Should be **NULL**.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
*
* @see GetLastMsg#GetLastMsg
*
*/
@@ -79,9 +79,9 @@ VOID DeviceClose(HSWDEVICE hSwDevice);
* 1 means doing once and retry one time...
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
*
* @see GetLastMsg#GetLastMsg
*
*
* @remark Plug in monitor may fail if device is created in a very short time.
* System need some time to prepare the device.
*
@@ -94,7 +94,7 @@ BOOL MonitorPlugIn(UINT index, UINT edid, INT retries);
* @param index [in] Monitor index, should be 0, 1, 2.
*
* @return TRUE/FALSE. If FALSE returned, error message can be retrieved by GetLastMsg()
*
*
* @see GetLastMsg#GetLastMsg
*
*/
@@ -133,9 +133,9 @@ const char* GetLastMsg();
* @brief Set if print error message when debug.
*
* @param b [in] TRUE to enable printing message.
*
* @remark For now, no need to read evironment variable to check if should print.
*
*
* @remark For now, no need to read environment variable to check if should print.
*
*/
VOID SetPrintErrMsg(BOOL b);