Discover which monitor has touch capabilities on Windows 10 - c++

I have a two-monitor setup running on Windows 10 and my secondary monitor is a touch-screen. I can detect both monitors with EnumDisplayMonitors and discover that there is a digitizer present with GetSystemMetrics(SM_DIGITIZER). I'd like my app window to open on the touch monitor, but I can't find any function that tells me which monitor the digitizer "belongs" to.
In the absence of a solution, I suppose I could have a start-up sequence during which the user is asked to tap the touch screen, then my code could move the window to the corresponding monitor. I'd just like it to be slicker than that.
Any ideas?

GetPointerDevices function give you that information. POINTER_DEVICE_INFO contains monitor handle and device pointer type in the same structure:
typedef struct tagPOINTER_DEVICE_INFO {
DWORD displayOrientation;
HANDLE device;
POINTER_DEVICE_TYPE pointerDeviceType; // can be POINTER_DEVICE_TYPE_TOUCH see below
HMONITOR monitor; // Monitor handle
ULONG startingCursorId;
USHORT maxActiveContacts;
WCHAR productString[POINTER_DEVICE_PRODUCT_STRING_MAX];
} POINTER_DEVICE_INFO;
typedef enum tagPOINTER_DEVICE_TYPE {
POINTER_DEVICE_TYPE_INTEGRATED_PEN,
POINTER_DEVICE_TYPE_EXTERNAL_PEN,
POINTER_DEVICE_TYPE_TOUCH,
POINTER_DEVICE_TYPE_TOUCH_PAD,
POINTER_DEVICE_TYPE_MAX
} POINTER_DEVICE_TYPE;

Related

Detect external devices insertion on Windows

I'm a little bit confused about how to notify my c++ application with event that the user has plugged in a device (USB, HID etc.). Application type is not defined. I'm trying to play around with console/message-only/service example apps, but there is no result. I'm using VS2015 and Windows 10.
I've found out that there are multiple ways to deal with it:
Using WMI like here. But I can not actually understand where is WMI here.
Using RegisterDeviceNotification and WM_DEVICECHANGE. As far as I can understand, there is no way to do that for the console applications, only for once with the GUI (real window) or for the message-only window. I've tried the last one with the example from this answer but my app doesn't receive any notifications when I plug in my USB flash drive. I've found this answer (from the same question as the answer mentioned above) and tried to use ChangeWindowMessageFilterEx() function with GetProcAddress from user32.dll to load it without connection dll to my app in such way:
BOOL InitInstance(HWND hWnd)
{
HMODULE hDll = GetModuleHandle(TEXT("user32.dll"));
if (hDll)
{
typedef BOOL(WINAPI *MESSAGEFILTERFUNCEX)(HWND hWnd, UINT message, DWORD action, VOID* pChangeFilterStruct);
const DWORD MSGFLT_ALLOW = 1;
MESSAGEFILTERFUNCEX ChangeWindowMessageFilterEx= (MESSAGEFILTERFUNCEX)::GetProcAddress(hDll, "ChangeWindowMessageFilterEx");
if (ChangeWindowMessageFilterEx) return func(hWnd, WM_COPYDATA, MSGFLT_ALLOW, NULL);
}
return FALSE; }
And the usage of this function is:
hWnd = CreateWindowEx(0, CLS_NAME, "DevNotifWnd", WS_ICONIC,
0, 0, CW_USEDEFAULT, 0, HWND_MESSAGE,
NULL, GetModuleHandle(0), (void*)&guid);
InitInstance(hWnd);
But there is no effect.
Using while(true){...} loop and call appropriate Win API functions like in this answer. But this way seems not be a perfect solution for my problem.
My questions are:
Could anybody explain me what is the best way? And if it is the second one with RegisterDeviceNotification, why it's not working in case of message-only window app?
Do other ways exist? And if not, what can I do, for example, to notify application when some certain software was installed?
Any comments are appreciated.
So I've finally found sort of answers to the questions.
The issue was with the GUID I've provided for the NotificationFilter. So I've set it to receive notifications from all devices with this code:
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
// No need to set up dbcc_classguid as it is ignored when
// DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is setted (see line down below)
HDEVNOTIFY dev_notify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
As far as for other types of notifications in windows that the app could sign up for, I found only one partially deprecated list of all Win32 API functions, where I found some new Notifications with Ctrl+F search :)
Hope this could save somebody's time.

Name of process for active window in Windows 8/10

The following sample has reliably returned the name of the process that is associated with the active window, but does not work with the newer modern/universal apps because it returns the name of a helper process WWAHost.exe on Windows 8 and ApplicationFrameHost.exe on Windows 10 rather than the name of the app.
HWND active_window = GetForegroundWindow();
GetWindowThreadProcessId(active_window, &active_process_id);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, active_process_id);
GetProcessImageFileName(active_process, image_name, 512);
With Windows 10 the ApplicationFrameHost.exe is the process that creates the window handles and is what gets returned by GetWindowThreadProcessId(), is there another Win32 API that can be used to get the active process of universal app that is active?
Also tried using GetApplicationUserModelId() and GetPackageFullName() with no success as they return APPMODEL_ERROR_NO_APPLICATION and APPMODEL_ERROR_NO_PACKAGE respectively because the active_process handle is just the helper process and not the process of the active application.
Any other APIs to use to get the process name of a Modern/Universal application given the hwnd of the window, or otherwise figure out the process name of the universal app is active.
Thanks in advance!
Be sure to use the Spy++ utility when you want to reverse-engineer something like this. Included with Visual Studio, you need the 64-bit version in Common7\Tools\spyxx_amd64.exe. Use Search > Find Window and drag the bullseye to a UWP app, like Weather.
You'll see the window you'll find with GetForegroundWindow(), it has at least 3 child windows:
ApplicationFrameTitleBarWindow
ApplicationFrameInputSinkWindow
Windows.Core.UI.CoreWindow, that's the host window for the UWP app and the one you are interested in. Right-click it and select Properties, Process tab, click the Process ID. That takes you to the real owner process you want to know.
So you just need to make an extra step from the code you already have, you just have to enumerate the child windows and look for one with a different owner process. Some C code, trying to make it as universal as possible without making too many assumptions and not enough error checking:
#include <stdio.h>
#include <Windows.h>
typedef struct {
DWORD ownerpid;
DWORD childpid;
} windowinfo;
BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lp) {
windowinfo* info = (windowinfo*)lp;
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid != info->ownerpid) info->childpid = pid;
return TRUE;
}
int main()
{
Sleep(2000);
HWND active_window = GetForegroundWindow();
windowinfo info = { 0 };
GetWindowThreadProcessId(active_window, &info.ownerpid);
info.childpid = info.ownerpid;
EnumChildWindows(active_window, EnumChildWindowsCallback, (LPARAM)&info);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info.childpid);
WCHAR image_name[MAX_PATH] = { 0 };
DWORD bufsize = MAX_PATH;
QueryFullProcessImageName(active_process, 0, image_name, &bufsize);
wprintf(L"%s\n", image_name);
CloseHandle(active_process);
return 0;
}
Output on the Weather program:
C:\Program Files\WindowsApps\Microsoft.BingWeather_4.5.168.0_x86__8wekyb3d8bbwe\
Microsoft.Msn.Weather.exe
Here is a small console app application that continuously (so you can test it easily selecting different windows on your desktop) display information about the current foreground window process and store process, if any.
Apps can have a window hierarchy that can span multiple processes. What I do here is search the first sub window that has the 'Windows.UI.Core.CoreWindow' class name.
This app uses the UIAutomation API (and also smart pointers, smart BSTRs and smart VARIANTs provided by the #import directive). I suppose you can do the same with standard Windows SDK, but I find the UIAutomation used this way quite elegant.
#include "stdafx.h"
#import "UIAutomationCore.dll"
using namespace UIAutomationClient;
int main()
{
// initialize COM, needed for UIA
CoInitialize(NULL);
// initialize main UIA class
IUIAutomationPtr pUIA(__uuidof(CUIAutomation));
do
{
// get the Automation element for the foreground window
IUIAutomationElementPtr foregroundWindow = pUIA->ElementFromHandle(GetForegroundWindow());
wprintf(L"pid:%i\n", foregroundWindow->CurrentProcessId);
// prepare a [class name = 'Windows.UI.Core.CoreWindow'] condition
_variant_t prop = L"Windows.UI.Core.CoreWindow";
IUIAutomationConditionPtr condition = pUIA->CreatePropertyCondition(UIA_ClassNamePropertyId, prop);
// get the first element (window hopefully) that satisfies this condition
IUIAutomationElementPtr coreWindow = foregroundWindow->FindFirst(TreeScope::TreeScope_Children, condition);
if (coreWindow)
{
// get the process id property for that window
wprintf(L"store pid:%i\n", coreWindow->CurrentProcessId);
}
Sleep(1000);
} while (TRUE);
cleanup:
CoUninitialize();
return 0;
}
Does taking snapshot of running processes and pulling the name out of it by comparing process id not work?
Full reference here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686837(v=vs.85).aspx
But you fix the snapshot with CreateToolhelp32Snapshot().
Or from WTSEnumerateProcesses() and surrounding API?
Pretty sure it worked in Win 8. Is it broken in 10?
Starting from Win10 Anniversary Update ApplicationFrameHost child window return anything but UWP application. It worked only in Tablet mode after relogon.

Ungrouping Separate Processes From The Taskbar

I'm writing an application using C++ and Qt which the user can run multiple instances of on the same machine. Each instance of the application has two to three windows associated with them. At the moment, all instances of the application and their windows are grouped together in the taskbar (top image). I want each process to have its own group in the taskbar (bottom image). How can this be achieved?
You can set a different application ID for certain of the windows, or certain of the processes. This is what Windows uses to determine whether to group the icons or not.
Please see this article: http://msdn.microsoft.com/en-us/magazine/dd942846.aspx
Pertinent quote:
Setting the application ID for a process involves a call to the SetCurrentProcessExplicitAppUserModelID Win32 function from shell32.dll. Setting the application ID for a window requires calling the SHGetPropertyStoreForWindow function and then manipulating the returned IPropertyStore object. The following example shows you how to do this:
PROPVARIANT pv;
InitPropVariantFromString(L"MyAppID", &pv);
IPropertyStore* pps;
VERIFY(SHGetPropertyStoreForWindow(hwnd, IID_PPV_ARGS(&pps)));
VERIFY(pps->SetValue(PKEY_AppUserModel_ID, pv));
VERIFY(pps->Commit());
This solution will separate taskbar according to processID. The disadvantage is that the pinning does not work well.
OSVERSIONINFO v;
v.dwOSVersionInfoSize= sizeof(OSVERSIONINFO);
GetVersionEx(&v);
if (v.dwMajorVersion == 6 && v.dwMinorVersion > 1 || v.dwMajorVersion > 6)
{
//on Windows 7 or higher ungroup taskbar for separate process
DWORD currentProcessId = GetCurrentProcessId();
WCHAR AppID[100];
swprintf(AppID, sizeof(AppID) / sizeof(AppID[0]), L"AppID%u", currentProcessId);
SetCurrentProcessExplicitAppUserModelID(AppID);
}

X get and send keystrokes C++

I want to make a text replacement program for linux. ie I type something like .alog, and it gets replaced with /usr/local/apache/logs/. I know I can do this with alaises, but I am often remotely logged on machines that do not have such alaises.
I am also interested in doing this for learning purposes.
I see some info online about grab and send keystrokes in X for a window I make, but can't find info on doing it for all windows in the workspace.
Any suggestions on how to do this would be greatly appreciated.
You may wish to start with the code of a window manager as a starting point; Window Managers bind keys to work regardless of window, this is probably a good start. dwm is widely held to have beautiful code.
setup() appears to add its event mask to the root window directly:
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
/* ... */
/* select for events */
wa.cursor = cursor[CurNormal];
wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
|EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
XSelectInput(dpy, root, wa.event_mask);
grabkeys();

Monitoring Screensaver activity fails on Windows 7

Good afternoon, i have a section of code i am using to monitor screen saver activity in Windows XP onwards, this currently works correctly on all Windows OS's except for Windows 7, i am aware that certain screen saver parameters to the SystemParametersInfo function are not available in Windows 7 but thought that SPI_GETSCREENSAVERRUNNING was available, the code is as follows:
BOOL bScrnSvrRunning = FALSE;
BOOL bResult = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &boolScreenSaverRunning, 0);
The function always returns true for bResult but bScrnSvrRunning is always false,
does anyone have any idea what might cause this?
If you really want to monitor the screen saver activity you can consider to use System Event Notification Service (SENS). The System Event Notification Service monitors and dispatches there, so it can notify your application about the starting (see ISensLogon::StartScreenSaver) and stopping (see ISensLogon::StopScreenSaver) of the screen saver many events. An example how to use SENS you can find here (see also here and here).
You are using the wrong parameter "slot". Look closely at the declaration of SystemParametersInfo:
BOOL WINAPI SystemParametersInfo(
__in UINT uiAction,
__in UINT uiParam,
__inout PVOID pvParam,
__in UINT fWinIni
);
And let me quote the info for SPI_GETSCREENSAVERRUNNING:
Determines whether a screen saver is currently running on the window station of the calling process. The pvParam parameter must point to a BOOL variable that receives TRUE if a screen saver is currently running, or FALSE otherwise.
pvParam is the one that recieves the info, so you must supply your bool in the pvParam parameter:
BOOL bScrnSvrRunning = FALSE;
BOOL bResult = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &boolScreenSaverRunning, 0);