Merge pull request #399 from fufesou/copy_paste_2

windows clipboard
This commit is contained in:
RustDesk 2022-02-15 13:14:35 +08:00 committed by GitHub
commit e407ba3a33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 4506 additions and 1 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ __pycache__
src/version.rs
*dmg
sciter.dll
**pdb

11
Cargo.lock generated
View File

@ -388,6 +388,16 @@ dependencies = [
"textwrap 0.14.2",
]
[[package]]
name = "clipboard"
version = "0.1.0"
dependencies = [
"cc",
"hbb_common",
"lazy_static",
"thiserror",
]
[[package]]
name = "clipboard-master"
version = "3.1.3"
@ -3365,6 +3375,7 @@ dependencies = [
"cc",
"cfg-if 1.0.0",
"clap 3.0.10",
"clipboard",
"clipboard-master",
"cocoa 0.24.0",
"core-foundation 0.9.2",

View File

@ -21,6 +21,7 @@ whoami = "1.2"
scrap = { path = "libs/scrap" }
hbb_common = { path = "libs/hbb_common" }
enigo = { path = "libs/enigo" }
clipboard = { path = "libs/clipboard" }
sys-locale = "0.1"
serde_derive = "1.0"
serde = "1.0"
@ -82,7 +83,7 @@ rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" }
android_logger = "0.10"
[workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo"]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard"]
[package.metadata.winres]
LegalCopyright = "Copyright © 2020"

15
libs/clipboard/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "clipboard"
version = "0.1.0"
edition = "2021"
build= "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
cc = "1.0"
[dependencies]
thiserror = "1.0.30"
lazy_static = "1.4"
hbb_common = { path = "../hbb_common" }

16
libs/clipboard/README.md Normal file
View File

@ -0,0 +1,16 @@
# clipboard
Copy files and text through network.
Main lowlevel logic from [FreeRDP](https://github.com/FreeRDP/FreeRDP).
TODO: Move this lib to a separate project.
## impl
### windows
![scene](./docs/assets/scene3.png)
![A1->B1](./docs/assets/win_A_B.png)
![B1->A1](./docs/assets/win_B_A.png)

43
libs/clipboard/build.rs Normal file
View File

@ -0,0 +1,43 @@
use cc;
fn build_c_impl() {
let mut build = cc::Build::new();
#[cfg(target_os = "windows")]
build.file("src/windows/wf_cliprdr.c");
#[cfg(target_os = "linux")]
build.file("src/X11/xf_cliprdr.c");
#[cfg(target_os = "macos")]
build.file("src/OSX/Clipboard.m");
build.flag_if_supported("-Wno-c++0x-extensions");
build.flag_if_supported("-Wno-return-type-c-linkage");
build.flag_if_supported("-Wno-invalid-offsetof");
build.flag_if_supported("-Wno-unused-parameter");
if build.get_compiler().is_like_msvc() {
build.define("WIN32", "");
// build.define("_AMD64_", "");
build.flag("-Zi");
build.flag("-GR-");
// build.flag("-std:c++11");
} else {
build.flag("-fPIC");
// build.flag("-std=c++11");
// build.flag("-include");
// build.flag(&confdefs_path.to_string_lossy());
}
build.compile("mycliprdr");
#[cfg(target_os = "windows")]
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
#[cfg(target_os = "linux")]
println!("cargo:rerun-if-changed=src/X11/xf_cliprdr.c");
#[cfg(target_os = "macos")]
println!("cargo:rerun-if-changed=src/OSX/Clipboard.m");
}
fn main() {
build_c_impl();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,11 @@
#include "../cliprdr.h"
void mac_cliprdr_init(CliprdrClientContext *cliprdr)
{
(void)cliprdr;
}
void mac_cliprdr_uninit(CliprdrClientContext *cliprdr)
{
(void)cliprdr;
}

View File

@ -0,0 +1,11 @@
#include "../cliprdr.h"
void xf_cliprdr_init(CliprdrClientContext* cliprdr)
{
(void)cliprdr;
}
void xf_cliprdr_uninit( CliprdrClientContext* cliprdr)
{
(void)cliprdr;
}

View File

@ -0,0 +1,231 @@
#ifndef WF_CLIPRDR_H__
#define WF_CLIPRDR_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef signed char INT8, *PINT8;
typedef signed short INT16, *PINT16;
typedef signed int INT32, *PINT32;
typedef unsigned char UINT8, *PUINT8;
typedef unsigned short UINT16, *PUINT16;
typedef unsigned int UINT32, *PUINT32;
typedef unsigned int UINT;
typedef int BOOL;
typedef unsigned char BYTE;
/* Clipboard Messages */
#define DEFINE_CLIPRDR_HEADER_COMMON() \
UINT32 serverConnID; \
UINT32 remoteConnID; \
UINT16 msgType; \
UINT16 msgFlags; \
UINT32 dataLen
struct _CLIPRDR_HEADER
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_HEADER CLIPRDR_HEADER;
struct _CLIPRDR_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
};
typedef struct _CLIPRDR_CAPABILITY_SET CLIPRDR_CAPABILITY_SET;
struct _CLIPRDR_GENERAL_CAPABILITY_SET
{
UINT16 capabilitySetType;
UINT16 capabilitySetLength;
UINT32 version;
UINT32 generalFlags;
};
typedef struct _CLIPRDR_GENERAL_CAPABILITY_SET CLIPRDR_GENERAL_CAPABILITY_SET;
struct _CLIPRDR_CAPABILITIES
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 cCapabilitiesSets;
CLIPRDR_CAPABILITY_SET *capabilitySets;
};
typedef struct _CLIPRDR_CAPABILITIES CLIPRDR_CAPABILITIES;
struct _CLIPRDR_MONITOR_READY
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_MONITOR_READY CLIPRDR_MONITOR_READY;
struct _CLIPRDR_TEMP_DIRECTORY
{
DEFINE_CLIPRDR_HEADER_COMMON();
char szTempDir[520];
};
typedef struct _CLIPRDR_TEMP_DIRECTORY CLIPRDR_TEMP_DIRECTORY;
struct _CLIPRDR_FORMAT
{
UINT32 formatId;
char *formatName;
};
typedef struct _CLIPRDR_FORMAT CLIPRDR_FORMAT;
struct _CLIPRDR_FORMAT_LIST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 numFormats;
CLIPRDR_FORMAT *formats;
};
typedef struct _CLIPRDR_FORMAT_LIST CLIPRDR_FORMAT_LIST;
struct _CLIPRDR_FORMAT_LIST_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
};
typedef struct _CLIPRDR_FORMAT_LIST_RESPONSE CLIPRDR_FORMAT_LIST_RESPONSE;
struct _CLIPRDR_LOCK_CLIPBOARD_DATA
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 clipDataId;
};
typedef struct _CLIPRDR_LOCK_CLIPBOARD_DATA CLIPRDR_LOCK_CLIPBOARD_DATA;
struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 clipDataId;
};
typedef struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA CLIPRDR_UNLOCK_CLIPBOARD_DATA;
struct _CLIPRDR_FORMAT_DATA_REQUEST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 requestedFormatId;
};
typedef struct _CLIPRDR_FORMAT_DATA_REQUEST CLIPRDR_FORMAT_DATA_REQUEST;
struct _CLIPRDR_FORMAT_DATA_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
const BYTE *requestedFormatData;
};
typedef struct _CLIPRDR_FORMAT_DATA_RESPONSE CLIPRDR_FORMAT_DATA_RESPONSE;
struct _CLIPRDR_FILE_CONTENTS_REQUEST
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 streamId;
UINT32 listIndex;
UINT32 dwFlags;
UINT32 nPositionLow;
UINT32 nPositionHigh;
UINT32 cbRequested;
BOOL haveClipDataId;
UINT32 clipDataId;
};
typedef struct _CLIPRDR_FILE_CONTENTS_REQUEST CLIPRDR_FILE_CONTENTS_REQUEST;
struct _CLIPRDR_FILE_CONTENTS_RESPONSE
{
DEFINE_CLIPRDR_HEADER_COMMON();
UINT32 streamId;
UINT32 cbRequested;
const BYTE *requestedData;
};
typedef struct _CLIPRDR_FILE_CONTENTS_RESPONSE CLIPRDR_FILE_CONTENTS_RESPONSE;
typedef struct _cliprdr_client_context CliprdrClientContext;
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context,
const CLIPRDR_CAPABILITIES *capabilities);
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context,
const CLIPRDR_CAPABILITIES *capabilities);
typedef UINT (*pcCliprdrMonitorReady)(CliprdrClientContext *context,
const CLIPRDR_MONITOR_READY *monitorReady);
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context,
const CLIPRDR_TEMP_DIRECTORY *tempDirectory);
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context,
const CLIPRDR_FORMAT_LIST *formatList);
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context,
const CLIPRDR_FORMAT_LIST *formatList);
typedef UINT (*pcCliprdrClientFormatListResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
typedef UINT (*pcCliprdrServerFormatListResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse);
typedef UINT (*pcCliprdrClientLockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
typedef UINT (*pcCliprdrServerLockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData);
typedef UINT (*pcCliprdrClientUnlockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
typedef UINT (*pcCliprdrServerUnlockClipboardData)(
CliprdrClientContext *context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData);
typedef UINT (*pcCliprdrClientFormatDataRequest)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
typedef UINT (*pcCliprdrServerFormatDataRequest)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest);
typedef UINT (*pcCliprdrClientFormatDataResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
typedef UINT (*pcCliprdrServerFormatDataResponse)(
CliprdrClientContext *context, const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse);
typedef UINT (*pcCliprdrClientFileContentsRequest)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
typedef UINT (*pcCliprdrServerFileContentsRequest)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest);
typedef UINT (*pcCliprdrClientFileContentsResponse)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
typedef UINT (*pcCliprdrServerFileContentsResponse)(
CliprdrClientContext *context, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse);
// TODO: hide more members of clipboard context
struct _cliprdr_client_context
{
void *custom;
BOOL enableFiles;
BOOL enableOthers;
pcCliprdrServerCapabilities ServerCapabilities;
pcCliprdrClientCapabilities ClientCapabilities;
pcCliprdrMonitorReady MonitorReady;
pcCliprdrTempDirectory TempDirectory;
pcCliprdrClientFormatList ClientFormatList;
pcCliprdrServerFormatList ServerFormatList;
pcCliprdrClientFormatListResponse ClientFormatListResponse;
pcCliprdrServerFormatListResponse ServerFormatListResponse;
pcCliprdrClientLockClipboardData ClientLockClipboardData;
pcCliprdrServerLockClipboardData ServerLockClipboardData;
pcCliprdrClientUnlockClipboardData ClientUnlockClipboardData;
pcCliprdrServerUnlockClipboardData ServerUnlockClipboardData;
pcCliprdrClientFormatDataRequest ClientFormatDataRequest;
pcCliprdrServerFormatDataRequest ServerFormatDataRequest;
pcCliprdrClientFormatDataResponse ClientFormatDataResponse;
pcCliprdrServerFormatDataResponse ServerFormatDataResponse;
pcCliprdrClientFileContentsRequest ClientFileContentsRequest;
pcCliprdrServerFileContentsRequest ServerFileContentsRequest;
pcCliprdrClientFileContentsResponse ClientFileContentsResponse;
pcCliprdrServerFileContentsResponse ServerFileContentsResponse;
UINT32 lastRequestedFormatId;
};
#ifdef __cplusplus
}
#endif
#endif // WF_CLIPRDR_H__

View File

@ -0,0 +1,566 @@
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(deref_nullptr)]
use std::{boxed::Box, result::Result};
use thiserror::Error;
pub type size_t = ::std::os::raw::c_ulonglong;
pub type __vcrt_bool = bool;
pub type wchar_t = ::std::os::raw::c_ushort;
pub type POINTER_64_INT = ::std::os::raw::c_ulonglong;
pub type INT8 = ::std::os::raw::c_schar;
pub type PINT8 = *mut ::std::os::raw::c_schar;
pub type INT16 = ::std::os::raw::c_short;
pub type PINT16 = *mut ::std::os::raw::c_short;
pub type INT32 = ::std::os::raw::c_int;
pub type PINT32 = *mut ::std::os::raw::c_int;
pub type INT64 = ::std::os::raw::c_longlong;
pub type PINT64 = *mut ::std::os::raw::c_longlong;
pub type UINT8 = ::std::os::raw::c_uchar;
pub type PUINT8 = *mut ::std::os::raw::c_uchar;
pub type UINT16 = ::std::os::raw::c_ushort;
pub type PUINT16 = *mut ::std::os::raw::c_ushort;
pub type UINT32 = ::std::os::raw::c_uint;
pub type PUINT32 = *mut ::std::os::raw::c_uint;
pub type UINT64 = ::std::os::raw::c_ulonglong;
pub type PUINT64 = *mut ::std::os::raw::c_ulonglong;
pub type LONG32 = ::std::os::raw::c_int;
pub type PLONG32 = *mut ::std::os::raw::c_int;
pub type ULONG32 = ::std::os::raw::c_uint;
pub type PULONG32 = *mut ::std::os::raw::c_uint;
pub type DWORD32 = ::std::os::raw::c_uint;
pub type PDWORD32 = *mut ::std::os::raw::c_uint;
pub type INT_PTR = ::std::os::raw::c_longlong;
pub type PINT_PTR = *mut ::std::os::raw::c_longlong;
pub type UINT_PTR = ::std::os::raw::c_ulonglong;
pub type PUINT_PTR = *mut ::std::os::raw::c_ulonglong;
pub type LONG_PTR = ::std::os::raw::c_longlong;
pub type PLONG_PTR = *mut ::std::os::raw::c_longlong;
pub type ULONG_PTR = ::std::os::raw::c_ulonglong;
pub type PULONG_PTR = *mut ::std::os::raw::c_ulonglong;
pub type SHANDLE_PTR = ::std::os::raw::c_longlong;
pub type HANDLE_PTR = ::std::os::raw::c_ulonglong;
pub type UHALF_PTR = ::std::os::raw::c_uint;
pub type PUHALF_PTR = *mut ::std::os::raw::c_uint;
pub type HALF_PTR = ::std::os::raw::c_int;
pub type PHALF_PTR = *mut ::std::os::raw::c_int;
pub type SIZE_T = ULONG_PTR;
pub type PSIZE_T = *mut ULONG_PTR;
pub type SSIZE_T = LONG_PTR;
pub type PSSIZE_T = *mut LONG_PTR;
pub type DWORD_PTR = ULONG_PTR;
pub type PDWORD_PTR = *mut ULONG_PTR;
pub type LONG64 = ::std::os::raw::c_longlong;
pub type PLONG64 = *mut ::std::os::raw::c_longlong;
pub type ULONG64 = ::std::os::raw::c_ulonglong;
pub type PULONG64 = *mut ::std::os::raw::c_ulonglong;
pub type DWORD64 = ::std::os::raw::c_ulonglong;
pub type PDWORD64 = *mut ::std::os::raw::c_ulonglong;
pub type KAFFINITY = ULONG_PTR;
pub type PKAFFINITY = *mut KAFFINITY;
pub type PVOID = *mut ::std::os::raw::c_void;
pub type CHAR = ::std::os::raw::c_char;
pub type SHORT = ::std::os::raw::c_short;
pub type LONG = ::std::os::raw::c_long;
pub type WCHAR = wchar_t;
pub type PWCHAR = *mut WCHAR;
pub type LPWCH = *mut WCHAR;
pub type PWCH = *mut WCHAR;
pub type LPCWCH = *const WCHAR;
pub type PCWCH = *const WCHAR;
pub type NWPSTR = *mut WCHAR;
pub type LPWSTR = *mut WCHAR;
pub type PWSTR = *mut WCHAR;
pub type PZPWSTR = *mut PWSTR;
pub type PCZPWSTR = *const PWSTR;
pub type LPUWSTR = *mut WCHAR;
pub type PUWSTR = *mut WCHAR;
pub type LPCWSTR = *const WCHAR;
pub type PCWSTR = *const WCHAR;
pub type PZPCWSTR = *mut PCWSTR;
pub type PCZPCWSTR = *const PCWSTR;
pub type LPCUWSTR = *const WCHAR;
pub type PCUWSTR = *const WCHAR;
pub type PZZWSTR = *mut WCHAR;
pub type PCZZWSTR = *const WCHAR;
pub type PUZZWSTR = *mut WCHAR;
pub type PCUZZWSTR = *const WCHAR;
pub type PNZWCH = *mut WCHAR;
pub type PCNZWCH = *const WCHAR;
pub type PUNZWCH = *mut WCHAR;
pub type PCUNZWCH = *const WCHAR;
pub type PCHAR = *mut CHAR;
pub type LPCH = *mut CHAR;
pub type PCH = *mut CHAR;
pub type LPCCH = *const CHAR;
pub type PCCH = *const CHAR;
pub type NPSTR = *mut CHAR;
pub type LPSTR = *mut CHAR;
pub type PSTR = *mut CHAR;
pub type PZPSTR = *mut PSTR;
pub type PCZPSTR = *const PSTR;
pub type LPCSTR = *const CHAR;
pub type PCSTR = *const CHAR;
pub type PZPCSTR = *mut PCSTR;
pub type PCZPCSTR = *const PCSTR;
pub type PZZSTR = *mut CHAR;
pub type PCZZSTR = *const CHAR;
pub type PNZCH = *mut CHAR;
pub type PCNZCH = *const CHAR;
pub type TCHAR = ::std::os::raw::c_char;
pub type PTCHAR = *mut ::std::os::raw::c_char;
pub type TBYTE = ::std::os::raw::c_uchar;
pub type PTBYTE = *mut ::std::os::raw::c_uchar;
pub type LPTCH = LPCH;
pub type PTCH = LPCH;
pub type LPCTCH = LPCCH;
pub type PCTCH = LPCCH;
pub type PTSTR = LPSTR;
pub type LPTSTR = LPSTR;
pub type PUTSTR = LPSTR;
pub type LPUTSTR = LPSTR;
pub type PCTSTR = LPCSTR;
pub type LPCTSTR = LPCSTR;
pub type PCUTSTR = LPCSTR;
pub type LPCUTSTR = LPCSTR;
pub type PZZTSTR = PZZSTR;
pub type PUZZTSTR = PZZSTR;
pub type PCZZTSTR = PCZZSTR;
pub type PCUZZTSTR = PCZZSTR;
pub type PZPTSTR = PZPSTR;
pub type PNZTCH = PNZCH;
pub type PUNZTCH = PNZCH;
pub type PCNZTCH = PCNZCH;
pub type PCUNZTCH = PCNZCH;
pub type PSHORT = *mut SHORT;
pub type PLONG = *mut LONG;
pub type ULONG = ::std::os::raw::c_ulong;
pub type PULONG = *mut ULONG;
pub type USHORT = ::std::os::raw::c_ushort;
pub type PUSHORT = *mut USHORT;
pub type UCHAR = ::std::os::raw::c_uchar;
pub type PUCHAR = *mut UCHAR;
pub type PSZ = *mut ::std::os::raw::c_char;
pub type DWORD = ::std::os::raw::c_ulong;
pub type BOOL = ::std::os::raw::c_int;
pub type BYTE = ::std::os::raw::c_uchar;
pub type WORD = ::std::os::raw::c_ushort;
pub type FLOAT = f32;
pub type PFLOAT = *mut FLOAT;
pub type PBOOL = *mut BOOL;
pub type LPBOOL = *mut BOOL;
pub type PBYTE = *mut BYTE;
pub type LPBYTE = *mut BYTE;
pub type PINT = *mut ::std::os::raw::c_int;
pub type LPINT = *mut ::std::os::raw::c_int;
pub type PWORD = *mut WORD;
pub type LPWORD = *mut WORD;
pub type LPLONG = *mut ::std::os::raw::c_long;
pub type PDWORD = *mut DWORD;
pub type LPDWORD = *mut DWORD;
pub type LPVOID = *mut ::std::os::raw::c_void;
pub type LPCVOID = *const ::std::os::raw::c_void;
pub type INT = ::std::os::raw::c_int;
pub type UINT = ::std::os::raw::c_uint;
pub type PUINT = *mut ::std::os::raw::c_uint;
pub type va_list = *mut ::std::os::raw::c_char;
pub const TRUE: ::std::os::raw::c_int = 1;
pub const FALSE: ::std::os::raw::c_int = 0;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_HEADER {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_HEADER = _CLIPRDR_HEADER;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_CAPABILITY_SET {
pub capabilitySetType: UINT16,
pub capabilitySetLength: UINT16,
}
pub type CLIPRDR_CAPABILITY_SET = _CLIPRDR_CAPABILITY_SET;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_GENERAL_CAPABILITY_SET {
pub capabilitySetType: UINT16,
pub capabilitySetLength: UINT16,
pub version: UINT32,
pub generalFlags: UINT32,
}
pub type CLIPRDR_GENERAL_CAPABILITY_SET = _CLIPRDR_GENERAL_CAPABILITY_SET;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_CAPABILITIES {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub cCapabilitiesSets: UINT32,
pub capabilitySets: *mut CLIPRDR_CAPABILITY_SET,
}
pub type CLIPRDR_CAPABILITIES = _CLIPRDR_CAPABILITIES;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_MONITOR_READY {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_MONITOR_READY = _CLIPRDR_MONITOR_READY;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_TEMP_DIRECTORY {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub szTempDir: [::std::os::raw::c_char; 520usize],
}
pub type CLIPRDR_TEMP_DIRECTORY = _CLIPRDR_TEMP_DIRECTORY;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT {
pub formatId: UINT32,
pub formatName: *mut ::std::os::raw::c_char,
}
pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_LIST {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub numFormats: UINT32,
pub formats: *mut CLIPRDR_FORMAT,
}
pub type CLIPRDR_FORMAT_LIST = _CLIPRDR_FORMAT_LIST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_LIST_RESPONSE {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
}
pub type CLIPRDR_FORMAT_LIST_RESPONSE = _CLIPRDR_FORMAT_LIST_RESPONSE;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_LOCK_CLIPBOARD_DATA {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub clipDataId: UINT32,
}
pub type CLIPRDR_LOCK_CLIPBOARD_DATA = _CLIPRDR_LOCK_CLIPBOARD_DATA;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_UNLOCK_CLIPBOARD_DATA {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub clipDataId: UINT32,
}
pub type CLIPRDR_UNLOCK_CLIPBOARD_DATA = _CLIPRDR_UNLOCK_CLIPBOARD_DATA;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_DATA_REQUEST {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub requestedFormatId: UINT32,
}
pub type CLIPRDR_FORMAT_DATA_REQUEST = _CLIPRDR_FORMAT_DATA_REQUEST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FORMAT_DATA_RESPONSE {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub requestedFormatData: *const BYTE,
}
pub type CLIPRDR_FORMAT_DATA_RESPONSE = _CLIPRDR_FORMAT_DATA_RESPONSE;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FILE_CONTENTS_REQUEST {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub streamId: UINT32,
pub listIndex: UINT32,
pub dwFlags: UINT32,
pub nPositionLow: UINT32,
pub nPositionHigh: UINT32,
pub cbRequested: UINT32,
pub haveClipDataId: BOOL,
pub clipDataId: UINT32,
}
pub type CLIPRDR_FILE_CONTENTS_REQUEST = _CLIPRDR_FILE_CONTENTS_REQUEST;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE {
pub serverConnID: UINT32,
pub remoteConnID: UINT32,
pub msgType: UINT16,
pub msgFlags: UINT16,
pub dataLen: UINT32,
pub streamId: UINT32,
pub cbRequested: UINT32,
pub requestedData: *const BYTE,
}
pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE;
pub type CliprdrClientContext = _cliprdr_client_context;
pub type pcCliprdrServerCapabilities = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
capabilities: *const CLIPRDR_CAPABILITIES,
) -> UINT,
>;
pub type pcCliprdrClientCapabilities = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
capabilities: *const CLIPRDR_CAPABILITIES,
) -> UINT,
>;
pub type pcCliprdrMonitorReady = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
monitorReady: *const CLIPRDR_MONITOR_READY,
) -> UINT,
>;
pub type pcCliprdrTempDirectory = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
tempDirectory: *const CLIPRDR_TEMP_DIRECTORY,
) -> UINT,
>;
pub type pcCliprdrClientFormatList = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatList: *const CLIPRDR_FORMAT_LIST,
) -> UINT,
>;
pub type pcCliprdrServerFormatList = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatList: *const CLIPRDR_FORMAT_LIST,
) -> UINT,
>;
pub type pcCliprdrClientFormatListResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFormatListResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatListResponse: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrClientLockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrServerLockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
lockClipboardData: *const CLIPRDR_LOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrClientUnlockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrServerUnlockClipboardData = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
unlockClipboardData: *const CLIPRDR_UNLOCK_CLIPBOARD_DATA,
) -> UINT,
>;
pub type pcCliprdrClientFormatDataRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT,
>;
pub type pcCliprdrServerFormatDataRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataRequest: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT,
>;
pub type pcCliprdrClientFormatDataResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFormatDataResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
formatDataResponse: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrClientFileContentsRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT,
>;
pub type pcCliprdrServerFileContentsRequest = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsRequest: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT,
>;
pub type pcCliprdrClientFileContentsResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT,
>;
pub type pcCliprdrServerFileContentsResponse = ::std::option::Option<
unsafe extern "C" fn(
context: *mut CliprdrClientContext,
fileContentsResponse: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT,
>;
// TODO: hide more members of clipboard context
#[repr(C)]
#[derive(Debug, Clone)]
pub struct _cliprdr_client_context {
pub custom: *mut ::std::os::raw::c_void,
pub enableFiles: BOOL,
pub enableOthers: BOOL,
pub ServerCapabilities: pcCliprdrServerCapabilities,
pub ClientCapabilities: pcCliprdrClientCapabilities,
pub MonitorReady: pcCliprdrMonitorReady,
pub TempDirectory: pcCliprdrTempDirectory,
pub ClientFormatList: pcCliprdrClientFormatList,
pub ServerFormatList: pcCliprdrServerFormatList,
pub ClientFormatListResponse: pcCliprdrClientFormatListResponse,
pub ServerFormatListResponse: pcCliprdrServerFormatListResponse,
pub ClientLockClipboardData: pcCliprdrClientLockClipboardData,
pub ServerLockClipboardData: pcCliprdrServerLockClipboardData,
pub ClientUnlockClipboardData: pcCliprdrClientUnlockClipboardData,
pub ServerUnlockClipboardData: pcCliprdrServerUnlockClipboardData,
pub ClientFormatDataRequest: pcCliprdrClientFormatDataRequest,
pub ServerFormatDataRequest: pcCliprdrServerFormatDataRequest,
pub ClientFormatDataResponse: pcCliprdrClientFormatDataResponse,
pub ServerFormatDataResponse: pcCliprdrServerFormatDataResponse,
pub ClientFileContentsRequest: pcCliprdrClientFileContentsRequest,
pub ServerFileContentsRequest: pcCliprdrServerFileContentsRequest,
pub ClientFileContentsResponse: pcCliprdrClientFileContentsResponse,
pub ServerFileContentsResponse: pcCliprdrServerFileContentsResponse,
pub lastRequestedFormatId: UINT32,
}
// #[link(name = "user32")]
// #[link(name = "ole32")]
extern "C" {
pub(crate) fn init_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
pub(crate) fn uninit_cliprdr(context: *mut CliprdrClientContext) -> BOOL;
}
#[derive(Error, Debug)]
pub enum CliprdrError {
#[error("invalid cliprdr name")]
CliprdrName,
#[error("failed to init cliprdr")]
CliprdrInit,
#[error("unknown cliprdr error")]
Unknown,
}
impl CliprdrClientContext {
pub fn create(
enable_files: bool,
enable_others: bool,
client_format_list: pcCliprdrClientFormatList,
client_format_list_response: pcCliprdrClientFormatListResponse,
client_format_data_request: pcCliprdrClientFormatDataRequest,
client_format_data_response: pcCliprdrClientFormatDataResponse,
client_file_contents_request: pcCliprdrClientFileContentsRequest,
client_file_contents_response: pcCliprdrClientFileContentsResponse,
) -> Result<Box<Self>, CliprdrError> {
let context = CliprdrClientContext {
custom: 0 as *mut _,
enableFiles: if enable_files { TRUE } else { FALSE },
enableOthers: if enable_others { TRUE } else { FALSE },
ServerCapabilities: None,
ClientCapabilities: None,
MonitorReady: None,
TempDirectory: None,
ClientFormatList: client_format_list,
ServerFormatList: None,
ClientFormatListResponse: client_format_list_response,
ServerFormatListResponse: None,
ClientLockClipboardData: None,
ServerLockClipboardData: None,
ClientUnlockClipboardData: None,
ServerUnlockClipboardData: None,
ClientFormatDataRequest: client_format_data_request,
ServerFormatDataRequest: None,
ClientFormatDataResponse: client_format_data_response,
ServerFormatDataResponse: None,
ClientFileContentsRequest: client_file_contents_request,
ServerFileContentsRequest: None,
ClientFileContentsResponse: client_file_contents_response,
ServerFileContentsResponse: None,
lastRequestedFormatId: 0,
};
let mut context = Box::new(context);
unsafe {
if FALSE == init_cliprdr(&mut (*context)) {
println!("Failed to init cliprdr");
Err(CliprdrError::CliprdrInit)
} else {
Ok(context)
}
}
}
}
impl Drop for CliprdrClientContext {
fn drop(&mut self) {
unsafe {
if FALSE == uninit_cliprdr(&mut *self) {
println!("Failed to uninit cliprdr");
} else {
println!("Succeeded to uninit cliprdr");
}
}
}
}

548
libs/clipboard/src/lib.rs Normal file
View File

@ -0,0 +1,548 @@
use cliprdr::*;
use hbb_common::{
log,
message_proto::cliprdr as msg_cliprdr,
message_proto::*,
tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
},
ResultType,
};
use std::{
boxed::Box,
ffi::{CStr, CString},
};
pub mod cliprdr;
#[derive(Debug)]
pub struct ConnID {
pub server_conn_id: u32,
pub remote_conn_id: u32,
}
lazy_static::lazy_static! {
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(ConnID, Message)>, TokioMutex<UnboundedReceiver<(ConnID, Message)>>) = {
let (tx, rx) = unbounded_channel();
(tx, TokioMutex::new(rx))
};
}
#[inline(always)]
pub fn get_rx_client_msg<'a>() -> &'a TokioMutex<UnboundedReceiver<(ConnID, Message)>> {
&MSG_CHANNEL_CLIENT.1
}
pub fn server_msg(context: &mut Box<CliprdrClientContext>, conn_id: ConnID, msg: Cliprdr) -> u32 {
match msg.union {
Some(msg_cliprdr::Union::ready(_)) => {
// proc ready
0
}
Some(msg_cliprdr::Union::format_list(req)) => {
log::debug!("server_format_list called");
let ret = server_format_list(context, conn_id, req);
log::debug!("server_format_list called, return {}", ret);
ret
}
Some(msg_cliprdr::Union::format_list_response(req)) => {
log::debug!("format_list_response called");
let ret = server_format_list_response(context, conn_id, req);
log::debug!("server_format_list_response called, return {}", ret);
ret
}
Some(msg_cliprdr::Union::format_data_request(req)) => {
log::debug!("format_data_request called");
let ret = server_format_data_request(context, conn_id, req);
log::debug!("server_format_data_request called, return {}", ret);
ret
}
Some(msg_cliprdr::Union::format_data_response(req)) => {
log::debug!("format_data_response called");
let ret = server_format_data_response(context, conn_id, req);
log::debug!("server_format_data_response called, return {}", ret);
ret
}
Some(msg_cliprdr::Union::file_contents_request(req)) => {
log::debug!("file_contents_request called");
let ret = server_file_contents_request(context, conn_id, req);
log::debug!("server_file_contents_request called, return {}", ret);
ret
}
Some(msg_cliprdr::Union::file_contents_response(req)) => {
log::debug!("file_contents_response called");
let ret = server_file_contents_response(context, conn_id, req);
log::debug!("server_file_contents_response called, return {}", ret);
ret
}
None => {
unreachable!()
}
}
}
fn server_format_list(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
data: CliprdrServerFormatList,
) -> u32 {
// do not check msgFlags for now
unsafe {
let num_formats = data.formats.len() as UINT32;
let mut formats = data
.formats
.into_iter()
.map(|format| {
if format.format.is_empty() {
CLIPRDR_FORMAT {
formatId: format.id as UINT32,
formatName: 0 as *mut _,
}
} else {
let n = match CString::new(format.format) {
Ok(n) => n,
Err(_) => CString::new("").unwrap(),
};
CLIPRDR_FORMAT {
formatId: format.id as UINT32,
formatName: n.into_raw(),
}
}
})
.collect::<Vec<CLIPRDR_FORMAT>>();
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let format_list = CLIPRDR_FORMAT_LIST {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
numFormats: num_formats,
formats: formats.as_mut_ptr(),
};
let ret = ((**context).ServerFormatList.unwrap())(&mut (**context), &format_list);
for f in formats {
if !f.formatName.is_null() {
// retake pointer to free memory
let _ = CString::from_raw(f.formatName);
}
}
ret as u32
}
}
fn server_format_list_response(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
data: CliprdrServerFormatListResponse,
) -> u32 {
unsafe {
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let format_list_response = CLIPRDR_FORMAT_LIST_RESPONSE {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16,
dataLen: 0 as UINT32,
};
let ret =
(**context).ServerFormatListResponse.unwrap()(&mut (**context), &format_list_response);
ret as u32
}
}
fn server_format_data_request(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
data: CliprdrServerFormatDataRequest,
) -> u32 {
unsafe {
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let format_data_request = CLIPRDR_FORMAT_DATA_REQUEST {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
requestedFormatId: data.requested_format_id as UINT32,
};
let ret =
((**context).ServerFormatDataRequest.unwrap())(&mut (**context), &format_data_request);
ret as u32
}
}
fn server_format_data_response(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
mut data: CliprdrServerFormatDataResponse,
) -> u32 {
unsafe {
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let format_data_response = CLIPRDR_FORMAT_DATA_RESPONSE {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16,
dataLen: data.format_data.len() as UINT32,
requestedFormatData: data.format_data.as_mut_ptr(),
};
let ret = ((**context).ServerFormatDataResponse.unwrap())(
&mut (**context),
&format_data_response,
);
ret as u32
}
}
fn server_file_contents_request(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
data: CliprdrFileContentsRequest,
) -> u32 {
unsafe {
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let file_contents_request = CLIPRDR_FILE_CONTENTS_REQUEST {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: 0 as UINT16,
dataLen: 0 as UINT32,
streamId: data.stream_id as UINT32,
listIndex: data.list_index as UINT32,
dwFlags: data.dw_flags as UINT32,
nPositionLow: data.n_position_low as UINT32,
nPositionHigh: data.n_position_high as UINT32,
cbRequested: data.cb_requested as UINT32,
haveClipDataId: if data.have_clip_data_id { TRUE } else { FALSE },
clipDataId: data.clip_data_id as UINT32,
};
let ret = ((**context).ServerFileContentsRequest.unwrap())(
&mut (**context),
&file_contents_request,
);
ret as u32
}
}
fn server_file_contents_response(
context: &mut Box<CliprdrClientContext>,
conn_id: ConnID,
mut data: CliprdrFileContentsResponse,
) -> u32 {
unsafe {
let server_conn_id = if conn_id.server_conn_id != 0 {
conn_id.server_conn_id as UINT32
} else {
data.server_conn_id as UINT32
};
let remote_conn_id = if conn_id.remote_conn_id != 0 {
conn_id.remote_conn_id as UINT32
} else {
data.remote_conn_id as UINT32
};
let file_contents_response = CLIPRDR_FILE_CONTENTS_RESPONSE {
serverConnID: server_conn_id,
remoteConnID: remote_conn_id,
msgType: 0 as UINT16,
msgFlags: data.msg_flags as UINT16,
dataLen: 4 + data.requested_data.len() as UINT32,
streamId: data.stream_id as UINT32,
cbRequested: data.requested_data.len() as UINT32,
requestedData: data.requested_data.as_mut_ptr(),
};
let ret = ((**context).ServerFileContentsResponse.unwrap())(
&mut (**context),
&file_contents_response,
);
ret as u32
}
}
pub fn create_cliprdr_context(enable_files: bool, enable_others: bool) -> ResultType<Box<CliprdrClientContext>> {
Ok(CliprdrClientContext::create(
enable_files,
enable_others,
Some(client_format_list),
Some(client_format_list_response),
Some(client_format_data_request),
Some(client_format_data_response),
Some(client_file_contents_request),
Some(client_file_contents_response),
)?)
}
extern "C" fn client_format_list(
_context: *mut CliprdrClientContext,
format_list: *const CLIPRDR_FORMAT_LIST,
) -> UINT {
log::debug!("client_format_list called");
let mut data = CliprdrServerFormatList::default();
unsafe {
let mut i = 0u32;
while i < (*format_list).numFormats {
let format_data = &(*(*format_list).formats.offset(i as isize));
if format_data.formatName.is_null() {
data.formats.push(CliprdrFormat {
id: format_data.formatId as i32,
format: "".to_owned(),
..Default::default()
});
} else {
let format_name = CStr::from_ptr(format_data.formatName).to_str();
let format_name = match format_name {
Ok(n) => n.to_owned(),
Err(_) => {
log::warn!("failed to get format name");
"".to_owned()
}
};
data.formats.push(CliprdrFormat {
id: format_data.formatId as i32,
format: format_name,
..Default::default()
});
}
i += 1;
}
data.server_conn_id = (*format_list).serverConnID as i32;
data.remote_conn_id = (*format_list).remoteConnID as i32;
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_format_list(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
extern "C" fn client_format_list_response(
_context: *mut CliprdrClientContext,
format_list_response: *const CLIPRDR_FORMAT_LIST_RESPONSE,
) -> UINT {
log::debug!("client_format_list_response called");
let mut data = CliprdrServerFormatListResponse::default();
unsafe {
data.server_conn_id = (*format_list_response).serverConnID as i32;
data.remote_conn_id = (*format_list_response).remoteConnID as i32;
data.msg_flags = (*format_list_response).msgFlags as i32;
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_format_list_response(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
extern "C" fn client_format_data_request(
_context: *mut CliprdrClientContext,
format_data_request: *const CLIPRDR_FORMAT_DATA_REQUEST,
) -> UINT {
log::debug!("client_format_data_request called");
let mut data = CliprdrServerFormatDataRequest::default();
unsafe {
data.server_conn_id = (*format_data_request).serverConnID as i32;
data.remote_conn_id = (*format_data_request).remoteConnID as i32;
data.requested_format_id = (*format_data_request).requestedFormatId as i32;
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_format_data_request(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
extern "C" fn client_format_data_response(
_context: *mut CliprdrClientContext,
format_data_response: *const CLIPRDR_FORMAT_DATA_RESPONSE,
) -> UINT {
log::debug!("client_format_data_response called");
let mut data = CliprdrServerFormatDataResponse::default();
unsafe {
data.server_conn_id = (*format_data_response).serverConnID as i32;
data.remote_conn_id = (*format_data_response).remoteConnID as i32;
data.msg_flags = (*format_data_response).msgFlags as i32;
data.format_data = std::slice::from_raw_parts(
(*format_data_response).requestedFormatData,
(*format_data_response).dataLen as usize,
)
.to_vec();
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_format_data_response(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
extern "C" fn client_file_contents_request(
_context: *mut CliprdrClientContext,
file_contents_request: *const CLIPRDR_FILE_CONTENTS_REQUEST,
) -> UINT {
log::debug!("client_file_contents_request called");
// TODO: support huge file?
// if (!cliprdr->hasHugeFileSupport)
// {
// if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) >
// UINT32_MAX)
// return ERROR_INVALID_PARAMETER;
// if (fileContentsRequest->nPositionHigh != 0)
// return ERROR_INVALID_PARAMETER;
// }
let mut data = CliprdrFileContentsRequest::default();
unsafe {
data.server_conn_id = (*file_contents_request).serverConnID as i32;
data.remote_conn_id = (*file_contents_request).remoteConnID as i32;
data.stream_id = (*file_contents_request).streamId as i32;
data.list_index = (*file_contents_request).listIndex as i32;
data.dw_flags = (*file_contents_request).dwFlags as i32;
data.n_position_low = (*file_contents_request).nPositionLow as i32;
data.n_position_high = (*file_contents_request).nPositionHigh as i32;
data.cb_requested = (*file_contents_request).cbRequested as i32;
data.have_clip_data_id = (*file_contents_request).haveClipDataId == TRUE;
data.clip_data_id = (*file_contents_request).clipDataId as i32;
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_file_contents_request(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
extern "C" fn client_file_contents_response(
_context: *mut CliprdrClientContext,
file_contents_response: *const CLIPRDR_FILE_CONTENTS_RESPONSE,
) -> UINT {
log::debug!("client_file_contents_response called");
let mut data = CliprdrFileContentsResponse::default();
unsafe {
data.server_conn_id = (*file_contents_response).serverConnID as i32;
data.remote_conn_id = (*file_contents_response).remoteConnID as i32;
data.msg_flags = (*file_contents_response).msgFlags as i32;
data.stream_id = (*file_contents_response).streamId as i32;
data.requested_data = std::slice::from_raw_parts(
(*file_contents_response).requestedData,
(*file_contents_response).cbRequested as usize,
)
.to_vec();
}
let conn_id = ConnID {
server_conn_id: data.server_conn_id as u32,
remote_conn_id: data.remote_conn_id as u32,
};
let mut msg = Message::new();
let mut cliprdr = Cliprdr::new();
cliprdr.set_file_contents_response(data);
msg.set_cliprdr(cliprdr);
// no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, msg)).unwrap();
0
}
#[cfg(test)]
mod tests {
// #[test]
// fn test_cliprdr_run() {
// super::cliprdr_run();
// }
}

File diff suppressed because it is too large Load Diff

View File

@ -306,6 +306,73 @@ message FileDirCreate {
string path = 2;
}
// main logic from freeRDP
message CliprdrMonitorReady {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
}
message CliprdrFormat {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 id = 3;
string format = 4;
}
message CliprdrServerFormatList {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
repeated CliprdrFormat formats = 3;
}
message CliprdrServerFormatListResponse {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 msg_flags = 3;
}
message CliprdrServerFormatDataRequest {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 requested_format_id = 3;
}
message CliprdrServerFormatDataResponse {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 msg_flags = 3;
bytes format_data = 4;
}
message CliprdrFileContentsRequest {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 stream_id = 3;
int32 list_index = 4;
int32 dw_flags = 5;
int32 n_position_low = 6;
int32 n_position_high = 7;
int32 cb_requested = 8;
bool have_clip_data_id = 9;
int32 clip_data_id = 10;
}
message CliprdrFileContentsResponse {
int32 server_conn_id = 1;
int32 remote_conn_id = 2;
int32 msg_flags = 3;
int32 stream_id = 4;
bytes requested_data = 5;
}
message Cliprdr {
oneof union {
CliprdrMonitorReady ready = 1;
CliprdrServerFormatList format_list = 2;
CliprdrServerFormatListResponse format_list_response = 3;
CliprdrServerFormatDataRequest format_data_request = 4;
CliprdrServerFormatDataResponse format_data_response = 5;
CliprdrFileContentsRequest file_contents_request = 6;
CliprdrFileContentsResponse file_contents_response = 7;
}
}
message SwitchDisplay {
int32 display = 1;
sint32 x = 2;
@ -405,5 +472,6 @@ message Message {
FileAction file_action = 17;
FileResponse file_response = 18;
Misc misc = 19;
Cliprdr cliprdr = 20;
}
}

View File

@ -16,6 +16,7 @@ use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all};
use std::sync::{Arc, Mutex};
pub const CLIPBOARD_NAME: &'static str = "clipboard";
pub const CLIPRDR_NAME: &'static str = "cliprdr";
pub const CLIPBOARD_INTERVAL: u64 = 333;
lazy_static::lazy_static! {

View File

@ -29,6 +29,8 @@ use std::{
mod audio_service;
mod clipboard_service;
#[cfg(windows)]
pub mod cliprdr_service;
mod connection;
pub mod input_service;
mod service;
@ -61,6 +63,8 @@ pub fn new() -> ServerPtr {
server.add_service(Box::new(audio_service::new()));
server.add_service(Box::new(video_service::new()));
server.add_service(Box::new(clipboard_service::new()));
#[cfg(windows)]
server.add_service(Box::new(cliprdr_service::new()));
server.add_service(Box::new(input_service::new_cursor()));
server.add_service(Box::new(input_service::new_pos()));
Arc::new(RwLock::new(server))

View File

@ -0,0 +1,104 @@
use super::*;
use clipboard::{create_cliprdr_context, get_rx_client_msg, server_msg, ConnID};
use hbb_common::{
log,
tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex,
},
tokio::time::{self, Duration, Instant},
ResultType,
};
use std::sync::atomic::{AtomicBool, Ordering};
pub use crate::common::CLIPRDR_NAME as NAME;
lazy_static::lazy_static! {
static ref MSG_CHANNEL_SERVER: (UnboundedSender<(ConnID, Cliprdr)>, TokioMutex<UnboundedReceiver<(ConnID, Cliprdr)>>) = {
let (tx, rx) = unbounded_channel();
(tx, TokioMutex::new(rx))
};
}
static RUNNING: AtomicBool = AtomicBool::new(false);
pub fn new() -> GenericService {
let sp = GenericService::new(NAME, true);
sp.run::<_>(listen::run);
sp
}
pub fn handle_serve_cliprdr_msg(id: i32, msg: Cliprdr) {
if RUNNING.load(Ordering::SeqCst) {
log::debug!("handle handle_serve_cliprdr_msg");
MSG_CHANNEL_SERVER
.0
.send((
ConnID {
server_conn_id: id as u32,
remote_conn_id: 0,
},
msg,
))
.unwrap();
} else {
// should not reach this branch
}
}
mod listen {
use super::*;
static WAIT: Duration = Duration::from_millis(1500);
#[tokio::main]
pub async fn run(sp: GenericService) -> ResultType<()> {
let mut cliprdr_context = create_cliprdr_context(true, false)?;
RUNNING.store(false, Ordering::SeqCst);
let mut timer = time::interval_at(Instant::now() + WAIT, WAIT);
let mut client_rx = get_rx_client_msg().lock().await;
let mut server_rx = MSG_CHANNEL_SERVER.1.lock().await;
while sp.ok() {
RUNNING.store(true, Ordering::SeqCst);
tokio::select! {
msg = client_rx.recv() => {
match msg {
Some((conn_id, msg)) => {
if conn_id.server_conn_id == 0 {
sp.send(msg)
} else {
sp.send_to(msg, conn_id.server_conn_id as i32)
}
}
None => {
unreachable!()
}
}
}
msg = server_rx.recv() => {
match msg {
Some((conn_id, msg)) => {
let res = server_msg(&mut cliprdr_context, conn_id, msg);
if res != 0 {
// log::warn!("failed to process message for {}", id);
}
}
None => {
unreachable!()
}
}
}
_ = timer.tick() => {},
}
sp.snapshot(|_| Ok(()))?;
}
RUNNING.store(false, Ordering::SeqCst);
log::info!("Clipboard listener stopped!");
Ok(())
}
}

View File

@ -224,6 +224,10 @@ impl Connection {
s.write().unwrap().subscribe(
super::clipboard_service::NAME,
conn.inner.clone(), conn.clipboard_enabled() && conn.keyboard);
#[cfg(windows)]
s.write().unwrap().subscribe(
super::cliprdr_service::NAME,
conn.inner.clone(), conn.clipboard_enabled() && conn.keyboard);
}
} else if &name == "audio" {
conn.audio = enabled;
@ -600,6 +604,8 @@ impl Connection {
}
if !self.clipboard_enabled() || !self.keyboard {
noperms.push(super::clipboard_service::NAME);
#[cfg(windows)]
noperms.push(super::cliprdr_service::NAME);
}
if !self.audio_enabled() {
noperms.push(super::audio_service::NAME);
@ -824,6 +830,11 @@ impl Connection {
update_clipboard(cb, None);
}
}
#[cfg(windows)]
Some(message::Union::cliprdr(clip)) => {
log::debug!("received cliprdr msg");
cliprdr_service::handle_serve_cliprdr_msg(self.inner.id, clip)
}
Some(message::Union::file_action(fa)) => {
if self.file_transfer.is_some() {
match fa.union {
@ -993,6 +1004,12 @@ impl Connection {
self.inner.clone(),
self.clipboard_enabled() && self.keyboard,
);
#[cfg(windows)]
s.write().unwrap().subscribe(
super::cliprdr_service::NAME,
self.inner.clone(),
self.clipboard_enabled() && self.keyboard,
);
}
}
}

View File

@ -137,6 +137,12 @@ impl<T: Subscriber + From<ConnInner>> ServiceTmpl<T> {
self.send_shared(Arc::new(msg));
}
pub fn send_to(&self, msg: Message, id: i32) {
if let Some(s) = self.0.write().unwrap().subscribes.get_mut(&id) {
s.send(Arc::new(msg));
}
}
pub fn send_shared(&self, msg: Arc<Message>) {
let mut lock = self.0.write().unwrap();
for s in lock.subscribes.values_mut() {

View File

@ -2,6 +2,10 @@ use crate::client::*;
use crate::common::{
self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL,
};
#[cfg(windows)]
use clipboard::{
cliprdr::CliprdrClientContext, create_cliprdr_context, get_rx_client_msg, server_msg, ConnID,
};
use enigo::{self, Enigo, KeyboardControllable};
use hbb_common::{
allow_err,
@ -1159,6 +1163,16 @@ async fn io_loop(handler: Handler) {
.as_mut()
.map(|v| v.render_frame(data).ok());
});
#[cfg(windows)]
let cliprdr_context = match create_cliprdr_context(true, false) {
Ok(context) => Some(context),
Err(err) => {
handler.msgbox("error", "Create clipboard error", &err.to_string());
None
}
};
let mut remote = Remote {
handler,
video_sender,
@ -1172,6 +1186,10 @@ async fn io_loop(handler: Handler) {
timer: time::interval(SEC30),
last_update_jobs_status: (Instant::now(), Default::default()),
first_frame: false,
#[cfg(windows)]
cliprdr_context,
#[cfg(windows)]
pid: std::process::id(),
};
remote.io_loop().await;
}
@ -1211,6 +1229,10 @@ struct Remote {
timer: Interval,
last_update_jobs_status: (Instant, HashMap<i32, u64>),
first_frame: bool,
#[cfg(windows)]
cliprdr_context: Option<Box<CliprdrClientContext>>,
#[cfg(windows)]
pid: u32,
}
impl Remote {
@ -1230,6 +1252,13 @@ impl Remote {
}
self.handler
.call("setConnectionType", &make_args!(peer.is_secured(), direct));
// just build for now
#[cfg(not(windows))]
let (_client_tx, mut client_rx) = mpsc::unbounded_channel::<i32>();
#[cfg(windows)]
let mut client_rx = get_rx_client_msg().lock().await;
loop {
tokio::select! {
res = peer.next() => {
@ -1260,6 +1289,21 @@ impl Remote {
}
}
}
msg = client_rx.recv() => {
#[cfg(not(windows))]
println!("{:?}", msg);
#[cfg(windows)]
match msg {
Some((conn_id, msg)) => {
if conn_id.remote_conn_id == 0 || conn_id.remote_conn_id == self.pid {
allow_err!(peer.send(&msg).await);
}
}
None => {
unreachable!()
}
}
}
_ = self.timer.tick() => {
if last_recv_time.elapsed() >= SEC30 {
self.handler.msgbox("error", "Connection Error", "Timeout");
@ -1631,6 +1675,24 @@ impl Remote {
update_clipboard(cb, Some(&self.old_clipboard));
}
}
#[allow(unused_variables)]
Some(message::Union::cliprdr(clip)) => {
log::debug!("received cliprdr msg");
#[cfg(windows)]
if !self.handler.lc.read().unwrap().disable_clipboard {
if let Some(context) = &mut self.cliprdr_context {
let res = server_msg(
context,
ConnID {
server_conn_id: 0,
remote_conn_id: self.pid,
},
clip,
);
log::debug!("server msg returns {}", res);
}
}
}
Some(message::Union::file_response(fr)) => match fr.union {
Some(file_response::Union::dir(fd)) => {
let entries = fd.entries.to_vec();