windows获取窗口相关的api搞定等待完善message的管理管理逻辑。
1. message不能重复设置多次,相同的message只设置一次 2. 鼠标在L3移出去就发送剪切板消息不行,需要换成监听windows剪切板,只有内容变动的时候并且鼠标移动到窗口外面再发送,避免发送重复的消息。 3. 鼠标在L0只要前台窗口时VM horizontal时移出窗口外就进行剪切板的同步。 4. 单个消息使用时间作为magic str,这部分需要适配一下。
This commit is contained in:
parent
041a1526d6
commit
4d04dc2677
|
@ -16,7 +16,7 @@ select = "0.5"
|
||||||
scraper = "0.12"
|
scraper = "0.12"
|
||||||
arboard = "3.4.0"
|
arboard = "3.4.0"
|
||||||
|
|
||||||
winapi = { version = "0.3.9", features = ["winuser"] }
|
winapi = { version = "0.3.9", features = ["winuser", "psapi"] }
|
||||||
|
|
||||||
[profile.test]
|
[profile.test]
|
||||||
env = { "RUST_LOG" = "debug" }
|
env = { "RUST_LOG" = "debug" }
|
||||||
|
|
58
src/lib.rs
58
src/lib.rs
|
@ -1,19 +1,20 @@
|
||||||
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
||||||
use reqwest::header::{HeaderMap, CONTENT_TYPE, COOKIE};
|
use reqwest::header::HeaderMap;
|
||||||
use reqwest::{Client, Response};
|
use reqwest::{Client, Response};
|
||||||
use scraper::{Html, Selector};
|
use scraper::{Html, Selector};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ops::Index;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::{Mutex};
|
use tokio::sync::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{task, time};
|
use tokio::{task, time};
|
||||||
use std::collections::{BTreeMap, VecDeque};
|
use std::collections::BTreeMap;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
pub mod wclip;
|
pub mod wclip;
|
||||||
pub mod sys_res;
|
pub mod sys_res;
|
||||||
|
|
||||||
|
use sys_res::*;
|
||||||
pub struct ClipboardSync {
|
pub struct ClipboardSync {
|
||||||
user_name: String,
|
user_name: String,
|
||||||
password: String,
|
password: String,
|
||||||
|
@ -22,7 +23,7 @@ pub struct ClipboardSync {
|
||||||
cookies: String,
|
cookies: String,
|
||||||
clip: wclip::Wclip,
|
clip: wclip::Wclip,
|
||||||
//last message magic
|
//last message magic
|
||||||
cache_magic: u8,
|
cache_magic: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42";
|
const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42";
|
||||||
|
@ -35,11 +36,15 @@ pub struct ClipboardMsgs {
|
||||||
pub msgs: Vec<String>,
|
pub msgs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 同步获取消息的线程
|
||||||
async fn msg_sync(ctx:Arc<Mutex<ClipboardSync>>){
|
async fn msg_sync(ctx:Arc<Mutex<ClipboardSync>>){
|
||||||
let mut ctx = ctx.lock().await;
|
let mut ctx = ctx.lock().await;
|
||||||
loop{
|
loop{
|
||||||
let _ = ctx.update_msg().await;
|
let _ = ctx.update_msg().await;
|
||||||
time::sleep(Duration::new(10, 0)).await;
|
time::sleep(Duration::new(10, 0)).await;
|
||||||
|
let prog_name = get_foredround_window_name();
|
||||||
|
if prog_name == "VMware Horizon Client"{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn start_msg_sync(ctx:Arc<Mutex<ClipboardSync>>) -> Result<task::JoinHandle<()>, Box<dyn Error>>{
|
pub async fn start_msg_sync(ctx:Arc<Mutex<ClipboardSync>>) -> Result<task::JoinHandle<()>, Box<dyn Error>>{
|
||||||
|
@ -48,8 +53,10 @@ pub async fn start_msg_sync(ctx:Arc<Mutex<ClipboardSync>>) -> Result<task::JoinH
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Msg <'a>{
|
enum Msg <'a>{
|
||||||
Msg(&'a str),
|
// magic str, message context
|
||||||
Sub((u8, u8, u8, &'a str)),
|
Msg((String, &'a str)),
|
||||||
|
//index of message pack, total message pack number, magic str, message context
|
||||||
|
Sub((u8, u8, String, &'a str)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipboardSync {
|
impl ClipboardSync {
|
||||||
|
@ -61,7 +68,7 @@ impl ClipboardSync {
|
||||||
ip: ip.to_string(),
|
ip: ip.to_string(),
|
||||||
cookies: "".to_string(),
|
cookies: "".to_string(),
|
||||||
clip: wclip::Wclip::new(),
|
clip: wclip::Wclip::new(),
|
||||||
cache_magic: 0xff,
|
cache_magic: "0xff".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +170,8 @@ impl ClipboardSync {
|
||||||
self.msg2clip(&resp).await;
|
self.msg2clip(&resp).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//解析可能存在的消息数据
|
||||||
fn parse_msg<'a>(msg: &'a str) -> Msg {
|
fn parse_msg<'a>(msg: &'a str) -> Msg {
|
||||||
//x|x|x| -> index|total|magic|
|
//x|x|x| -> index|total|magic|
|
||||||
let head = &msg[0..7];
|
let head = &msg[0..7];
|
||||||
|
@ -177,17 +186,21 @@ impl ClipboardSync {
|
||||||
}).map(|x|x.as_bytes()[0] - b'!').collect::<Vec<_>>();
|
}).map(|x|x.as_bytes()[0] - b'!').collect::<Vec<_>>();
|
||||||
|
|
||||||
if check.len() != 3 {
|
if check.len() != 3 {
|
||||||
return Msg::Msg(msg)
|
//TODO: get magic
|
||||||
|
return Msg::Msg(("maigic".to_string(), msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Msg::Sub((check[0], check[1], check[2], body));
|
return Msg::Sub((check[0], check[1], check[2].to_string(), body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//将message解析并放置到剪切板上
|
||||||
pub async fn msg2clip(&mut self, html: &str) {
|
pub async fn msg2clip(&mut self, html: &str) {
|
||||||
// log::info!("html: {}", html);
|
// log::info!("html: {}", html);
|
||||||
let document = Html::parse_document(html);
|
let document = Html::parse_document(html);
|
||||||
|
// 所有剪切板的数据都是在code这个html lable上的
|
||||||
let selector = Selector::parse("code").unwrap();
|
let selector = Selector::parse("code").unwrap();
|
||||||
let mut msg_map = BTreeMap::new();
|
let mut msg_map = BTreeMap::new();
|
||||||
let mut magic_ref = 0xff;
|
let mut magic_ref = "0xff".to_string();
|
||||||
let mut is_first = true;
|
let mut is_first = true;
|
||||||
for element in document.select(&selector).into_iter() {
|
for element in document.select(&selector).into_iter() {
|
||||||
//let text = element.text().collect::<Vec<_>>().concat();
|
//let text = element.text().collect::<Vec<_>>().concat();
|
||||||
|
@ -195,20 +208,21 @@ impl ClipboardSync {
|
||||||
log::info!("Found: [{}]", text);
|
log::info!("Found: [{}]", text);
|
||||||
let msg = ClipboardSync::parse_msg(text.as_str());
|
let msg = ClipboardSync::parse_msg(text.as_str());
|
||||||
match msg {
|
match msg {
|
||||||
|
//一整个消息。直接复制到剪切板即可
|
||||||
Msg::Msg(msg) => {
|
Msg::Msg(msg) => {
|
||||||
if magic_ref == 0xff {
|
if magic_ref == "0xff" {
|
||||||
self.clip.set(&msg);
|
self.clip.set(msg.1);
|
||||||
break;
|
break;//处理完毕。直接退出
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Msg::Sub((index, total, magic, _body)) => {
|
Msg::Sub((index, total, magic, body)) => {
|
||||||
magic_ref = if magic_ref == 0xff {magic} else {magic_ref};
|
if magic_ref == "0xff" {
|
||||||
if magic_ref != magic { // other message ignore
|
magic_ref = magic;
|
||||||
if is_first {
|
} else {
|
||||||
break;
|
if magic_ref != magic { // other message ignore
|
||||||
|
is_first = false;
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
is_first = false;
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if msg_map.len() == 0 && (
|
if msg_map.len() == 0 && (
|
||||||
self.cache_magic == magic_ref // message is repeated ignore it
|
self.cache_magic == magic_ref // message is repeated ignore it
|
||||||
|
@ -217,7 +231,7 @@ impl ClipboardSync {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// same msg pack, append to list
|
// same msg pack, append to list
|
||||||
msg_map.insert(index, text);
|
msg_map.insert(index, body.to_string());
|
||||||
if msg_map.len() as u8 == total {
|
if msg_map.len() as u8 == total {
|
||||||
let msg = msg_map.into_iter().map(|(_key, v)| v).collect::<String>();
|
let msg = msg_map.into_iter().map(|(_key, v)| v).collect::<String>();
|
||||||
self.cache_magic = magic_ref; // save for next msg
|
self.cache_magic = magic_ref; // save for next msg
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
extern crate winapi;
|
extern crate winapi;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
use std::ptr::null_mut;
|
use std::path::Path;
|
||||||
use winapi::um::winuser::{
|
use winapi::um::winuser::{
|
||||||
GetCursorPos, GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN,
|
GetCursorPos, GetSystemMetrics, SM_CXSCREEN, SM_CYSCREEN,GetWindowRect
|
||||||
FindWindowA, GetWindowRect
|
|
||||||
};
|
};
|
||||||
use winapi::shared::windef::{
|
use winapi::shared::windef::{
|
||||||
POINT,
|
POINT,
|
||||||
RECT,
|
RECT,
|
||||||
};
|
};
|
||||||
use winapi::um::winuser::{GetForegroundWindow, GetWindowTextW, GetClassNameW, GetWindowThreadProcessId};
|
use winapi::um::winuser::{GetForegroundWindow, GetWindowThreadProcessId};
|
||||||
use std::ptr;
|
use std::ffi::OsString;
|
||||||
use std::ffi::{OsString, CString};
|
|
||||||
use std::os::windows::ffi::OsStringExt;
|
use std::os::windows::ffi::OsStringExt;
|
||||||
use winapi::um::processthreadsapi::{OpenProcess, GetProcessImageFileNameA};
|
use winapi::um::processthreadsapi::OpenProcess;
|
||||||
use winapi::um::winnt::PROCESS_QUERY_INFORMATION;
|
use winapi::um::winnt::PROCESS_QUERY_INFORMATION;
|
||||||
|
use winapi::um::psapi::GetProcessImageFileNameW;
|
||||||
|
|
||||||
pub fn screen_size() -> (i32, i32) {
|
pub fn screen_size() -> (i32, i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -35,69 +33,77 @@ pub fn cursor_pos() -> (i32, i32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_window_rect() -> Option<(i32, i32, i32, i32)> {
|
pub fn get_foredround_window_rect() -> Option<(i32, i32, i32, i32)> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let h = GetForegroundWindow();
|
let h = GetForegroundWindow();
|
||||||
|
|
||||||
let mut rect: RECT = std::mem::zeroed();
|
let mut rect: RECT = std::mem::zeroed();
|
||||||
if GetWindowRect(h, &mut rect) != 0 {
|
if GetWindowRect(h, &mut rect) != 0 {
|
||||||
|
println!("GetWindowRect: {:?}", rect);
|
||||||
Some((rect.left, rect.top, rect.right, rect.bottom))
|
Some((rect.left, rect.top, rect.right, rect.bottom))
|
||||||
} else {
|
} else {
|
||||||
|
println!("cant get foregtound window rect");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn get_foredround_window_name() {
|
pub fn get_foredround_window_name() -> String {
|
||||||
|
let mut name = OsString::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
let foreground_window = GetForegroundWindow();
|
let foreground_window = GetForegroundWindow();
|
||||||
|
|
||||||
// let mut process_id = 0;
|
let mut process_id = 0;
|
||||||
// GetWindowThreadProcessId(foreground_window, &mut process_id);
|
GetWindowThreadProcessId(foreground_window, &mut process_id);
|
||||||
|
|
||||||
// let mut process_name: [u16; 1024] = [0; 1024];
|
// let mut process_name: [u16; 1024] = [0; 1024];
|
||||||
// GetWindowTextW(foreground_window, process_name.as_mut_ptr(), 1024);
|
// GetWindowTextW(foreground_window, process_name.as_mut_ptr(), 1024);
|
||||||
|
|
||||||
let process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
|
let process_handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0, process_id);
|
||||||
if process_handle.is_null() {
|
if process_handle.is_null() {
|
||||||
return None;
|
panic!("Cant open foreground process with {}!", process_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut image_name = [0u8; 1024];
|
let mut image_name = [0u16; 1024];
|
||||||
let mut image_name_size = image_name.len() as u32;
|
if GetProcessImageFileNameW(process_handle, image_name.as_mut_ptr() as *mut _, image_name.len() as u32) == 0 {
|
||||||
if GetProcessImageFileNameA(process_handle, image_name.as_mut_ptr() as *mut _, &mut image_name_size) == 0 {
|
panic!("Cant Get foreground prog name!")
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut class_name: [u16; 256] = [0; 256];
|
// let mut class_name: [u16; 256] = [0; 256];
|
||||||
GetClassNameW(foreground_window, class_name.as_mut_ptr(), 256);
|
// GetClassNameW(foreground_window, class_name.as_mut_ptr(), 256);
|
||||||
|
|
||||||
let mut process_name_str = OsString::from_wide(&process_name);
|
name = OsString::from_wide(&image_name);
|
||||||
let mut class_name_str = OsString::from_wide(&class_name);
|
// let mut class_name_str = OsString::from_wide(&class_name);
|
||||||
|
// log::info!("Class Name: {}", class_name_str.to_string_lossy().to_string());
|
||||||
log::info!("Process Name: {}", process_name_str.to_string_lossy().to_string());
|
|
||||||
log::info!("Class Name: {}", class_name_str.to_string_lossy().to_string());
|
|
||||||
}
|
}
|
||||||
|
let path = Path::new(&name);
|
||||||
|
let name = path.file_name().unwrap().to_string_lossy().to_string();
|
||||||
|
println!("Current Proc Name: [{}]", name);
|
||||||
|
name
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_screen_size() {
|
fn test_screen_size() {
|
||||||
|
// env_logger::init();
|
||||||
let (width, height) = screen_size();
|
let (width, height) = screen_size();
|
||||||
assert!(width > 0);
|
assert!(width > 0);
|
||||||
assert!(height > 0);
|
assert!(height > 0);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_window_rect() {
|
fn test_get_foredround_window_rect() {
|
||||||
let (x, y, width, height) = get_window_rect().unwrap();
|
// env_logger::init();
|
||||||
assert!(x >= 0);
|
let (x, y, width, height) = get_foredround_window_rect().unwrap();
|
||||||
assert!(y >= 0);
|
// assert!(x >= 0);
|
||||||
|
// assert!(y >= 0);
|
||||||
assert!(width > 0);
|
assert!(width > 0);
|
||||||
assert!(height > 0);
|
assert!(height > 0);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cursor_pos() {
|
fn test_cursor_pos() {
|
||||||
|
// env_logger::init();
|
||||||
let (x, y) = cursor_pos();
|
let (x, y) = cursor_pos();
|
||||||
assert!(x >= 0);
|
assert!(x >= 0);
|
||||||
assert!(y >= 0);
|
assert!(y >= 0);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user