diff --git a/Readme.md b/Readme.md index c96dae7..4e359fa 100644 --- a/Readme.md +++ b/Readme.md @@ -12,6 +12,8 @@ Config file # It will send messages based on timeout when set to true send_messages = false +# minize the game after it has send the message or keypress mode +minimize_after_action = true # Message it will send messages = [ 'test1', @@ -27,4 +29,11 @@ message_start_time_utc = '12:00' message_stop_time_utc = '23:00' # Timeout used when sending messages message_timeout_mins = 8 + +# Press a key for anti-afk instead (will requires the game to go unminimized) +keypress_mode = false +# which key to press (keypress_mode) +key = ' ' +# how many millisecond to hold the key down (keypress_mode) +key_hold_time = 80 ``` diff --git a/config.txt b/config.txt index 7aef6c5..2ae386f 100644 --- a/config.txt +++ b/config.txt @@ -1,7 +1,10 @@ -minimize_after_message = false -send_messages = true -messages = ['t'] +send_messages = false +minimize_after_action = true +messages = ['Join our discord, we are always recruiting: discord.gg/BoB'] chat_type = 'Public' message_start_time_utc = '12:00' message_stop_time_utc = '23:00' -message_timeout_mins = 0 +message_timeout_mins = 8 +keypress_mode = false +key = ' ' +key_hold_time = 80 diff --git a/src/actions.rs b/src/actions.rs index a2b6cd6..21c10e8 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -20,14 +20,33 @@ fn make_l_param(lo_word: i32, hi_word: i32) -> i32 { (hi_word << 16) | (lo_word & 0xffff) } -pub fn anti_afk(game_name: &str, mut run_once_no_game: bool) -> bool { +pub fn anti_afk(cfg: &structs::SeederConfig, game_name: &str, mut run_once_no_game: bool) -> bool { let game_info = is_running(game_name); if game_info.is_running { unsafe { let current_forground_window = GetForegroundWindow(); - let l_param = make_l_param(20, 20); - SendMessageW(game_info.game_process, 0x201, 0, l_param as isize); - SendMessageW(game_info.game_process, 0x202, 0, l_param as isize); + + if cfg.keypress_mode { + ShowWindow(game_info.game_process, 9); + SetForegroundWindow(game_info.game_process); + sleep(Duration::from_millis(1808)); + + if cfg.key == "tab" { + send_keys::key_enter(0x0F, cfg.key_hold_time); + } else { + send_keys::send_key(&cfg.key, cfg.key_hold_time); + } + sleep(Duration::from_secs(1)); + + if cfg.minimize_after_action { + ShowWindow(game_info.game_process, 6); + } + } else { + // use mousebutton + let l_param = make_l_param(20, 20); + SendMessageW(game_info.game_process, 0x201, 0, l_param as isize); + SendMessageW(game_info.game_process, 0x202, 0, l_param as isize); + } SetForegroundWindow(current_forground_window); // reset no game check run_once_no_game = true; @@ -188,7 +207,7 @@ pub fn send_message( structs::ChatType::Squad => message_action(current_message, squad_key), } - if cfg.minimize_after_message { + if cfg.minimize_after_action { ShowWindow(game_info.game_process, 6); } } diff --git a/src/bf1.rs b/src/bf1.rs index 030b652..e3584f0 100644 --- a/src/bf1.rs +++ b/src/bf1.rs @@ -1,9 +1,9 @@ -mod shared_main; -mod chars; -mod send_keys; -mod actions; -mod structs; - -fn main() { - shared_main::anti_afk_runner("Battlefield™ 1"); -} \ No newline at end of file +mod actions; +mod chars; +mod send_keys; +mod shared_main; +mod structs; + +fn main() { + shared_main::anti_afk_runner("Battlefield™ 1"); +} diff --git a/src/bf2042.rs b/src/bf2042.rs index 27ef5d5..fae427b 100644 --- a/src/bf2042.rs +++ b/src/bf2042.rs @@ -1,9 +1,9 @@ -mod shared_main; -mod chars; -mod send_keys; -mod actions; -mod structs; - -fn main() { - shared_main::anti_afk_runner("Battlefield™ 2042"); -} \ No newline at end of file +mod actions; +mod chars; +mod send_keys; +mod shared_main; +mod structs; + +fn main() { + shared_main::anti_afk_runner("Battlefield™ 2042"); +} diff --git a/src/bf4.rs b/src/bf4.rs index fa2dc18..0328708 100644 --- a/src/bf4.rs +++ b/src/bf4.rs @@ -1,9 +1,9 @@ -mod shared_main; -mod chars; -mod send_keys; -mod actions; -mod structs; - -fn main() { - shared_main::anti_afk_runner("Battlefield 4"); -} \ No newline at end of file +mod actions; +mod chars; +mod send_keys; +mod shared_main; +mod structs; + +fn main() { + shared_main::anti_afk_runner("Battlefield 4"); +} diff --git a/src/bfv.rs b/src/bfv.rs index 3d54689..b0bba2f 100644 --- a/src/bfv.rs +++ b/src/bfv.rs @@ -1,9 +1,9 @@ -mod shared_main; -mod chars; -mod send_keys; -mod actions; -mod structs; - -fn main() { - shared_main::anti_afk_runner("Battlefield™ V"); +mod shared_main; +mod chars; +mod send_keys; +mod actions; +mod structs; + +fn main() { + shared_main::anti_afk_runner("Battlefield™ V"); } \ No newline at end of file diff --git a/src/chars.rs b/src/chars.rs index 62bd835..a6fa010 100644 --- a/src/chars.rs +++ b/src/chars.rs @@ -1,90 +1,85 @@ -const CHAR_MAPPING: [u16; 47] = [ - 0x33, //, - 0x0C, //- - 0x34, //. - 0x35, //\/ - 0x0B, //0 - 0x02, //1 - 0x03, //2 - 0x04, //3 - 0x05, //4 - 0x06, //5 - 0x07, //6 - 0x08, //7 - 0x09, //8 - 0x0A, //9 - 0x0, - 0x27, //; - 0x0, - 0x0D, //= - 0x0, - 0x0, - 0x0, - 0x1E, //A - 0x30, //B - 0x2E, //C - 0x20, //D - 0x12, //E - 0x21, //F - 0x22, //G - 0x23, //H - 0x17, //I - 0x24, //J - 0x25, //K - 0x26, //L - 0x32, //M - 0x31, //N - 0x18, //O - 0x19, //P - 0x10, //Q - 0x13, //R - 0x1F, //S - 0x14, //T - 0x16, //U - 0x2F, //V - 0x11, //W - 0x2D, //X - 0x15, //Y - 0x2C, //Z -]; - -#[derive(Debug)] -pub enum DXCode { - Symbol(u16), - Shifted(u16) -} - -/** - Convert ASCII char into DirectX key code - */ -pub fn char_to_dxcodes(c: char) -> Option { - let mut c_u8 = c as u8; - - if c.is_ascii_lowercase() { - c_u8 &= 0xdf; - } - - if c.is_ascii_whitespace() { - return Some(DXCode::Symbol(0x39)); - } - - if c == ":".chars().next().unwrap() { - return Some(DXCode::Shifted(0x27)); - } - - if c_u8 < 0x5B && c_u8 > 0x2B { - let index = c_u8 - 0x2C; - let code = CHAR_MAPPING[index as usize]; - // println!("{} {}", index, code); - if code == 0x0 { - None - } else if c.is_ascii_uppercase() { - // Press SHIFT - Some(DXCode::Shifted(code)) - } else { - Some(DXCode::Symbol(code)) - } - } else { - None - } -} \ No newline at end of file +const CHAR_MAPPING: [u16; 47] = [ + 0x33, //, + 0x0C, //- + 0x34, //. + 0x35, //\/ + 0x0B, //0 + 0x02, //1 + 0x03, //2 + 0x04, //3 + 0x05, //4 + 0x06, //5 + 0x07, //6 + 0x08, //7 + 0x09, //8 + 0x0A, //9 + 0x0, 0x27, //; + 0x0, 0x0D, //= + 0x0, 0x0, 0x0, 0x1E, //A + 0x30, //B + 0x2E, //C + 0x20, //D + 0x12, //E + 0x21, //F + 0x22, //G + 0x23, //H + 0x17, //I + 0x24, //J + 0x25, //K + 0x26, //L + 0x32, //M + 0x31, //N + 0x18, //O + 0x19, //P + 0x10, //Q + 0x13, //R + 0x1F, //S + 0x14, //T + 0x16, //U + 0x2F, //V + 0x11, //W + 0x2D, //X + 0x15, //Y + 0x2C, //Z +]; + +#[derive(Debug)] +pub enum DXCode { + Symbol(u16), + Shifted(u16), +} + +/** + Convert ASCII char into DirectX key code +*/ +pub fn char_to_dxcodes(c: char) -> Option { + let mut c_u8 = c as u8; + + if c.is_ascii_lowercase() { + c_u8 &= 0xdf; + } + + if c.is_ascii_whitespace() { + return Some(DXCode::Symbol(0x39)); + } + + if c == ":".chars().next().unwrap() { + return Some(DXCode::Shifted(0x27)); + } + + if c_u8 < 0x5B && c_u8 > 0x2B { + let index = c_u8 - 0x2C; + let code = CHAR_MAPPING[index as usize]; + // println!("{} {}", index, code); + if code == 0x0 { + None + } else if c.is_ascii_uppercase() { + // Press SHIFT + Some(DXCode::Shifted(code)) + } else { + Some(DXCode::Symbol(code)) + } + } else { + None + } +} diff --git a/src/send_keys.rs b/src/send_keys.rs index f3d9bf4..9b1d0fc 100644 --- a/src/send_keys.rs +++ b/src/send_keys.rs @@ -1,67 +1,79 @@ -use std::{mem, thread::sleep, time::Duration}; -use winapi::um::winuser::{INPUT, INPUT_KEYBOARD, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, SendInput}; - -use crate::chars::DXCode; -// key codes: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - -unsafe fn create_input(key_code: u16, wvk: u16, flags: u32) -> INPUT { - let mut input = mem::zeroed::(); - input.type_ = INPUT_KEYBOARD; - let mut ki = input.u.ki_mut(); - ki.wVk = wvk; - ki.wScan = key_code; - ki.dwExtraInfo = 0; - ki.dwFlags = flags; - ki.time = 0; - input -} - -unsafe fn key_down(key_code: u16) { - let mut input = create_input(key_code, 0, KEYEVENTF_SCANCODE); - SendInput(1, &mut input, mem::size_of::() as i32); -} - -unsafe fn key_up(key_code: u16) { - let mut input = create_input(key_code, 0, KEYEVENTF_KEYUP); - SendInput(1, &mut input, mem::size_of::() as i32); -} - -unsafe fn special_down(key_code: u16) { - let mut input = create_input(0, key_code, KEYEVENTF_EXTENDEDKEY); - SendInput(1, &mut input, mem::size_of::() as i32); -} - -unsafe fn special_up(key_code: u16) { - let mut input = create_input(0, key_code, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP); - SendInput(1, &mut input, mem::size_of::() as i32); -} - -pub unsafe fn spam_keys(key_code: u16, timeout: u64, amount: i16) { - for _ in 0..amount { - key_enter(key_code, timeout); - sleep(Duration::from_millis(timeout)); - } -} - -pub unsafe fn key_enter(key_code: u16, timeout: u64) { - key_down(key_code); - sleep(Duration::from_millis(timeout)); - key_up(key_code); -} - -pub unsafe fn send_string(keys: Vec) { - for key in keys { - match key { - DXCode::Shifted(code)=>{ - sleep(Duration::from_millis(10)); - special_down(0x10); - sleep(Duration::from_millis(10)); - key_enter(code, 8); - sleep(Duration::from_millis(10)); - special_up(0x10); - sleep(Duration::from_millis(10)); - }, - DXCode::Symbol(code) => key_enter(code, 8), - } - } -} \ No newline at end of file +use std::{mem, thread::sleep, time::Duration}; +use winapi::um::winuser::{ + SendInput, INPUT, INPUT_KEYBOARD, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, +}; + +use crate::chars::{char_to_dxcodes, DXCode}; +// key codes: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes + +unsafe fn create_input(key_code: u16, wvk: u16, flags: u32) -> INPUT { + let mut input = mem::zeroed::(); + input.type_ = INPUT_KEYBOARD; + let mut ki = input.u.ki_mut(); + ki.wVk = wvk; + ki.wScan = key_code; + ki.dwExtraInfo = 0; + ki.dwFlags = flags; + ki.time = 0; + input +} + +unsafe fn key_down(key_code: u16) { + let mut input = create_input(key_code, 0, KEYEVENTF_SCANCODE); + SendInput(1, &mut input, mem::size_of::() as i32); +} + +unsafe fn key_up(key_code: u16) { + let mut input = create_input(key_code, 0, KEYEVENTF_KEYUP); + SendInput(1, &mut input, mem::size_of::() as i32); +} + +unsafe fn special_down(key_code: u16) { + let mut input = create_input(0, key_code, KEYEVENTF_EXTENDEDKEY); + SendInput(1, &mut input, mem::size_of::() as i32); +} + +unsafe fn special_up(key_code: u16) { + let mut input = create_input(0, key_code, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP); + SendInput(1, &mut input, mem::size_of::() as i32); +} + +pub unsafe fn spam_keys(key_code: u16, timeout: u64, amount: i16) { + for _ in 0..amount { + key_enter(key_code, timeout); + sleep(Duration::from_millis(timeout)); + } +} + +pub unsafe fn key_enter(key_code: u16, timeout: u64) { + key_down(key_code); + sleep(Duration::from_millis(timeout)); + key_up(key_code); +} + +pub unsafe fn send_key(key: &String, timeout: u64) { + let char = key.chars().next().unwrap(); + if let Some(dx) = char_to_dxcodes(char) { + match dx { + DXCode::Shifted(code) => key_enter(code, timeout), + DXCode::Symbol(code) => key_enter(code, timeout), + } + } +} + +pub unsafe fn send_string(keys: Vec) { + for key in keys { + match key { + DXCode::Shifted(code) => { + sleep(Duration::from_millis(10)); + special_down(0x10); + sleep(Duration::from_millis(10)); + key_enter(code, 8); + sleep(Duration::from_millis(10)); + special_up(0x10); + sleep(Duration::from_millis(10)); + } + DXCode::Symbol(code) => key_enter(code, 8), + } + } +} diff --git a/src/shared_main.rs b/src/shared_main.rs index 70d1992..17d706d 100644 --- a/src/shared_main.rs +++ b/src/shared_main.rs @@ -37,13 +37,16 @@ pub fn anti_afk_runner(game_name: &str) { println!("error in config.txt: {}", e); println!("changing back to default.."); structs::SeederConfig { - minimize_after_message: true, send_messages: false, + minimize_after_action: true, messages: vec!["Join our discord, we are always recruiting: discord.gg/BoB".into()], chat_type: ChatType::Public, message_start_time_utc: "12:00".into(), message_stop_time_utc: "23:00".into(), message_timeout_mins: 8, + keypress_mode: false, + key: "tab".into(), + key_hold_time: 80, } } }; @@ -58,7 +61,7 @@ pub fn anti_afk_runner(game_name: &str) { actions::send_message(&cfg, game_name, ¤t_message_id); message_timeout.store(0, atomic::Ordering::Relaxed); } else { - run_once_no_game = actions::anti_afk(game_name, run_once_no_game); + run_once_no_game = actions::anti_afk(&cfg, game_name, run_once_no_game); if cfg.send_messages { message_timeout.store(timeout + 1, atomic::Ordering::Relaxed); } diff --git a/src/structs.rs b/src/structs.rs index dcc8fd9..1468a1c 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -11,13 +11,16 @@ pub enum ChatType { #[derive(Serialize, Deserialize, Clone)] pub struct SeederConfig { - pub minimize_after_message: bool, pub send_messages: bool, + pub minimize_after_action: bool, pub messages: Vec, pub chat_type: ChatType, pub message_start_time_utc: String, pub message_stop_time_utc: String, pub message_timeout_mins: u32, + pub keypress_mode: bool, + pub key: String, + pub key_hold_time: u64, } pub struct GameInfo { @@ -29,13 +32,16 @@ pub struct GameInfo { impl ::std::default::Default for SeederConfig { fn default() -> Self { Self { - minimize_after_message: true, send_messages: false, + minimize_after_action: true, messages: vec!["Join our discord, we are always recruiting: discord.gg/BoB".into()], chat_type: ChatType::Public, message_start_time_utc: "12:00".into(), message_stop_time_utc: "23:00".into(), message_timeout_mins: 8, + keypress_mode: false, + key: "tab".into(), + key_hold_time: 80, } } } diff --git a/src/test_msg.rs b/src/test_msg.rs index a2cc31a..4725d0f 100644 --- a/src/test_msg.rs +++ b/src/test_msg.rs @@ -13,13 +13,16 @@ fn main() { println!("error in config.txt: {}", e); println!("changing back to default.."); structs::SeederConfig { - minimize_after_message: true, + minimize_after_action: true, send_messages: true, messages: vec!["testmessage1".into()], chat_type: ChatType::Public, message_start_time_utc: "12:00".into(), message_stop_time_utc: "23:00".into(), message_timeout_mins: 8, + keypress_mode: false, + key: "tab".into(), + key_hold_time: 80, } } };