I've tried using RegisterPointerInputTarget (Win32 API) to capture all PT_TOUCH messages, but my app behaves exactly as if the function was never called. I've followed all advice I could find: the app has uiAccess=true, is signed, and is installed to C:\Program Files. The windows is created as a child of HWND_MESSAGE and the RegisterPointerInputTarget returns 1. However, my WndProc is not receiving any WM_POINTER messages at all. If I instead create a normal window, my WndProc receives WM_POINTER messages as expected, only when I'm pointing over the window.
Below is the code of my program. Note that the calls to InitializeTouchInjection, ShowWindow, UpdateWindow and AccSetRunningUtilityState should be unnecessary, I've just been trying everything I've seen in any example I could find.
I'm using a Wacom Intuos, tried both with the pen and with the fingers.
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include "oleacc.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_NCPOINTERUP:
case WM_NCPOINTERDOWN:
case WM_NCPOINTERUPDATE:
case WM_TOUCH:
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE:
{
std::cout << "TOUCH MESSAGE " << message << " WPARAM " << wParam << " LPARAM " << lParam << std::endl;
break;
}
}
std::cout << "SOME MESSAGE " << message << " HWND " << hWnd << " WPARAM " << wParam << " LPARAM " << lParam << std::endl;
return DefWindowProc(hWnd, message, wParam, lParam);
}
int main()
{
//InitializeTouchInjection(10, TOUCH_FEEDBACK_NONE);
LPCSTR className = "TouchHookWindow";
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
//wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
//wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
//wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = className;
if (!RegisterClass(&wc))
{
std::cout << "Failed to register window class!\n";
return -1;
}
DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
DWORD dwStyle = WS_OVERLAPPEDWINDOW;
//DWORD dwExStyle = WS_EX_NOACTIVATE;// | WS_EX_TRANSPARENT;
//DWORD dwStyle = WS_OVERLAPPEDWINDOW;
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 100;
rc.bottom = 100;
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
//HWND hWnd = CreateWindowEx(dwExStyle, className, "Touch Hook", dwStyle, 0, 0, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL);
HWND hWnd = CreateWindowEx(0, className, "TouchHook", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
//HWND hWnd = CreateWindowEx(dwExStyle, className, "TouchHook", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, hInstance, NULL);
//HWND hWnd = CreateWindowEx(dwExStyle, className, "TouchHook", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
std::cout << "Failed to create window!\n";
return -1;
}
//ShowWindow(hWnd, SW_SHOW);
//UpdateWindow(hWnd);
//SetForegroundWindow(hWnd);
//SetFocus(hWnd);
{
BOOL result = RegisterTouchWindow(hWnd, 0);
std::cout << "RegisterTouchWindow result " << result << std::endl;
}
{
BOOL result = RegisterPointerInputTarget(hWnd, PT_TOUCH);
std::cout << "RegisterPointerInputTarget result " << result << std::endl;
}
{
//HRESULT hr = AccSetRunningUtilityState(hWnd, ANRUS_TOUCH_MODIFICATION_ACTIVE, ANRUS_TOUCH_MODIFICATION_ACTIVE);
//std::cout << "AccSetRunningUtilityState " << (FAILED(hr) ? "FAILED" : "SUCCESS") << std::endl;
}
{
MSG msg;
BOOL result;
while (result = GetMessage(&msg, NULL, 0,0) != 0)
{
if (result != -1)
{
if (msg.message == WM_QUIT)
{
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
return 0;
}
Related
I'm trying to make an input library and I need to know if I have to account for the possibility that a person quickly clicking a mouse button can generate a RAWINPUT with both a RI_MOUSE_LEFT_BUTTON_DOWN and RI_MOUSE_LEFT_BUTTON_UP in it. The documentation seems to indicate that this might be possible, stating "The transition state of the mouse buttons. This member can be one or more of the following values."
EDIT:
I created a small program to feedback all the input packets from mouse and keyboard and a small autohotkey script to attempt to send Left button down and up at the same time, I was unable to create a packet with both left click up and down at it simultaneously.
Below is the C++ code and AHK script I used to test:
C++ code:
#include <windows.h>
#include <iostream>
using namespace std;
char mc[] = "mainclass";
int once = 1;
LRESULT CALLBACK mainproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
RAWINPUT fdsa;
int size = 48;
switch(message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_INPUT:
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &fdsa, &size, sizeof(RAWINPUTHEADER));
if(fdsa.header.dwType == RIM_TYPEMOUSE)
{
cout << "mouse X = " << fdsa.data.mouse.lLastX << "\nmouse Y = " << fdsa.data.mouse.lLastY << "\nmouse buttons = " << fdsa.data.mouse.usButtonFlags << endl << endl;
}
else if(fdsa.header.dwType == RIM_TYPEKEYBOARD)
{
cout << "vkey = " << fdsa.data.keyboard.VKey << " & ";
if((fdsa.data.keyboard.Flags&1)==1)
cout << "up\n\n";
else
cout << "down\n\n";
}
break;
default:
return DefWindowProc(hwnd, message, wparam, lparam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hthisinst, HINSTANCE hprevinst, LPSTR lpszArgument, int nCmdShow)
{
HWND mainwin;
MSG messages;
WNDCLASSEX wc;
wc.hInstance = hthisinst;
wc.lpszClassName = mc;
wc.lpfnWndProc = mainproc;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if(!RegisterClassEx(&wc))
return 0;
mainwin = CreateWindowEx(0, mc, "main window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hthisinst, NULL);
RAWINPUTDEVICE Rid[2];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = 0x100;
Rid[0].hwndTarget = mainwin;
Rid[1].usUsagePage = 0x01;
Rid[1].usUsage = 0x06;
Rid[1].dwFlags = 0x100;
Rid[1].hwndTarget = mainwin;
if(RegisterRawInputDevices(Rid, 2, sizeof(Rid[0])) == FALSE)
{
cout << "rawinput registration failed.\n";
return 3;
}
while(GetMessage(&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
ahk script:
$f::
Sendinput {LButton Down}{LButton up}
Sendinput {LButton up}{LButton down}
return
I also tried
$f::
Sendinput {LButton Down}{RButton Down}
Sendinput {LButton up}{RButton up}
Unfortunately the second script didn't cause both keys to be pressed or released at the same time, which I can guarantee is possible because I've done it manually and verified it with the c++ program.
I can't understand why I got a loop on BeginPaint function. I have already read posts about this kind of loop but almost all of them recommend: "Don't forget to use BeginPaint function on WM_PAINT message, because it entails subsequent WM_PAINT messages otherwise". This isn't my case. May you give me some advices?
This is my windowclass ("CWindow"):
class CWindow {
public:
CWindow();
virtual ~CWindow();
bool RegisterClass(HINSTANCE hInstance);
bool CreateWnd(HINSTANCE hInstance);
bool Show(int nShow);
private:
HWND handleWindow;
ATOM atom;
bool isRegistered;
bool isCreated;
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void OnPaint();
void OnDestroy();
};
WndProc function.
LRESULT CALLBACK CWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CWindow* windowPtr = reinterpret_cast<CWindow*> ( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
PAINTSTRUCT ps;
HDC hdc;
switch( msg ) {
case WM_PAINT:
// There is a loop right here!
hdc = BeginPaint( windowPtr->handleWindow, &ps );
// The code below doesn't executed!
RECT rect;
(void)GetClientRect(windowPtr->handleWindow, &rect);
(void)DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint( windowPtr->handleWindow, &ps );
break;
case WM_DESTROY:
windowPtr->OnDestroy();
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
RegisterClass
bool CWindow::RegisterClass(HINSTANCE hInstance)
{
const TCHAR app_name[] = TEXT("HelloWin");
WNDCLASSEX windowClass;
ZeroMemory( &windowClass, sizeof(windowClass) );
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = 0;
windowClass.hIcon = 0;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = app_name;
windowClass.hIconSm = NULL;
atom = RegisterClassEx( &windowClass );
DWORD errorCode = GetLastError();
if( errorCode ) {
isRegistered = 0;
std::wcout << L"ErrorCode: " << errorCode << std::endl;
} else {
isRegistered = 1;
}
return isRegistered;
}
CreateWindow
bool CWindow::CreateWnd(HINSTANCE hInstance)
{
handleWindow = CreateWindow((PCTSTR)atom, // window class name or atom
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
DWORD errorCode = GetLastError();
if( !handleWindow ) {
isCreated = 0;
} else {
isCreated = 1;
}
return isCreated;
}
Show
bool CWindow::Show(int nShow)
{
if( isCreated ) {
ShowWindow( handleWindow, nShow );
return UpdateWindow( handleWindow );
} else {
return 0;
}
}
WinMain
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevINstance, LPSTR lpCmdLine, int nShow )
{
CWindow window;
window.RegisterClass( hInstance );
window.CreateWnd( hInstance );
window.Show( nShow );
int response = 0;
MSG msg;
while( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
Since you never call SetWindowLongPtr,
CWindow* windowPtr = reinterpret_cast<CWindow*>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
returns a nullptr, that you subsequently try to dereference:
BeginPaint( windowPtr->handleWindow, &ps )
That will trigger an access violation exception, causing the BeginPaint call to never even get executed, leaving the invalid region as is. As a consequence, the system keeps generating WM_PAINT messages. That's the same issue as not calling BeginPaint altogether.1
To solve this, you'll either have to attach the window handle to the window instance by calling SetWindowLongPtr, or simply use the hWnd parameter that's passed into your CWindow::WindowProc.
1 Note that the system silently handles unhandled exceptions in your WindowProc on 64-bit versions of Windows under certain conditions.
A GUI app I'm writing does send a keydown event to another window, a cmd.exe.
PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
The event is sent just fine when it's done on events like WM_CREATE, WM_KEYUP, etc (a new line appears in cmd.exe).
Then I setup a global hotkey with RegisterHotKey. In a WM_HOTKEY handler I successfully receive key presses but PostMessage has no effect anymore.
How to fix that?
Full example, minified as possible:
#include <iostream>
#include <Windows.h>
using namespace std;
const char g_szClassName[] = "myWindowClass";
BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam) {
char winTitle[1024*10];
GetWindowText(hwnd, winTitle, sizeof(winTitle));
if (strstr(winTitle, "cmd.exe") != NULL) {
cout << "Sending a message to window " << hwnd << ": " << winTitle << endl;
PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_CREATE:
// register hotkey ctrl+alt+s
RegisterHotKey(hwnd, 100, MOD_ALT | MOD_CONTROL, 'S');
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
EnumWindows(enumWindows, 0);
PostQuitMessage(0);
break;
case WM_HOTKEY:
// hotkey ctrl+alt+s fired
EnumWindows(enumWindows, 0);
break;
case WM_KEYUP:
EnumWindows(enumWindows, 0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// just init stuff, do not waste your time
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Windows 7 64-bit
Raymond Chen has documented why this doesn't work the way you expect (PostMessage IS working just fine, but the response of the other window depends on actual keyboard state, just as I surmised in my comment). See his blog post:
You can't simulate keyboard input with PostMessage
I am trying to create an OpenGL window inside of already existing parent window using win32 api. However, when creating a child, the function CreateWindowEx returns NULL with an error 1407 ERROR_CANNOT_FIND_WND_CLASS. The window must be a child so there is a space left for other controls such as buttons and checkboxes...
Part of code that creates the parent window:
WNDCLASSEX wincl;
wincl.style = 0;
wincl.lpszMenuName = NULL;
wincl.lpszClassName = L"WindowClass";
wincl.lpfnWndProc = WndProc;
wincl.hInstance = hInstance;
wincl.hIconSm = LoadIcon(NULL, IDC_ICON);
wincl.hIcon = LoadIcon(NULL, IDC_ICON);
wincl.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wincl.cbWndExtra = 0;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.cbClsExtra = 0;
if(!RegisterClassEx(&wincl)){
std::cout << "Window failed to register!" << std::endl;
return false;
}
DWORD style = WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU | WS_SIZEBOX;
parentHwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
L"WindowClass",
L"Title",
style,
CW_USEDEFAULT, // X
CW_USEDEFAULT, // Y
800, // Width
600, // Height
NULL,
NULL,
hInstance,
0);
if (parentHwnd == NULL){
std::cout << "Window failed to create!" << std::endl;
return false;
}
ShowWindow(parentHwnd, SW_SHOWNORMAL);
UpdateWindow(parentHwnd);
Inside the message loop, I am creating the child window:
LRESULT WndProc(HWND hwnd, UINT Msg, WPARAM wParam , LPARAM lParam){
switch (Msg){
case WM_CREATE:{
// Create child OpenGL window
childHwnd = CreateWindowEx(0,
L"OpenGL",
NULL,
WS_CLIPCHILDREN | WS_VISIBLE,
100, // X
100, // Y
400, // Width
300, // Height
hwnd, // Parent
0, // ID
NULL,
NULL);
// Prints 1407 ERROR_CANNOT_FIND_WND_CLASS
std::cout << "Last error: " << GetLastError() << std::endl;
}
default:{
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
}
return 0;
}
I have looked into several tutorials (NeHe, cs.rit.edu, and many other but I can't post more than 2 links) and all of them used L"OpenGL" as class name for the second argument in the function CreateWindowEx().
What am I doing wrong? Is "OpenGL" a valid class name such as "Edit" / "Static" / "Button" ? Can I replace it with something else? I tried "Static" but it did not rendered anything.
I know there are many libraries (GLFW, SDL, ...) that handle window creation, but I need to use pure win32 API.
UPDATE:
RegisterClass() solved the problem. Here is the code that works for me:
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance; // Same hinstance used by parent
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"OpenGL";
wc.style = CS_OWNDC;
if(!RegisterClass(&wc)){
std::cout << "Failed to register window!" << std::endl;
return false;
}
childHwnd = CreateWindowEx(0, // Must be zero
L"OpenGL",
NULL,
WS_VISIBLE | WS_CHILD,
100, // X
100, // Y
400, // Width
300, // Height
parentHwnd, // Parent HWND
0, // ID
hInstance, // Same hinstance used by parent
NULL);
I was programming the example code from Frank Luna's book "Introduction to 3D Game Programming with DirectX 10". The code is the first Win32 example in the Appendix A: Windows Programming section.
Right now, the program compiles under both VC++ 2008/2010, but no window appears, although the debug session has started and I have to forcefully close it. I have no idea where it is, I'm not using Win32 Console mode, I have closed all other windows and no other IDE or session of VC++ is running.
Any idea why this might be happening?
PS: I have also checked my Processes. It is indeed running.
#include <Windows.h>
HWND ghMainWnd = 0;
bool InitWindowsApp(HINSTANCE instanceHandle, int show);
int Run();
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI
WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd )
{
if( !InitWindowsApp(hInstance, nShowCmd) )
return 0;
return Run();
}
bool InitWindowsApp( HINSTANCE instanceHandle, int show )
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instanceHandle;
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = L"BasicWndClass";
if( !RegisterClass(&wc) )
{
MessageBox(0, L"RegisterClass FAILED", 0, 0);
return false;
}
ghMainWnd = CreateWindow(
L"BasicWndClass",
L"Win32Basic",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
instanceHandle,
0);
if( ghMainWnd = 0 )
{
MessageBox( 0, L"Window Creation FAILED", 0, 0 );
return false;
}
ShowWindow( ghMainWnd, show );
UpdateWindow( ghMainWnd );
return true;
}
int Run()
{
MSG msg = {0};
BOOL bRet = 1;
while( bRet = GetMessage( &msg, 0, 0, 0 ) != 0 )
{
if( bRet == -1 )
{
MessageBox( 0, L"GetMessage FAILED", 0, 0 );
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK
WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_LBUTTONDOWN:
MessageBox( 0, L"Hello, World", 0, 0 );
return 0;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
DestroyWindow( ghMainWnd );
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
Change this:
if( ghMainWnd = 0 )
{
MessageBox( 0, L"Window Creation FAILED", 0, 0 );
return false;
}
to:
if( ghMainWnd == 0 )
{
MessageBox( 0, L"Window Creation FAILED", 0, 0 );
return false;
}
Two equals signs instead of one. :)
Wild guess: _UNICODE is not defined by project settings. Use CreateWindowW, RegisterClassW, to avoid dependency.