I have a C++ program that enumerates all the input devices (using direct input) at the start of the program. If the program is started, and then I plug in another controller, this controller won't be recognized until the program is restarted. Anyone know of an event I can use that will cause my program to enumerate all of the devices after a new one is plugged in?
This article discusses how to detect game pad changes. First of all, you can handle the WM_DEVICECHANGE message and check wParam for DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE. It seems that in order to receive these as WPARAMs, though, you need to call RegisterDeviceNotification first.
The article's example of how to do this is as follows:
DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
ZeroMemory(¬ificationFilter, sizeof(notificationFilter));
notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notificationFilter.dbcc_size = sizeof(notificationFilter);
HDEVNOTIFY hDevNotify;
hDevNotify = RegisterDeviceNotification(m_hWnd, ¬ificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE |
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if(hDevNotify == NULL) {
// do some error handling
}
The only other thing to watch out for is that the minimum supported OS for this is XP, so you need to put in the appropriate #define for that before including the Windows headers.
Depending on what you want to do, you might not even have to call this function first. Instead, you can just check DBT_DEVNODES_CHANGED to not differentiate between a device being plugged or unplugged. That could save some code if you don't care.
Got it working. When any device is removed or added just dispose all 'IDirectInputDevice8' and re-create them. This avoids bugs and keeps things simple.
Hook WinProc method to watch for add/remove events
bool refreshInputDevices = false;
LRESULT SubWndProc(int code, WPARAM wParam, LPARAM lParam)
{
// invalid code skip
if (code < 0) return CallNextHookEx(NULL, code, wParam, lParam);
// check if device was added/removed
PCWPSTRUCT pMsg = PCWPSTRUCT(lParam);
if (pMsg->message == WM_DEVICECHANGE)
{
switch (pMsg->wParam)
{
case DBT_DEVNODES_CHANGED:
refreshInputDevices = true;
break;
case DBT_DEVICEARRIVAL:
refreshInputDevices = true;
break;
case DBT_DEVICEREMOVECOMPLETE:
refreshInputDevices = true;
break;
}
}
// continue as normal
return CallNextHookEx(NULL, code, wParam, lParam);
}
Here is how you can hook on the input thread
// hook WinProc to watch for device changes
HMODULE module = GetModuleHandleW(NULL);
DWORD threadID = GetCurrentThreadId();
HHOOK hook = SetWindowsHookExW(WH_CALLWNDPROC, (HOOKPROC)&SubWndProc, module, threadID);
Related
I want my application to hook remote connect and disconnect events for all sessions on the specified computer.
According to the documentation, I should call WTSRegisterSessionNotification function first:
WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_ALL_SESSIONS);
Then in the messages processor callback I should do the required stuff on WM_WTSSESSION_CHANGE message type:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_WTSSESSION_CHANGE:
{
// do stuff
break;
}
}
}
It works very strange however. Every time I connect or disconnect to/from the computer where my application running, WTS_REMOTE_CONNECT or WTS_REMOTE_DISCONNECT called twice -- in one of these calls I can get user name and in another I can't (it's just an empty string).
case WM_WTSSESSION_CHANGE:
{
const int reason = (int)wParam;
const DWORD sessionId = (DWORD)lParam;
switch (reason)
{
case WTS_REMOTE_CONNECT:
{
DWORD bytesReturned = 0;
LPSTR pData = NULL;
if (WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pData, &bytesReturned) == 0)
{
// Handle error
break;
}
const std::string username = pData;
WTSFreeMemory(pData);
// do other stuff
I found this question but it has very strange accepted answer:
Hmm, the answer appears to be that it's fairly normal for these fields
to be empty on a terminal services/RDP session
I don't understand why it actually works this way.
I am working a program to simulate keyboard and mouse clicks programmatically. It need to send the clicks to a target window handle (ex: notepad edit control). I am getting the handle of notepad window and generating generating WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP messages for that window. The events are stored in queue, and later on played using a WH_JOURNALPLAYBACK hook.
For the code snippet below, the target hwnd in the playback proc though set correctly, messages never reach to the target handle. If I bring the notepad to foreground, it does receive the messages.
I am not sure why WH_JOURNALPLAYBACK ignores the handle parameter. I would have liked to generate a series of automation messages for various handles and played it back so that even without bringing the window into focus we can send keyboard and mouse events.
Please let me know
if messages to various target handles can be sent using a journal
playback hook
why in code below hwnd is ignored
..
#include <queue>
#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
using std::error;
struct Event
{
UINT msg;
UINT wparam;
UINT lparam;
HWND hwnd;
Event(UINT m, UINT wp, UINT lp, HWND h)
:msg(m),
wparam(wp),
lparam(lp),
hwnd(h)
{}
};
HHOOK jhook= NULL;
std::queue<Event> events;
bool gotoNextMsg = false;
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
switch( code )
{
case HC_SKIP:
cout<<"skip: "<<endl;
if(!events.empty())
{
events.pop();
}
break;
case HC_GETNEXT:
{
cout<<"next: "<<events.size()<<endl;
gotoNextMsg = true;
EVENTMSG * evm = (EVENTMSG*) lParam;
Event e = events.front();
switch(e.msg)
{
case WM_KEYDOWN:
cout<<"WM_KEYDOWN"<<endl;
break;
case WM_KEYUP:
cout<<"WM_KEYUP"<<endl;
break;
case WM_SYSKEYDOWN:
cout<<"WM_SYSKEYDOWN"<<endl;
break;
case WM_SYSKEYUP:
cout<<"WM_SYSKEYUP"<<endl;
break;
}
cout<<"handle: "<<e.hwnd<<endl;
cout<<"handle1:"<<evm->hwnd<<endl;
evm->message = e.msg;
evm->paramL = e.wparam;
evm->paramH = e.lparam;
evm->hwnd = e.hwnd;
evm->time = ::GetTickCount();
}
break;
default:
if( code < 0 )
::CallNextHookEx(jhook, code, wParam, lParam);
break;
}
if(events.empty())
{
cout<<"uinstalled"<<endl;
::UnhookWindowsHookEx(jhook);
::PostMessage(NULL, WM_USER+100, 0, 0);
}
return 0;
}
A journal hook injects events into the system message queue. For keyboard and mouse messages, the system dispatches them to the current focused window, same as if the user had input them manually. The HWND you specify in the event is not used, it gets replaced during dispatching.
And if you consider that a recorded journal can be played multiple times, and its data can persist across application instances and even reboots, and that HWNDs can be reused for different things over time, it should make sense why a journal playback cannot make use of an event's HWND even if the system message queue were not involved.
So, you cannot use WH_JOURNALPLAYBACK to target a specific window that is not in the foreground. You would have to send the recorded messages yourself. But be aware of some caveats that Raymond Chen has blogged about:
You can't simulate keyboard input with PostMessage
Simulating input via WM_CHAR messages may fake out the recipient but it won't fake out the input system
I have a dll that gets called by a process and now I would like to implement an input check in the dll to react on certain inputs that occur in the application.
SetWindowsHookEx() with a KeyboardProc function seemed like a possible solution so I implemented it.
This is roughly how the code in the dll looks like:
static HHOOK hhk = NULL;
LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code == HC_ACTION && ((DWORD)lParam & 0x80000000) == 0) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n");
break;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
if(AllocConsole()){
freopen("CONOUT$", "w", stdout); // redirect output to console for debugging
}
printf("Dll loaded, lastError = %i\n", GetLastError());
printf("lastError = %i\n", GetLastError());
// sidenote: for some reason the first GetLastError() returns 0 while the second one returns 6 (invalid handle)
hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId());
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
printf("\nCleaning up...");
FreeConsole();
UnhookWindowsHookEx(hhk);
}
return TRUE;
}
However nothing happens (or gets printed) in the Console window when I press any key. It doesn't even seem like the keyboardProc function is accessed at any time.
It does work though when I pass NULL instead of GetCurrentThreadId() to SetWindowsHookEx().
But this causes the hook to work globally meaning that whenever I press a key in another application, a Console window pops up (because the dll gets called again) and he checks for key inputs there.
Obviously this is not desired and I would like to make this work with only the process that originally called the dll.
I already checked if GetCurrentThreadId() returns a valid ID and it seems to be indeed the main thread ID of the process that initially called the dll (checked with Process Explorer).
So now my question is what could be the problem and more importantly, what can I do to make it working?
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint process_id;
uint thread_id = GetWindowThreadProcessId(windowHandle, out process_id);
hhook = SetWindowsHookEx(WH_KEYBOARD, a_KeyboardProc, hInstance, 0);
I have used the code above to get the main thread_ID for a certain process. The good part is, the SetWindowsHookEx function gives a logical output. Unfortunately, the bad part is, if a key is pressed in the thread that has been hooked, the thread stops working.
In specific, the idHook parameter of SetWindowsHoookEx function was set to 2 (instead of 13) in my case for non-low-level keyboard events. It seems, at least to me, that LL corresponds to low-level, where keyboardProc should come with a WH_KEYBOARD instead of WH_KEYBOARD_LL.
I am not sure at this point how my response would be related to your question. Hopefully, we get what we need through discussion.
I've been reading posts all over and trying different approaches, but I can't make this work.
I want to be able to track the last window before the user clicks on my application. This way I can bring it to the front and send a copy command to retrieve whatever the user has selected.
I thought about using hooks to receive notifications of activated windows, but it is not working as expected. I'm using HSHELL_WINDOWACTIVATED global hook to keep track of the current and last active window, but I always get both handles to be the same, pointing to my application.
The code looks like:
#pragma data_seg("ASEG")
HWND lastWindow = 0;
HWND currentWindow = 0;
#pragma data_seg()
#pragma comment(linker, "/section:ASEG,RWS")
HINSTANCE dllHandle;
BOOL APIENTRY DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
PVOID lpReserved )
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
dllHandle = hinstDLL;
return TRUE;
break;
}
}
LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode > 0)
{
switch (nCode)
{
case HSHELL_WINDOWACTIVATED: lastWindow = currentWindow;
currentWindow = (HWND)wParam;
break;
}
}
return ::CallNextHookEx(NULL, nCode,wParam,lParam);
}
extern "C" {
__declspec(dllexport) void Init()
{
SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHandle, 0);
}
}
Later on I would use the lastWindow to bring that window to the front and send a Ctrl+C command.
If you call GetWindowTextA(..) for each handle, the first time you activate a different window and go back to the application, lastWindow retrieves blank and currentWindow my application name. Any consecutive activations retrieve always the name of my application for both lastWindow and currentWindow.
I don't quite understand why this is happening. Any ideas?
Thanks!
I think you can use SetWinEventHook. This hook should allow you to capture the EVENT_SYSTEM_FOREGROUND message so that each time a window is brought to the foreground, you can capture the window handle. Then when your app window is activated, just look at the last value you captured.
See this: https://stackoverflow.com/a/4407715/1502289
Also, in your own code, you could simply do a comparison to see if the window handle is the handle to your own window. If not, save the handle.
Example:
...
case HSHELL_WINDOWACTIVATED:
if (lastWindow != [your own window's handle])
{
lastWindow = (HWND)wParam;
}
break;
...
I have a little console application that has an embedded v8 engine, and I would like to add a hook to register key events. This all worked before when I was using Qt and QtScript, but I am porting it all over to straight C++ in VC++ 2008. The application compiles and runs, but the hook is never called, here is the relevant code:
In main()
HWND hwndC = GetConsoleWindow() ;
HINSTANCE hInst = (HINSTANCE)GetWindowLong( hwndC, GWL_HINSTANCE );
if (SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInst, NULL) == 0) {
printf("Failed to set hook\n");
} else {
printf("Hook established\n");
}
g->RunScript(argc,argv);
And the proc:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf("HookProc called\n");
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) (lParam);
if (wParam == WM_KEYDOWN) {
keyDown(p,g);
} else if (wParam == WM_KEYUP) {
keyUp(p,g);
}
fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
This is essentially an expansion on shell.cc from the v8 sample code. I wonder if it is somehow blocking? I admit to not really knowing what I am doing here, just playing around and learning but this one has me stumped.
Inside of keyDown say, I have something like this:
v8::Handle<v8::String> callback_name = v8::String::New("onKeyDown");
v8::Handle<v8::Value> callback_val = g->_context->Global()->Get(callback_name);
if (!callback_val->IsFunction()) {
printf("No onKeyDown handler found\n");
return;
}
v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(callback_val);
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { v8::Int32::New(char(p->vkCode)) };
printf("Calling onKeyDown\n");
v8::Handle<v8::Value> result = callback->Call(g->_context->Global(), argc, argv);
Some of this may actually not work in the end, but it just never gets called, when I run the program, and define: onKeyDown = function(key) {...}; I can see that onKeyDown is working just fine, I can use all of my bound c++ method etc from JS, so this thing is just driving me batty.
Any help, maybe pointers to some educational materials would be much appreciated.
Just to be clear, this function in c: LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) is never getting called, or never seeing a printf, and the output at the start says: Hook established, so windows is reporting the hook is established.
/Jason
A low-level hook, like WH_KEYBOARD_LL requires that your application pumps a message loop. That's the only way that Windows can break into your thread and make the call to the HookProc callback you registered.
A console mode app doesn't pump a message loop like regular Windows GUI apps do. Judging from your snippet, it isn't going to be easy to add one either. You'll need to create a thread.
Maybe this function will be of help to you?
GetAsyncKeyState