Problem:
I have a console chat. When I am typing a message and another person sends a message, their message gets printed right after the last character i typed, breaking it.
Example:
"HellAndrew: Hi!o!"
I try to type "Hello!", but "Andrew" interferes with a "Hi!"
How I'd like to handle this:
I was thinking that before printing a message from another client I copy the text I currently have in my standard input, print the other user's text then put the text back in the standard input, a row lower.
I tried using ReadConsoleInput/WriteConsoleInput APIs, but it does not do what I want and adds a significant (>10s) delay.
ReadConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), Inputs, 100, &Count);
//printing
WriteConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), Inputs, 100, &Count);
I cannot spot any other console APIs on MSDN that I can use. Perhaps I am using the others above wrong somehow.
I would appreciate some help in using these. Thanks!
After researching your question, I made the following test and can get the expected effect.
After reading another process string, use WriteConsoleOutputCharacter to write characters in different positions.
WriteConsoleOutputCharacterA(hStdOut, lpszString, strlen(lpszString), { 0,0 }, &dwWritten);
The coordinates of the cursor can be modified according to the actual situation, such as to achieve message scrolling.
Note: You can use SetConsoleCursorPosition to locate to another position to accept the input stream firstly.
Like this,
coord.X = 0;
coord.Y = 10;
SetConsoleCursorPosition(hStdOut, coord);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
Updated:
This is the sample I tested and I attach a quick gif demo.
Server.cpp
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <thread>
using namespace std;
DWORD dwWritten;
DWORD num;
DWORD dwRead;
char strMessage[256];
HWND h_client;
void td1();
COORD coord;
SHORT i = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (message == WM_DESTROY) {
PostQuitMessage(0);
}
if (message == WM_COPYDATA)
{
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1)
{
CHAR* lpszString = (CHAR*)(pcds->lpData);
WriteConsoleOutputCharacterA(hStdOut, lpszString, strlen(lpszString)-2, { 0,i++ }, &dwWritten);
}
if (i > 24)
{
system("cls");
i = 0;
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------\n");
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
};
HINSTANCE hinst;
int main() {
HWND hwnd;
hinst = GetModuleHandle(NULL);
// create a window class:
WNDCLASS wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = L"win32";
// register class with operating system:
RegisterClass(&wc);
// create and show window:
hwnd = CreateWindow(L"win32", L"Server", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
std::thread t1(td1);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, SW_SHOW);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void td1()
{
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
while (1)
{
h_client = FindWindow(L"win32", L"Client");
if (h_client)
{
break;
}
}
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------");
while (1)
{
coord.X = 0;
coord.Y = 26;
SetConsoleCursorPosition(hStdOut, coord);
memset(strMessage, 0, 256);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
SetConsoleCursorPosition(hStdOut, coord);
for (int i = strlen(strMessage); i > 0; i--)
{
putchar(32);
}
COPYDATASTRUCT cds;
cds.dwData = 1; // can be anything
cds.cbData = sizeof(CHAR) * strlen(strMessage);
cds.lpData = strMessage;
SendMessage(h_client, WM_COPYDATA, (WPARAM)h_client, (LPARAM)(LPVOID)&cds);
}
}
Client.cpp
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <thread>
using namespace std;
DWORD dwWritten;
DWORD dwRead;
char strMessage[256];
HWND h_server;
SHORT i = 0;
COORD coord;
void td1();
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (message == WM_DESTROY) {
PostQuitMessage(0);
}
if (message == WM_COPYDATA)
{
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1)
{
CHAR* lpszString = (CHAR*)(pcds->lpData);
int len = pcds->cbData;
WriteConsoleOutputCharacterA(hStdOut, lpszString, len - 2, { 0,i++ }, &dwWritten);
}
if (i > 24)
{
system("cls");
i = 0;
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------\n");
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
HINSTANCE hinst;
int main() {
HWND hwnd;
hinst = GetModuleHandle(NULL);
// create a window class:
WNDCLASS wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = L"win32";
// register class with operating system:
RegisterClass(&wc);
// create and show window:
hwnd = CreateWindow(L"win32", L"Client", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
std::thread t1(td1);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, SW_SHOW);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void td1()
{
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
while (1)
{
h_server = FindWindow(L"win32", L"Server");
if (h_server)
{
break;
}
}
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------");
while (1)
{
coord.X = 0;
coord.Y = 26;
SetConsoleCursorPosition(hStdOut, coord);
memset(strMessage, 0, 256);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
SetConsoleCursorPosition(hStdOut, coord);
for (int i = strlen(strMessage); i > 0; i--)
{
putchar(32);
}
COPYDATASTRUCT cds;
cds.dwData = 1; // can be anything
cds.cbData = sizeof(CHAR) * (strlen(strMessage) + 1);
cds.lpData = strMessage;
SendMessage(h_server, WM_COPYDATA, (WPARAM)h_server, (LPARAM)(LPVOID)&cds);
}
}
In fact, the code on the client and server is almost the same. I did it by sending WM_COPYDATA message.
This only applies to two different processes on the same computer. For the console chat of two machines, it is necessary to rely on the TCP protocol.
Related
I am trying to monitor and printout the RAWINPUT from a mouse sent to the foreground window, or just all RAWINPUT from the mouse in general.
the global hook LowLevelMouseProc does not work for me because it returns a MOUSEHOOKSTRUCT that does not give me the dx and dy.
The Raw Input API mentions that for WM_INPUT received when the current window is in the back ground, wParam will be set to RIM_INPUTSINK. But I have no idea how to receive WM_INPUT while the program is in the background.
here is some code explaining what I am trying to do.
int main()
{
//regiter the monitoring device
static bool raw_input_initialized = false;
if (raw_input_initialized == false)
{
RAWINPUTDEVICE rid;
rid.usUsagePage = 0x01; //Mouse
rid.usUsage = 0x02;
rid.dwFlags = 0;
rid.hwndTarget = NULL;
if (RegisterRawInputDevices(&rid, 1, sizeof(rid)) == FALSE)
{
exit(-1);
}
raw_input_initialized = true;
}
HWND targetWindow = { 0 };
while (true)
{
targetWindow = GetForegroundWindow(); // get the window runing in the formost window;
std::cout << targetWindow << '\n';
}
return 0;
}
// enterd every time there is a rawinput to ForegroundWindow, or alternatively just a rawinput in general
LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// print out the values that I need
case WM_INPUT:
UINT dataSize;
GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER)); //Need to populate data size first
std::cout << GET_RAWINPUT_CODE_WPARAM(wParam) << " code thing\n";
if (dataSize > 0)
{
std::unique_ptr<BYTE[]> rawdata = std::make_unique<BYTE[]>(dataSize);
if (GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, rawdata.get(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
{
RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(rawdata.get());
if (raw->header.dwType == RIM_TYPEMOUSE)
{
std::cout << raw->data.mouse.lLastX << std::endl;
}
}
}
break;
}
}
But I have no idea how to receive WM_INPUT while the program is in the background.
You need to specify the RIDEV_INPUTSINK flag when registering the device, per the RAWINPUTDEVICE documentation:
dwFlags
Type: DWORD
Mode flag that specifies how to interpret the information provided by usUsagePage and usUsage. It can be zero (the default) or one of the following values. By default, the operating system sends raw input from devices with the specified top level collection (TLC) to the registered application as long as it has the window focus.
...
RIDEV_INPUTSINK
0x00000100
If set, this enables the caller to receive the input even when the caller is not in the foreground. Note that hwndTarget must be specified.
As such, you must specify an HWND to receive the WM_INPUT messages, and have a message loop to service that window.
Try this:
#include <iostream>
#include <vector>
#include <Windows.h>
LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int main()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASS wc = {};
wc.lpfnWndProc = targetWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("MyRawInputWnd");
if (!RegisterClass(&wc))
return -1;
HWND targetWindow = CreateWindowEx(0, wc.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
if (!targetWindow)
return -1;
//register the monitoring device
RAWINPUTDEVICE rid = {};
rid.usUsagePage = 0x01; //Mouse
rid.usUsage = 0x02;
rid.dwFlags = RIDEV_INPUTSINK;
rid.hwndTarget = targetWindow;
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
return -1;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(targetWindow);
return 0;
}
LRESULT CALLBACK targetWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// print out the values that I need
case WM_INPUT: {
UINT dataSize;
GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, NULL, &dataSize, sizeof(RAWINPUTHEADER)); //Need to populate data size first
std::cout << GET_RAWINPUT_CODE_WPARAM(wParam) << " code thing\n";
if (dataSize > 0)
{
std::vector<BYTE> rawdata(dataSize);
if (GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, rawdata.data(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize)
{
RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(rawdata.data());
if (raw->header.dwType == RIM_TYPEMOUSE)
{
std::cout << raw->data.mouse.lLastX << std::endl;
}
}
}
return 0;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
I am trying to move the mouse (on Windows 10) using SendInput when I perform a physical mouse click. It works fine if I click once or twice, but if clicking for examples 6 times in quick succession the mouse lags for a few seconds then the program stops responding.
Is there any obvious reason why this is happening?
(Edited)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
LRESULT CALLBACK MouseHook(int, WPARAM, LPARAM);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
{
HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseHook, NULL, 0);
MessageBox(NULL, L"Hello", L"Hello", MB_OK);
UnhookWindowsHookEx(hook);
return 0;
}
LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
switch (wParam) {
case WM_RBUTTONUP:
INPUT buffer;
ZeroMemory(&buffer, sizeof(buffer));
buffer.type = INPUT_MOUSE;
buffer.mi.dx = 0;
buffer.mi.dy = 10;
buffer.mi.mouseData = 0;
buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
buffer.mi.time = 0;
buffer.mi.dwExtraInfo = 0;
SendInput(1, &buffer, sizeof(INPUT));
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
Using Raw Input sample:
#include <windows.h>
#include <iostream>
using namespace std;
BOOL registerTouchpadForInput(HWND hWnd)
{
RAWINPUTDEVICE rid;
rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
rid.usUsagePage = 1;
rid.usUsage = 2;
rid.hwndTarget = hWnd;
return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
void getinputdata(LPARAM lparam)
{
HRAWINPUT hInput = (HRAWINPUT)lparam;
RAWINPUT input = { 0 };
UINT size = sizeof(RAWINPUT);
GetRawInputData(hInput, RID_INPUT,&input, &size,sizeof(RAWINPUTHEADER));
if (RIM_TYPEMOUSE == input.header.dwType)
{
if (input.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
{
INPUT buffer;
ZeroMemory(&buffer, sizeof(buffer));
buffer.type = INPUT_MOUSE;
buffer.mi.dx = 0;
buffer.mi.dy = 10;
buffer.mi.mouseData = 0;
buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
buffer.mi.time = 0;
buffer.mi.dwExtraInfo = 0;
SendInput(1, &buffer, sizeof(INPUT));
}
}
return;
}
static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL registrationStatus = false;
switch (message)
{
case WM_CREATE:
registrationStatus = registerTouchpadForInput(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_INPUT:
getinputdata(lParam);
return DefWindowProc(hwnd, message, wParam, lParam);
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int main()
{
WNDCLASSEX wndclass = {
sizeof(WNDCLASSEX),
CS_DBLCLKS,
NVTouch_WindowProc,
0,
0,
GetModuleHandle(0),
LoadIcon(0,IDI_APPLICATION),
LoadCursor(0,IDC_ARROW),
HBRUSH(COLOR_WINDOW + 1),
0,
L"myclass",
LoadIcon(0,IDI_APPLICATION)
};
bool isClassRegistered = false;
isClassRegistered = RegisterClassEx(&wndclass);
if (isClassRegistered)
{
HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
if (window)
{
ShowWindow(window, SW_SHOWDEFAULT);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
been trying to make a basic auto clicker and cannot seem to get MouseInput to click the mouse. I believe it's probably something simple causing this issue. No errors occur it just won't do what it is intended to do.
Could somebody take a look at it and tell me whats wrong with it?
#include <iostream>
#include <Windows.h>
#include <thread>
#include <conio.h>
void loop()
{
int cps;
std::cout << "Enter desired clicks per second: ";
std::cin >> cps;
bool toggled = false;
while (true)
{
static bool bPressedToggle = false;
if (GetKeyState(VK_TAB) < 0)
bPressedToggle = true;
else if (bPressedToggle)
{
bPressedToggle = false;
toggled = !toggled;
std::cout << (toggled ? "Toggled" : "Disabled") << std::endl;
if (!toggled) continue;
}
if (toggled && (GetAsyncKeyState(VK_LBUTTON) & (1 << 16)))
{
POINT pntCurrentCursor;
GetCursorPos(&pntCurrentCursor);
INPUT inpMouseInput;
inpMouseInput.type = INPUT_MOUSE;
inpMouseInput.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
inpMouseInput.mi.dx = pntCurrentCursor.x;
inpMouseInput.mi.dy = pntCurrentCursor.y;
SendInput(1, &inpMouseInput, sizeof(INPUT)); // DOWN
RtlZeroMemory(&inpMouseInput, sizeof(INPUT));
inpMouseInput.type = INPUT_MOUSE;
inpMouseInput.mi.dwFlags = MOUSEEVENTF_LEFTUP;
inpMouseInput.mi.dx = pntCurrentCursor.x;
inpMouseInput.mi.dy = pntCurrentCursor.y;
SendInput(1, &inpMouseInput, sizeof(INPUT)); // UP
Sleep( 1000 / cps);
}
//Sleep(1);
}
}
int main()
{
loop();
return 0;
} ```
As a supplement, the screen coordinates returned by GetCursorPos need to be converted to absolute and passed to SendInput:
dx = (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN);
dy = (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN);
And #IInspectable had provided enough useful information, for this I have created a simple demo for reference only.
#include <iostream>
#include <Windows.h>
#include <thread>
#include <conio.h>
#define IDT_MOUSETRAP 100
HWND hWnd;
bool toggled = false;
int cps;
HANDLE hThread;
BOOL flag = true;
VOID CALLBACK MyTimerProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
POINT pntCurrentCursor;
GetCursorPos(&pntCurrentCursor);
INPUT inpMouseInput;
inpMouseInput.type = INPUT_MOUSE;
inpMouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN;
inpMouseInput.mi.dx = (pntCurrentCursor.x * 65536) / GetSystemMetrics(SM_CXSCREEN);;
inpMouseInput.mi.dy = (pntCurrentCursor.y * 65536) / GetSystemMetrics(SM_CYSCREEN);;
SendInput(1, &inpMouseInput, sizeof(INPUT)); // DOWN
RtlZeroMemory(&inpMouseInput, sizeof(INPUT));
inpMouseInput.type = INPUT_MOUSE;
inpMouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP;
inpMouseInput.mi.dx = pntCurrentCursor.x;
inpMouseInput.mi.dy = pntCurrentCursor.y;
SendInput(1, &inpMouseInput, sizeof(INPUT)); // UP
}
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
UINT uResult = SetTimer(hWnd, IDT_MOUSETRAP, 1000 / cps, (TIMERPROC)MyTimerProc);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, NULL, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool bPressedToggle = false;
DWORD ThreadId;
switch (message)
{
case WM_CREATE:
{
std::cout << "Enter desired clicks per second: ";
std::cin >> cps;
}
break;
case WM_KEYDOWN:
{
if (GetKeyState(VK_TAB) < 0)
{
bPressedToggle = true;
if (bPressedToggle)
{
bPressedToggle = false;
toggled = !toggled;
std::cout << (toggled ? "Toggled" : "Disabled") << std::endl;
}
if (toggled == true && flag == true)
{
flag = false;
hThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &ThreadId);
}
else if (toggled == false && flag == false)
{
KillTimer(hWnd, IDT_MOUSETRAP);
flag = true;
}
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void Createyourwindow()
{
WNDCLASSEXW wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(NULL);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = L"MyClass";
RegisterClassExW(&wcex);
hWnd = CreateWindowW(L"MyClass", L"window", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG msg;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, NULL, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
int main()
{
Createyourwindow();
return 0;
}
Note: Because the message loop of the window is needed, the mouse focus needs to be inside the window when pressing the TAB key.
I'm trying to make a clipboard queue, allowing me to copy multiple things and then paste them FIFO. To do so, I'm using with Windows API as well as a basic keyboard hook to detect ctrl+c and ctrl+v. My code seems to work however I seem to constantly get a random output from the queue.
#include <Windows.h>
#include <stdio.h>
#include <vector>
using namespace std;
vector<char*> clipboardQueue;
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == 0x43 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-c is pressed
WM_COPY;
Sleep(500);
OpenClipboard(NULL);
char* buffer;
buffer = (char*)GetClipboardData(CF_TEXT);
CloseClipboard();
clipboardQueue.push_back(buffer);
cout << buffer << " copied!\n";
cout << "clipboard size: " << clipboardQueue.size() << "\n";
}
else if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed
if (clipboardQueue.size() > 0) {
const char* output = clipboardQueue[0];
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
WM_PASTE;
clipboardQueue.erase(clipboardQueue.begin());
cout << output << " pasted!\n";
cout << "clipboard size: " << clipboardQueue.size() << "\n";
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
OpenClipboard(NULL);
EmptyClipboard();
CloseClipboard();
HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(keyBoard);
}
Using this code when copying "one, two, three, four, five" my outputs seem to be random with occassional missing keys entirely:
three
three
three
?
five
one
?
three
?
five
?
four
four
four
five
Key edits:
When copy data to clipboard using ctrl + c there will sent a WM_CLIPBOARDUPDATE message which you can use to monitor ctrl + c operations. But there is no related message to monitor paste control + v operation so I keep hook part for control + v.
I can reproduce "outputs seem to be random" issue and solve it using array instead of std::vector.
Create a message-only window if you don't need a interact UI.
Add a new custom clipboard format MY_CLIPBOARD_FORMAT to indicate this is set data cased WM_CLIPBOARDUPDATE message not actual control + v operation.
The following is just an example implement for your use case you can refer to:
#include <windows.h>
#define MAX_LOADSTRING 100
#define MY_CLIPBOARD_FORMAT (CF_PRIVATEFIRST + 1)
// Global Variables:
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
static int index = 0;
static char dataArry[10][10] = {};
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK LowLevelKeyboardProc(int, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
DWORD errorCode;
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_QUEUECLIPBOARDDATA, szWindowClass, MAX_LOADSTRING);
// Register window class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
ATOM cls = RegisterClassExW(&wcex);
errorCode = GetLastError();
// Create a message-only window
HWND hWnd = CreateWindowEx(0, szWindowClass, szTitle, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
if (!hWnd)
{
errorCode = GetLastError();
return FALSE;
}
// Set keyboard hook
HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
// Register a clipboard format listener
if (!AddClipboardFormatListener(hWnd))
errorCode = GetLastError();
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (wParam == WM_KEYDOWN) {
if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed
if(index <= 0)
return CallNextHookEx(NULL, nCode, wParam, lParam);
static int i = 0;
if (i < index)
{
const char* output = dataArry[i];
const size_t len = strlen(output) + 1;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), output, len);
GlobalUnlock(hMem);
OpenClipboard(0);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
// Set custom defined format to indicate paste operation
SetClipboardData(MY_CLIPBOARD_FORMAT, NULL);
CloseClipboard();
OutputDebugStringA("\n pasted!\n");
i++;
}
else
{
i = 0;
index = 0;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD errorCode;
HANDLE clipObj = NULL;
char* lptstr = NULL;
switch (message)
{
case WM_CLIPBOARDUPDATE:
{
OutputDebugStringA("\nWM_CLIPBOARDUPDATE\n");
// Empty clipboard casue this WM_CLIPBOARDUPDATE, actually no new data copied
if (IsClipboardFormatAvailable(MY_CLIPBOARD_FORMAT))
break;
if (!IsClipboardFormatAvailable(CF_TEXT))
break;
if (!OpenClipboard(hWnd))
{
errorCode = GetLastError();
break;
}
clipObj = GetClipboardData(CF_TEXT);
if(NULL == clipObj)
{
errorCode = GetLastError();
break;
}
lptstr = (char*)GlobalLock(clipObj);
if (lptstr != NULL)
{
OutputDebugStringA(lptstr);
memcpy(dataArry[index++], lptstr, strlen(lptstr));
GlobalUnlock(lptstr);
}
CloseClipboard();
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
So is there a way to make my Win32 application "think" that the mouse is moving over its window and making some clicks when the actual window is hidden (i mean ShowWindow(hWnd, SW_HIDE);)?
I tried to simulate mouse moving with PostMessage and SendMessage but no luck so far.
int x = 0;
int y = 0;
while (true)
{
SendMessage(hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
x += 10;
y += 10;
Sleep(100);
}
Is this even possible?
Yes it's possible. This is a test hidden window:
#define UNICODE
#include <Windows.h>
#include <Strsafe.h>
#include <Windowsx.h>
LRESULT CALLBACK WndProc(HWND Hwnd, UINT Msg, WPARAM WParam, LPARAM LParam);
INT CALLBACK
WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
INT nCmdShow)
{
WNDCLASSEX WndClass;
ZeroMemory(&WndClass, sizeof(WNDCLASSEX));
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.lpfnWndProc = WndProc;
WndClass.hInstance = hInstance;
WndClass.lpszClassName = L"HiddenWinClass";
if(RegisterClassEx(&WndClass))
{
HWND Hwnd;
MSG Msg;
Hwnd = CreateWindowEx(0, L"HiddenWinClass", L"Nan",
0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL);
if(Hwnd)
{
UpdateWindow(Hwnd);
ShowWindow(Hwnd, SW_HIDE);
while(GetMessage(&Msg, 0, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
}
return 0;
}
LRESULT CALLBACK
WndProc(HWND Hwnd,
UINT Msg,
WPARAM WParam,
LPARAM LParam)
{
TCHAR Message[255];
switch(Msg)
{
case WM_MOUSEMOVE:
StringCbPrintf(Message, sizeof(Message), L"(%d, %d)",
GET_X_LPARAM(LParam), GET_Y_LPARAM(LParam));
MessageBox(NULL, Message, L"WM_MOUSEMOVE", MB_OK);
break;
default:
return DefWindowProc(Hwnd, Msg, WParam, LParam);
}
return 0;
}
and this is your code:
#define UNICODE
#include <Windows.h>
int
main(int argc, char **argv)
{
HWND Hwnd;
if((Hwnd = FindWindow(L"HiddenWinClass", L"Nan")))
{
int x, y;
for(x = y = 0 ; ; x += 10, y += 10)
{
SendMessage(Hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
Sleep(100);
}
}
return 0;
}
It works nicely.