HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   Форум АНТИЧАТ > ПРОГРАММИРОВАНИЕ > Общие вопросы программирования
   
 
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 30.01.2026, 03:06
Haru Urara
Познающий
Регистрация: 28.07.2024
Сообщений: 54
Провел на форуме:
10322

Репутация: 13
По умолчанию

Я учусь создавать меню для SA-MP. Как исправить курсор мыши? Он не двигается с середины экрана, когда я открываю меню. Я использую SDK SAMP от DK22Pac.

1769726783046.pngHaru Urara · 30 Янв 2026 в 02:06' data-fancybox="lb-post-1657226" data-lb-caption-extra-html="" data-lb-sidebar-href="" data-single-image="1" data-src="https://www.blast.hk/attachments/285736/" style="cursor: pointer;" title="1769726783046.png">


My Code:

C++:





Код:
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#include 
#pragma comment(lib, "d3d9.lib")
#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h"
#include "MinHook.h"
#ifdef _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#else
#pragma comment(lib, "libMinHook.x86.lib")
#endif
#define LOG_FILE "bode_menu.txt"
#define FRAME_TIME_BUDGET 16.0f
// ~60 FPS, em ms
// Estrutura para salvar estado do cursor
struct
CursorState
{
bool
bVisible
;
bool
clipExists
;
RECT clipRect
;
HCURSOR hCursor
;
}
;
static
bool
menu
=
false
;
static
bool
inicializado
=
false
;
static
bool
render_paused
=
false
;
static
int
click_count
=
0
;
static
HWND gameWindow
=
nullptr
;
// Estado do cursor
static
CursorState saved_cursor_state
=
{
}
;
static
bool
cursor_state_saved
=
false
;
// Ponteiros originais (D3D9)
typedef
HRESULT
(
__stdcall
*
tEndScene
)
(
IDirect3DDevice9
*
)
;
typedef
HRESULT
(
__stdcall
*
tReset
)
(
IDirect3DDevice9
*
,
D3DPRESENT_PARAMETERS
*
)
;
tEndScene oEndScene
=
nullptr
;
tReset oReset
=
nullptr
;
WNDPROC oWndProc
=
nullptr
;
extern
IMGUI_IMPL_API LRESULT
ImGui_ImplWin32_WndProcHandler
(
HWND
,
UINT
,
WPARAM
,
LPARAM
)
;
void
Log
(
const
char
*
fmt
,
.
.
.
)
{
FILE
*
f
=
fopen
(
LOG_FILE
,
"a"
)
;
if
(
f
)
{
// Timestamp
time_t now
=
time
(
nullptr
)
;
struct
tm
*
timeinfo
=
localtime
(
&
now
)
;
fprintf
(
f
,
"[%02d:%02d:%02d] "
,
timeinfo
->
tm_hour
,
timeinfo
->
tm_min
,
timeinfo
->
tm_sec
)
;
va_list args
;
va_start
(
args
,
fmt
)
;
vfprintf
(
f
,
fmt
,
args
)
;
fprintf
(
f
,
"\n"
)
;
va_end
(
args
)
;
fclose
(
f
)
;
}
}
void
SaveCursorState
(
)
{
if
(
cursor_state_saved
)
return
;
Log
(
"[CURSOR] Salvando estado do cursor..."
)
;
// Usa CURSORINFO para obter visibilidade e hCursor
CURSORINFO ci
;
ci
.
cbSize
=
sizeof
(
ci
)
;
if
(
GetCursorInfo
(
&
ci
)
)
{
saved_cursor_state
.
bVisible
=
(
ci
.
flags
&
CURSOR_SHOWING
)
!=
0
;
saved_cursor_state
.
hCursor
=
ci
.
hCursor
;
}
else
{
// fallback
saved_cursor_state
.
bVisible
=
true
;
saved_cursor_state
.
hCursor
=
LoadCursor
(
NULL
,
IDC_ARROW
)
;
}
// Salva clip region, marcando se existe
RECT rc
;
if
(
GetClipCursor
(
&
rc
)
)
{
saved_cursor_state
.
clipExists
=
true
;
saved_cursor_state
.
clipRect
=
rc
;
}
else
{
saved_cursor_state
.
clipExists
=
false
;
}
cursor_state_saved
=
true
;
Log
(
"[CURSOR] Estado salvo: Visible=%d, ClipExists=%d, Cursor=0x%p"
,
saved_cursor_state
.
bVisible
,
saved_cursor_state
.
clipExists
,
saved_cursor_state
.
hCursor
)
;
}
void
RestoreCursorState
(
)
{
if
(
!
cursor_state_saved
)
return
;
Log
(
"[CURSOR] Restaurando estado do cursor..."
)
;
// Restaura clip region somente se existia; caso contrário remove confinamento
if
(
saved_cursor_state
.
clipExists
)
{
ClipCursor
(
&
saved_cursor_state
.
clipRect
)
;
}
else
{
ClipCursor
(
NULL
)
;
}
// Restaura cursor gráfico
SetCursor
(
saved_cursor_state
.
hCursor
)
;
// Restaura visibilidade usando ShowCursor; ajusta contador interno
if
(
saved_cursor_state
.
bVisible
)
{
while
(
ShowCursor
(
TRUE
)
=
0
)
{
}
}
cursor_state_saved
=
false
;
Log
(
"[CURSOR] Estado restaurado: Visible=%d"
,
saved_cursor_state
.
bVisible
)
;
}
void
ShowCursorForMenu
(
)
{
Log
(
"[CURSOR] Mostrando cursor para menu..."
)
;
// Remove confinamento
ClipCursor
(
NULL
)
;
// Força cursor sistema com seta
SetCursor
(
LoadCursor
(
NULL
,
IDC_ARROW
)
)
;
// Garante visibilidade
while
(
ShowCursor
(
TRUE
)
=
WM_MOUSEFIRST
&&
uMsg
=
WM_KEYFIRST
&&
uMsg

0
)
{
--
skip_render_frames
;
return
oEndScene
(
pDevice
)
;
}
if
(
!
inicializado
)
{
Log
(
"[INIT] Inicializando menu ImGui..."
)
;
gameWindow
=
FindWindowA
(
NULL
,
"GTA:SA:MP"
)
;
if
(
!
gameWindow
)
gameWindow
=
FindWindowA
(
"Grand Theft Auto San Andreas"
,
NULL
)
;
if
(
!
gameWindow
)
{
D3DDEVICE_CREATION_PARAMETERS cp
;
if
(
SUCCEEDED
(
pDevice
->
GetCreationParameters
(
&
cp
)
)
)
{
gameWindow
=
cp
.
hFocusWindow
;
}
}
if
(
!
gameWindow
)
{
Log
(
"[INIT] ERRO: Não conseguiu encontrar HWND do jogo!"
)
;
return
oEndScene
(
pDevice
)
;
}
Log
(
"[INIT] HWND detectado: 0x%p"
,
gameWindow
)
;
// Inicializa ImGui
ImGui
::
CreateContext
(
)
;
ImGui
::
StyleColorsDark
(
)
;
ImGuiIO
&
io
=
ImGui
::
GetIO
(
)
;
io
.
ConfigFlags
|=
ImGuiConfigFlags_NavEnableKeyboard
;
io
.
IniFilename
=
NULL
;
io
.
MouseDrawCursor
=
false
;
// Não desenha cursor (usa do sistema)
ImGui_ImplWin32_Init
(
gameWindow
)
;
ImGui_ImplDX9_Init
(
pDevice
)
;
// Hook do WndProc para capturar input
oWndProc
=
(
WNDPROC
)
SetWindowLongPtr
(
gameWindow
,
GWLP_WNDPROC
,
(
LONG_PTR
)
WndProcHook
)
;
inicializado
=
true
;
menu
=
false
;
Log
(
"[INIT] === ImGui PRONTO! ==="
)
;
}
// Atualização de tempo local para medir frame
clock_t frame_start_time_local
=
clock
(
)
;
ImGuiIO
&
io
=
ImGui
::
GetIO
(
)
;
if
(
menu
)
{
POINT cursorPos
;
if
(
GetCursorPos
(
&
cursorPos
)
)
{
ScreenToClient
(
gameWindow
,
&
cursorPos
)
;
// Atualiza posição
io
.
MousePos
=
ImVec2
(
(
float
)
cursorPos
.
x
,
(
float
)
cursorPos
.
y
)
;
}
else
{
io
.
MousePos
=
ImVec2
(
-
FLT_MAX
,
-
FLT_MAX
)
;
}
// Atualiza botões do mouse
io
.
MouseDown
[
0
]
=
(
GetAsyncKeyState
(
VK_LBUTTON
)
&
0x8000
)
!=
0
;
io
.
MouseDown
[
1
]
=
(
GetAsyncKeyState
(
VK_RBUTTON
)
&
0x8000
)
!=
0
;
io
.
MouseDown
[
2
]
=
(
GetAsyncKeyState
(
VK_MBUTTON
)
&
0x8000
)
!=
0
;
}
// ========================================
// TOGGLE DO MENU (F2)
// ========================================
static
bool
f2_pressed
=
false
;
if
(
GetAsyncKeyState
(
VK_F2
)
&
0x8000
)
{
if
(
!
f2_pressed
)
{
f2_pressed
=
true
;
if
(
!
menu
)
{
// Abrindo menu
menu
=
true
;
SaveCursorState
(
)
;
ShowCursorForMenu
(
)
;
// garante que ImGui esteja pronto a receber input
ImGui
::
GetIO
(
)
.
WantCaptureMouse
=
true
;
ImGui
::
GetIO
(
)
.
WantCaptureKeyboard
=
true
;
render_paused
=
false
;
Log
(
"[MENU] === MENU ABERTO ==="
)
;
}
else
{
// Fechando menu
menu
=
false
;
// Restaurar o estado do cursor SALVO (não "ocultar" arbitrariamente)
RestoreCursorState
(
)
;
// Invalida objetos do ImGui para evitar possíveis draw-residue/artefatos
ImGui_ImplDX9_InvalidateDeviceObjects
(
)
;
// Limpa flags de captura
ImGui
::
GetIO
(
)
.
WantCaptureMouse
=
false
;
ImGui
::
GetIO
(
)
.
WantCaptureKeyboard
=
false
;
// pula alguns frames sem render de menu para garantir limpeza visual
skip_render_frames
=
2
;
Log
(
"[MENU] === MENU FECHADO ==="
)
;
}
}
}
else
{
f2_pressed
=
false
;
}
// ========================================
// SE MENU ESTÁ FECHADO, RETORNA RÁPIDO
// ========================================
if
(
!
menu
)
{
return
oEndScene
(
pDevice
)
;
}
// ========================================
// RENDERIZA MENU (ImGui)
// ========================================
// Inicia frame do ImGui
ImGui_ImplDX9_NewFrame
(
)
;
ImGui_ImplWin32_NewFrame
(
)
;
ImGui
::
NewFrame
(
)
;
// === JANELA DO MENU ===
ImGui
::
SetNextWindowPos
(
ImVec2
(
100
,
100
)
,
ImGuiCond_FirstUseEver
)
;
ImGui
::
SetNextWindowSize
(
ImVec2
(
600
,
500
)
,
ImGuiCond_FirstUseEver
)
;
if
(
ImGui
::
Begin
(
"Bode Menu - SA-MP"
,
&
menu
,
ImGuiWindowFlags_NoCollapse
)
)
{
ImGui
::
TextColored
(
ImVec4
(
0
,
1
,
0
,
1
)
,
"Menu Stealth - SA-MP"
)
;
ImGui
::
Separator
(
)
;
// Mostra informações
ImGui
::
Text
(
"FPS: %.1f"
,
io
.
Framerate
)
;
ImGui
::
Text
(
"Posicao do Mouse: X=%.0f Y=%.0f"
,
io
.
MousePos
.
x
,
io
.
MousePos
.
y
)
;
ImGui
::
Text
(
"Cliques registrados: %d"
,
click_count
)
;
ImGui
::
Spacing
(
)
;
ImGui
::
Separator
(
)
;
// Botão de teste
if
(
ImGui
::
Button
(
"TESTE CLIQUE"
,
ImVec2
(
200
,
50
)
)
)
{
click_count
++
;
Beep
(
1000
,
100
)
;
Log
(
"[MENU] Botao clicado! Total: %d"
,
click_count
)
;
}
ImGui
::
Spacing
(
)
;
// Exemplos de widgets
static
bool
checkbox_test
=
false
;
ImGui
::
Checkbox
(
"Opcao de Teste"
,
&
checkbox_test
)
;
static
float
slider_test
=
0.5f
;
ImGui
::
SliderFloat
(
"Slider Teste"
,
&
slider_test
,
0.0f
,
1.0f
)
;
ImGui
::
Spacing
(
)
;
ImGui
::
TextColored
(
ImVec4
(
1
,
1
,
0
,
1
)
,
"Pressione F2 para fechar"
)
;
ImGui
::
End
(
)
;
}
// Render ImGui
ImGui
::
EndFrame
(
)
;
ImGui
::
Render
(
)
;
ImGui_ImplDX9_RenderDrawData
(
ImGui
::
GetDrawData
(
)
)
;
// ========================================
// CONTROLE DE FRAME TIME (OTIMIZAÇÃO) - medição local
// ========================================
clock_t frame_end_time_local
=
clock
(
)
;
double
frame_ms
=
(
double
)
(
frame_end_time_local
-
frame_start_time_local
)
*
1000.0
/
CLOCKS_PER_SEC
;
if
(
frame_ms
>
FRAME_TIME_BUDGET
*
1.5
)
{
static
int
slow_frame_count
=
0
;
if
(
++
slow_frame_count
%
30
==
0
)
{
Log
(
"[PERF] Frame lento: %.2f ms (budget: %.2f ms)"
,
frame_ms
,
FRAME_TIME_BUDGET
)
;
}
}
// Debug: detectar se outro módulo mudou o cursor (opcional)
if
(
cursor_state_saved
)
{
HCURSOR hCurNow
=
GetCursor
(
)
;
if
(
hCurNow
!=
saved_cursor_state
.
hCursor
)
{
Log
(
"[CURSOR] Detectado cursor atual diferente do salvo: now=0x%p saved=0x%p"
,
hCurNow
,
saved_cursor_state
.
hCursor
)
;
}
}
return
oEndScene
(
pDevice
)
;
}
// ============================================================================
// THREAD DE INICIALIZAÇÃO DO PLUGIN
// ============================================================================
DWORD WINAPI
ThreadInicio
(
LPVOID
)
{
Log
(
"=== BODE PLUGIN - INICIANDO ==="
)
;
// Aguarda carregamento do SAMP e D3D9
int
wait_count
=
0
;
while
(
!
GetModuleHandleA
(
"samp.dll"
)
&&
wait_count
++

CreateDevice
(
D3DADAPTER_DEFAULT
,
D3DDEVTYPE_NULLREF
,
hWnd
,
D3DCREATE_SOFTWARE_VERTEXPROCESSING
|
D3DCREATE_DISABLE_DRIVER_MANAGEMENT
,
&
d3dpp
,
&
pDevice
)
;
if
(
FAILED
(
hr
)
)
{
hr
=
pD3D
->
CreateDevice
(
D3DADAPTER_DEFAULT
,
D3DDEVTYPE_HAL
,
hWnd
,
D3DCREATE_SOFTWARE_VERTEXPROCESSING
,
&
d3dpp
,
&
pDevice
)
;
}
if
(
FAILED
(
hr
)
)
{
Log
(
"ERRO ao criar D3D9 device: 0x%08X"
,
hr
)
;
pD3D
->
Release
(
)
;
MH_Uninitialize
(
)
;
return
0
;
}
// Obtém v-table
void
*
*
vTable
=
*
(
void
*
*
*
)
pDevice
;
void
*
pEndScene
=
vTable
[
42
]
;
// EndScene index
void
*
pReset
=
vTable
[
16
]
;
// Reset index
// Cria hooks
if
(
MH_CreateHook
(
pEndScene
,
&
HookedEndScene
,
(
void
*
*
)
&
oEndScene
)
!=
MH_OK
)
{
Log
(
"ERRO: Falha ao criar hook EndScene!"
)
;
pDevice
->
Release
(
)
;
pD3D
->
Release
(
)
;
MH_Uninitialize
(
)
;
return
0
;
}
if
(
MH_CreateHook
(
pReset
,
&
HookedReset
,
(
void
*
*
)
&
oReset
)
!=
MH_OK
)
{
Log
(
"ERRO: Falha ao criar hook Reset!"
)
;
pDevice
->
Release
(
)
;
pD3D
->
Release
(
)
;
MH_Uninitialize
(
)
;
return
0
;
}
// Habilita hooks
if
(
MH_EnableHook
(
MH_ALL_HOOKS
)
!=
MH_OK
)
{
Log
(
"ERRO: Falha ao ativar hooks!"
)
;
pDevice
->
Release
(
)
;
pD3D
->
Release
(
)
;
MH_Uninitialize
(
)
;
return
0
;
}
Log
(
"Hooks instalados com sucesso!"
)
;
Log
(
"EndScene: 0x%p -> 0x%p"
,
pEndScene
,
&
HookedEndScene
)
;
Log
(
"Reset: 0x%p -> 0x%p"
,
pReset
,
&
HookedReset
)
;
// Libera recursos temporários
pDevice
->
Release
(
)
;
pD3D
->
Release
(
)
;
Log
(
"=== PLUGIN PRONTO! Pressione F2 para abrir o menu ==="
)
;
return
0
;
}
// ============================================================================
// DLL MAIN
// ============================================================================
BOOL APIENTRY
DllMain
(
HMODULE hMod
,
DWORD reason
,
LPVOID
)
{
if
(
reason
==
DLL_PROCESS_ATTACH
)
{
DisableThreadLibraryCalls
(
hMod
)
;
Log
(
"=== PLUGIN CARREGADO ==="
)
;
CreateThread
(
nullptr
,
0
,
ThreadInicio
,
nullptr
,
0
,
nullptr
)
;
}
else
if
(
reason
==
DLL_PROCESS_DETACH
)
{
Log
(
"=== PLUGIN DESCARREGANDO ==="
)
;
// Restaura WndProc se alterado
if
(
oWndProc
&&
gameWindow
)
{
SetWindowLongPtr
(
gameWindow
,
GWLP_WNDPROC
,
(
LONG_PTR
)
oWndProc
)
;
oWndProc
=
nullptr
;
}
// Cleanup ImGui se inicializado
if
(
inicializado
)
{
ImGui_ImplDX9_Shutdown
(
)
;
ImGui_ImplWin32_Shutdown
(
)
;
ImGui
::
DestroyContext
(
)
;
inicializado
=
false
;
}
MH_DisableHook
(
MH_ALL_HOOKS
)
;
MH_Uninitialize
(
)
;
Log
(
"=== PLUGIN DESCARREGADO ==="
)
;
}
return
TRUE
;
}
 
Ответить с цитированием
 





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.