Movendo o cursor do mouse com o teclado
Caloni, 2007-07-26 computer projects blogBom, vamos deixar de papo furado e "codar". Para essa primeira tentativa iremos desenvolver um programa que move o cursor do mouse quando pressionada uma tecla de atalho e voltar à sua posição original quando pressionada outra tecla.
Como eu já havia dito anteriormente, uso o mouse quando necessário. Quando ele não é necessário ele fica clicando inconscientemente no Windows Explorer, já que utilizo a configuração de clique único, onde as pastas e arquivos ficam selecionáveis apenas pousando o cursor sobre eles. Eu gosto dessa configuração, exceto pelo comportamento desagradável que ocorre quando mudo para a janela do Windows Explorer e meu mouse ganha vida própria, selecionando alguma pasta ou arquivo e mudando meu foco de seleção.
Portanto, o objetivo desse programa é simples e direto: mover o mouse para um canto enquanto eu uso meu teclado. Nada mais, nada menos. Para isso iremos registrar alguns atalhos globais no Windows. Para registrar atalhos globais no Windows utilizamos a função do Windows API RegisterHotKey e é o que estou usando no código. O importante aqui é saber que iremos ser avisados do pressionamento das teclas que registrarmos por meio dessa função através do loop de mensagens da thread que chamar a função.
Um loop de mensagens é a maneira definida pelo Windows para avisar as aplicações dos eventos que ocorrerem no sistema que são relevantes para as suas janelas. Teremos chance de observar isso mais vezes, mas por enquanto basta ter uma visão geral do fluxo de mensagens que ocorre quando digitarmos a nossa tecla de atalho.
O código não tem muitos segredos (update 2026-01-27: mas eu não sei onde ele foi parar; por isso pedi para o Chat-GPT fazer um novo, onde ele gentilmente implementou a leitura inclusive das hotkeys no arquivo ini). Para registrar os atalhos, usamos a função RegisterHotKey. Para manipular os eventos usamos o tal loop de mensagens e manipulamos a mensagem WM_HOTKEY de acordo com a tecla pressionada. Para mover o mouse usamos a função SetCursorPos (e para armazenar a posição atual GetCursorPos). Por fim, para ler configurações de um .ini usamos a função GetPrivateProfileInt.
#include <windows.h>
#include <string>
#include <map>
#include <iostream>
using namespace std;
// global state
//
POINT g_OldPos = { 0 };
bool g_Hidden = false;
int g_DisableX = 0;
int g_DisableY = 0;
// hotkeys IDs
#define HK_HIDE 1
#define HK_SHOW 2
#define HK_EXIT 3
// utilities
//
pair<UINT, UINT> ParseHotkey(const string& text)
{
UINT mod = 0;
UINT vk = 0;
string s = text;
for (auto& c : s) c = toupper(c);
if (s.find("WIN+") != string::npos) mod |= MOD_WIN;
if (s.find("CTRL+") != string::npos) mod |= MOD_CONTROL;
if (s.find("ALT+") != string::npos) mod |= MOD_ALT;
if (s.find("SHIFT+") != string::npos) mod |= MOD_SHIFT;
if (s.find("DEL") != string::npos) vk = VK_DELETE;
else if (s.find("INS") != string::npos) vk = VK_INSERT;
else if (s.find("END") != string::npos) vk = VK_END;
else if (s.find("HOME") != string::npos) vk = VK_HOME;
else if (s.find("F1") != string::npos) vk = VK_F1;
else if (s.find("F2") != string::npos) vk = VK_F2;
else
vk = s.back(); // fallback: última letra
return { mod, vk };
}
string ReadIniString(const char* section, const char* key, const char* def)
{
char buf[128];
GetPrivateProfileStringA(section, key, def, buf, sizeof(buf), "HideCursor.ini");
return buf;
}
// mouse logic
//
void HideMouse()
{
if (!g_Hidden)
{
GetCursorPos(&g_OldPos);
SetCursorPos(g_DisableX, g_DisableY);
g_Hidden = true;
cout << "[+] Mouse hidden\n";
}
}
void ShowMouse()
{
if (g_Hidden)
{
SetCursorPos(g_OldPos.x, g_OldPos.y);
g_Hidden = false;
cout << "[+] Mouse restored\n";
}
}
int main()
{
cout << "HideCursor - keyboard mouse control\n";
// ini reading
g_DisableX = GetPrivateProfileIntA("HideCursor", "DisableX", 600, "HideCursor.ini");
g_DisableY = GetPrivateProfileIntA("HideCursor", "DisableY", 0, "HideCursor.ini");
string hkHide = ReadIniString("Hotkeys", "Hide", "WIN+DEL");
string hkShow = ReadIniString("Hotkeys", "Show", "WIN+INS");
string hkExit = ReadIniString("Hotkeys", "Exit", "WIN+END");
auto [modHide, vkHide] = ParseHotkey(hkHide);
auto [modShow, vkShow] = ParseHotkey(hkShow);
auto [modExit, vkExit] = ParseHotkey(hkExit);
// register global hotkeys
RegisterHotKey(NULL, HK_HIDE, modHide, vkHide);
RegisterHotKey(NULL, HK_SHOW, modShow, vkShow);
RegisterHotKey(NULL, HK_EXIT, modExit, vkExit);
cout << "Hotkeys:\n";
cout << " Hide: " << hkHide << endl;
cout << " Show: " << hkShow << endl;
cout << " Exit: " << hkExit << endl;
// message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_HOTKEY)
{
switch (msg.wParam)
{
case HK_HIDE:
HideMouse();
break;
case HK_SHOW:
ShowMouse();
break;
case HK_EXIT:
cout << "Exiting...\n";
goto exit_loop;
}
}
}
exit_loop:
UnregisterHotKey(NULL, HK_HIDE);
UnregisterHotKey(NULL, HK_SHOW);
UnregisterHotKey(NULL, HK_EXIT);
return 0;
}
Abaixo um exemplo do arquivo ini:
[HideCursor] DisableX=600 DisableY=0 [Hotkeys] Hide=WIN+DEL Show=WIN+INS Exit=WIN+END
Você acha que os atalhos "WinKey + Del", "WinKey + Insert" e "WinKey + End" foram uma má escolha para essa função de esconder o mouse? Concordo. Fiz de propósito. Que tal customizar o programa para que as teclas sejam lidas do arquivo de configuração HideCursor.ini?