improvements

This commit is contained in:
2025-04-10 08:26:24 +01:00
parent 7f795ba52e
commit c3a1e864a7
4 changed files with 72 additions and 70 deletions
+11 -12
View File
@@ -7,6 +7,7 @@ use windows::Win32::UI::Input::KeyboardAndMouse::{
pub const INTERVAL: Duration = Duration::from_secs(60); pub const INTERVAL: Duration = Duration::from_secs(60);
const VK_NUMPAD4: u8 = 0x64; const VK_NUMPAD4: u8 = 0x64;
const VK_NUMPAD6: u8 = 0x66; const VK_NUMPAD6: u8 = 0x66;
const PRESS_KEYS: [u8; 2] = [VK_NUMPAD4, VK_NUMPAD6];
#[derive(Debug)] #[derive(Debug)]
pub struct AntiAfk { pub struct AntiAfk {
@@ -25,30 +26,28 @@ impl Default for AntiAfk {
impl AntiAfk { impl AntiAfk {
pub fn activate(&mut self) { pub fn activate(&mut self) {
if util::is_window_focused(GTA_WINDOW_TITLE) if util::win::is_window_focused(GTA_WINDOW_TITLE)
&& !util::is_key_pressed(VK_NUMPAD4 as i32) && !util::win::is_any_key_pressed(&PRESS_KEYS)
&& !util::is_key_pressed(VK_NUMPAD6 as i32)
{ {
send(VK_NUMPAD4); send(&PRESS_KEYS);
send(VK_NUMPAD6);
} }
self.interval = Instant::now(); self.interval = Instant::now();
} }
} }
pub fn send(vk_code: u8) { pub fn send(vk_codes: &[u8]) {
unsafe { vk_codes.iter().for_each(|vk_code: &u8| unsafe {
keybd_event( keybd_event(
vk_code, *vk_code,
u8::try_from(MapVirtualKeyW(u32::from(vk_code), MAP_VIRTUAL_KEY_TYPE(0))).unwrap(), u8::try_from(MapVirtualKeyW(u32::from(*vk_code), MAP_VIRTUAL_KEY_TYPE(0))).unwrap(),
KEYBD_EVENT_FLAGS(0), KEYBD_EVENT_FLAGS(0),
0, 0,
); );
keybd_event( keybd_event(
vk_code, *vk_code,
u8::try_from(MapVirtualKeyW(u32::from(vk_code), MAP_VIRTUAL_KEY_TYPE(0))).unwrap(), u8::try_from(MapVirtualKeyW(u32::from(*vk_code), MAP_VIRTUAL_KEY_TYPE(0))).unwrap(),
KEYBD_EVENT_FLAGS(2), KEYBD_EVENT_FLAGS(2),
0, 0,
); );
} });
} }
+33 -34
View File
@@ -9,7 +9,6 @@ use crate::{
util::{ util::{
self, self,
consts::{ENHANCED, GTA_WINDOW_TITLE, LEGACY}, consts::{ENHANCED, GTA_WINDOW_TITLE, LEGACY},
elevation,
}, },
}; };
use eframe::egui; use eframe::egui;
@@ -21,8 +20,6 @@ use std::{
sync::LazyLock, sync::LazyLock,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use sysinfo::System;
use windows::Win32::Foundation::HANDLE;
const THEME: catppuccin_egui::Theme = catppuccin_egui::MOCHA; const THEME: catppuccin_egui::Theme = catppuccin_egui::MOCHA;
const WINDOW_SIZE: [f32; 2] = [240.0, 240.0]; const WINDOW_SIZE: [f32; 2] = [240.0, 240.0];
@@ -46,16 +43,21 @@ pub enum Stage {
} }
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Default)]
pub struct Flags {
initialized: bool,
elevated: bool,
debug: bool,
closing: bool,
current_frame: bool,
}
#[derive(Debug)] #[derive(Debug)]
pub struct App { pub struct App {
stage: Stage, stage: Stage,
closing: bool, flags: Flags,
debug: bool, pub sysinfo: sysinfo::System,
initialized: bool, pub game_handle: windows::Win32::Foundation::HANDLE,
elevated: bool,
current_frame: bool,
pub sysinfo: System,
pub game_handle: HANDLE,
launch: Launch, launch: Launch,
force_close: ForceClose, force_close: ForceClose,
empty_session: EmptySession, empty_session: EmptySession,
@@ -66,13 +68,9 @@ impl Default for App {
fn default() -> Self { fn default() -> Self {
Self { Self {
stage: Stage::default(), stage: Stage::default(),
closing: false, flags: Flags::default(),
initialized: false, sysinfo: sysinfo::System::new_all(),
debug: false, game_handle: windows::Win32::Foundation::HANDLE::default(),
elevated: elevation::is_elevated(),
current_frame: false,
sysinfo: System::new_all(),
game_handle: HANDLE::default(),
launch: Launch::default(), launch: Launch::default(),
force_close: ForceClose::default(), force_close: ForceClose::default(),
empty_session: EmptySession::default(), empty_session: EmptySession::default(),
@@ -83,7 +81,7 @@ impl Default for App {
impl eframe::App for App { impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if !self.initialized { if !self.flags.initialized {
catppuccin_egui::set_theme(ctx, THEME); catppuccin_egui::set_theme(ctx, THEME);
egui_extras::install_image_loaders(ctx); egui_extras::install_image_loaders(ctx);
if let Ok(config) = fs::read_to_string(CONFIG_PATH.as_path()) { if let Ok(config) = fs::read_to_string(CONFIG_PATH.as_path()) {
@@ -95,7 +93,8 @@ impl eframe::App for App {
style.spacing.item_spacing = egui::vec2(4.0, 4.0); style.spacing.item_spacing = egui::vec2(4.0, 4.0);
style.interaction.selectable_labels = false; style.interaction.selectable_labels = false;
}); });
self.initialized = true; self.flags.elevated = util::win::is_elevated();
self.flags.initialized = true;
} }
self.run_timers(); self.run_timers();
egui::TopBottomPanel::bottom("bottom_panel") egui::TopBottomPanel::bottom("bottom_panel")
@@ -106,11 +105,11 @@ impl eframe::App for App {
ui.selectable_value(&mut self.stage, Stage::About, "About"); ui.selectable_value(&mut self.stage, Stage::About, "About");
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
let button = ui let button = ui
.add_enabled(!self.elevated, egui::Button::new("Elevate")) .add_enabled(!self.flags.elevated, egui::Button::new("Elevate"))
.on_hover_text("Relaunch ourselves as administrator.") .on_hover_text("Relaunch ourselves as administrator.")
.on_disabled_hover_text("We are already running elevated."); .on_disabled_hover_text("We are already running elevated.");
if button.clicked() { if button.clicked() {
elevation::elevate(&mut self.closing); util::win::elevate(&mut self.flags.closing);
} }
}); });
}); });
@@ -127,12 +126,12 @@ impl eframe::App for App {
Stage::About => self.show_about(ctx, ui), Stage::About => self.show_about(ctx, ui),
}); });
if check_debug_keycombo_pressed(ctx) { if check_debug_keycombo_pressed(ctx) {
self.debug = !self.debug; self.flags.debug = !self.flags.debug;
} }
if check_debug_viewport_close_button_pressed(ctx) { if check_debug_viewport_close_button_pressed(ctx) {
self.debug = false; self.flags.debug = false;
} }
if self.debug { if self.flags.debug {
let main_rect = ctx.input(|i| { let main_rect = ctx.input(|i| {
i.viewport() i.viewport()
.clone() .clone()
@@ -151,7 +150,7 @@ impl eframe::App for App {
.with_icon(load_icon()), .with_icon(load_icon()),
|ctx, _class| { |ctx, _class| {
if check_debug_keycombo_pressed(ctx) { if check_debug_keycombo_pressed(ctx) {
self.debug = !self.debug; self.flags.debug = !self.flags.debug;
} }
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::both() egui::ScrollArea::both()
@@ -164,7 +163,7 @@ impl eframe::App for App {
); );
} }
ctx.request_repaint_after(Duration::from_millis(100)); ctx.request_repaint_after(Duration::from_millis(100));
if self.closing { if self.flags.closing {
ctx.send_viewport_cmd(egui::ViewportCommand::Close); ctx.send_viewport_cmd(egui::ViewportCommand::Close);
} }
} }
@@ -211,20 +210,20 @@ impl App {
); );
if force_close_button.clicked() && !self.force_close.prompting { if force_close_button.clicked() && !self.force_close.prompting {
self.force_close.prompting(); self.force_close.prompting();
self.current_frame = true; self.flags.current_frame = true;
}; };
if self.force_close.prompting if self.force_close.prompting
&& self.force_close.interval.elapsed() <= Duration::from_secs(3) && self.force_close.interval.elapsed() <= Duration::from_secs(3)
{ {
if force_close_button.clicked() && !self.current_frame { if force_close_button.clicked() && !self.flags.current_frame {
features::force_close::activate(&mut self.sysinfo); features::force_close::activate(&mut self.sysinfo);
self.force_close = ForceClose::default(); self.force_close = ForceClose::default();
} }
} else { } else {
self.force_close = ForceClose::default(); self.force_close = ForceClose::default();
} }
if self.current_frame { if self.flags.current_frame {
self.current_frame = false; self.flags.current_frame = false;
} }
} }
@@ -245,7 +244,7 @@ impl App {
if self.anti_afk.enabled { if self.anti_afk.enabled {
ui.add_space(8.0); ui.add_space(8.0);
ui.add_enabled_ui(false, |ui| { ui.add_enabled_ui(false, |ui| {
ui.label(if util::is_window_focused(GTA_WINDOW_TITLE) { ui.label(if util::win::is_window_focused(GTA_WINDOW_TITLE) {
"GTA is focused." "GTA is focused."
} else { } else {
"GTA is not focused!" "GTA is not focused!"
@@ -264,7 +263,7 @@ impl App {
.inner_margin(egui::vec2(4.0, 4.0)) .inner_margin(egui::vec2(4.0, 4.0))
.stroke(egui::Stroke::new(1.0, THEME.overlay1)) .stroke(egui::Stroke::new(1.0, THEME.overlay1))
.show(ui, |ui| { .show(ui, |ui| {
let response = ui.add_enabled_ui(self.elevated, |ui| { let response = ui.add_enabled_ui(self.flags.elevated, |ui| {
let label = ui.label("Game's network access"); let label = ui.label("Game's network access");
ui.horizontal(|ui| { ui.horizontal(|ui| {
let available_width = label.rect.width(); let available_width = label.rect.width();
@@ -382,11 +381,11 @@ fn check_debug_viewport_close_button_pressed(ctx: &egui::Context) -> bool {
}) })
} }
fn load_icon() -> eframe::egui::IconData { fn load_icon() -> egui::IconData {
let icon = include_bytes!("../assets/icon.png"); let icon = include_bytes!("../assets/icon.png");
let image = image::load_from_memory(icon).unwrap().into_rgba8(); let image = image::load_from_memory(icon).unwrap().into_rgba8();
let (width, height) = image.dimensions(); let (width, height) = image.dimensions();
eframe::egui::IconData { egui::IconData {
rgba: image.into_raw(), rgba: image.into_raw(),
width, width,
height, height,
+1 -20
View File
@@ -1,22 +1,3 @@
pub mod consts; pub mod consts;
pub mod countdown; pub mod countdown;
pub mod elevation; pub mod win;
use windows::Win32::UI::{
Input::KeyboardAndMouse::GetAsyncKeyState,
WindowsAndMessaging::{GetForegroundWindow, GetWindowTextW},
};
pub fn is_window_focused(target_title: &str) -> bool {
unsafe {
let hwnd = GetForegroundWindow();
let mut buffer: [u16; 512] = [0; 512];
let length = GetWindowTextW(hwnd, &mut buffer);
let current_title = String::from_utf16_lossy(&buffer[..length as usize]);
current_title == target_title
}
}
pub fn is_key_pressed(key: i32) -> bool {
unsafe { (GetAsyncKeyState(key) as i32 & 0x8000) != 0 }
}
+27 -4
View File
@@ -1,11 +1,34 @@
use windows::{ use windows::{
Win32::Foundation::{CloseHandle, HANDLE}, Win32::{
Win32::Security::{GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation}, Foundation::{CloseHandle, HANDLE},
Win32::System::Threading::{GetCurrentProcess, OpenProcessToken}, Security::{GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation},
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_HIDE}, System::Threading::{GetCurrentProcess, OpenProcessToken},
UI::{
Input::KeyboardAndMouse::GetAsyncKeyState,
Shell::ShellExecuteW,
WindowsAndMessaging::SW_HIDE,
WindowsAndMessaging::{GetForegroundWindow, GetWindowTextW},
},
},
core::{HSTRING, PCWSTR}, core::{HSTRING, PCWSTR},
}; };
#[allow(clippy::cast_sign_loss)]
pub fn is_window_focused(target_title: &str) -> bool {
unsafe {
let hwnd = GetForegroundWindow();
let mut buffer: [u16; 512] = [0; 512];
let length = GetWindowTextW(hwnd, &mut buffer);
let current_title = String::from_utf16_lossy(&buffer[..length as usize]);
current_title == target_title
}
}
pub fn is_any_key_pressed(keys: &[u8]) -> bool {
keys.iter()
.any(|&key| unsafe { (i32::from(GetAsyncKeyState(i32::from(key))) & 0x8000) != 0 })
}
pub fn elevate(closing: &mut bool) { pub fn elevate(closing: &mut bool) {
let exe = std::env::current_exe().unwrap(); let exe = std::env::current_exe().unwrap();
unsafe { unsafe {