Sending a click event to a Paint application - c++

I am writing an application that automatically draws something on a canvas, depending on the user's preferences.
For starters, how can I send a click event to the MS Paint application?

First, you need to find the Paint application:
static HWND findMSPaintDrawWindow(void)
{
HWND target;
target = FindWindow(TARGET_PAINT_WINDOW, NULL);
if (NULL != target)
{
target = FindWindowEx(target, NULL, TARGET_PAINT_INPUT_SUBWINDOW, NULL);
if (NULL != target)
{
target = FindWindowEx(target, NULL, NULL, NULL);
}
}
if (/*ENABLE_DEBUG_CONSOLE*/ 0)
{
char name[256];
GetClassName(target, name, 255);
printf("Detected ms paint Draw area with name [%s]\n", name);
}
return target;
}
Second, you interact with it:
static void sendMouseButton(int buttonState)
{
HWND target;
UINT buttonMode = WM_LBUTTONUP;
target = findMSPaintDrawWindow();
if (target)
{
if (buttonState)
{
buttonMode = WM_LBUTTONDOWN;
g_MouseDown = 0;
}
printf("INFO: Mouse [%d] msg %d\n", buttonState, buttonMode);
PostMessage(target, buttonMode, MK_LBUTTON, X, Y));
}
}
You can always browse the MSDN documentation for more details.

You have to search google for how to send windows message to different application. The mouse click is composed of 2 different messages: WM_LBUTTONDOWN and WM_LBUTTONUP.
http://stefanstools.sourceforge.net/SendMessage.html
http://www.codeproject.com/Articles/137/Sending-a-message-to-the-Main-Frame-Window-of-Anot

Related

Windows api programming-How to send/post messages to an application window to call up the menu items?

The problem
I have been working on a Windows cloud desktop project this week. One feature requires the server side can response to the users' inputs (mouse, keyboard...) from the client. I post the input messages (e.g., WM_LBUTTONDOWN, WM_KEYDOWN...) from the client to the specific application window in the server. Everything works fine when inputs target is the client area of an application window. However, the menu bar's item ("File" in notepad.exe, for example) does not response to the mouse clicking events. Here list part of my codes:
struct MouseMsg {
UINT msg;
WPARAM wParam;
LPARAM lParam;
};
enum class MouseEvent : unsigned int {
DOWN = 0,
UP,
MOVE,
WHEEL
};
struct MouseInputData
{
int32_t button;
int32_t wheel;
int32_t px;
int32_t py;
};
void ConstructMouseClickMsg(MouseMsg& mouseMsg, MouseInputData* mData, MouseEvent motion)
{
mouseMsg.lParam = MAKELPARAM(mData->px, mData->py);
switch (mData->button)
{
case 0:
{
mouseMsg.wParam = MK_LBUTTON;
mouseMsg.msg = (motion == MouseEvent::DOWN) ? WM_LBUTTONDOWN : WM_LBUTTONUP;
break;
}
case 1:
{
mouseMsg.wParam = MK_RBUTTON;
mouseMsg.msg = (motion == MouseEvent::DOWN) ? WM_RBUTTONDOWN : WM_RBUTTONUP;
break;
}
case 2:
{
mouseMsg.wParam = MK_MBUTTON;
mouseMsg.msg = (motion == MouseEvent::DOWN) ? WM_MBUTTONDOWN : WM_MBUTTONUP;
break;
}
default:
LOG->warn("Unknown mouse button types");
break;
}
}
void OnMouseClick(MouseInputData* mData, MouseEvent motion)
{
HWND mTargetHwnd = GetInputWindow(); // Omit details.
// This function can get the target window's handle
// and can tell if the window is client or menu (parent)
if (!mTargetHwnd)
{
LOG->warn("Null window");
return;
}
// construct mouse clicking messages
MouseMsg mouseMsg;
ConstructMouseClickMsg(mouseMsg, mData->button, motion);
if (mIsClientArea) // in client area or the menu bar? set in GetInputWindow()
{
PostMessageA(mTargetHwnd, mouseMsg.msg, mouseMsg.wParam, mouseMsg.lParam);
}
else
{
// How to ???
}
}
What I have tried
I used spy++ to monitor what messages a window received when the menu bar was clicked (as lines 1296~1327 in the following picture shows). WM_NCHITTEST, WM_NCLBUTTONDOWN, WM_SYSCOMMAND seemed to be the solution. I tried post all these messages but no response either.
Have-a-try codes:
if (mIsClientArea) // in client area or the menu bar? set in GetInputWindow()
{
PostMessageA(mTargetHwnd, mouseMsg.msg, mouseMsg.wParam, mouseMsg.lParam);
}
else
{
// How to ???
LOG->info("try to call up menu");
if (motion == MouseEvent::DOWN)
{
PostMessageA(mTargetHwnd, WM_NCLBUTTONDOWN, HTMENU, mouseMsg.lParam);
//PostMessageA(mCurrentHwnd, WM_SYSCOMMAND, SC_MOUSEMENU | 0x0005, mouseMsg.lParam);
}
else
{
PostMessageA(mTargetHwnd, WM_NCLBUTTONUP, HTMENU, mouseMsg.lParam);
}
}
Help!!!
Are there any specialist on Windows system can give me some hints please? Thanks sincerely!

WIN32 - Create a WebView2 synchronously does not work - I don't get a white rectangle for my integrated web browser

In brief, I explain you my problem. In my application, I've a button to load the browser. When I click on the button, it opens and creates well the webBrowser (white rectangle).
BUT when I try to create the web Browser when I open a window (who contains different components : buttons, edittext,...) of my application through the Event WM_SHOWWINDOW, I don't see my web browser EXCEPTED IF I put in comment all the loop "while" in the constructor EdgeBrowser.
Why ? Can you give me a solution please ? It would be friendly.
I created a class EdgeBrowser with a constructor who receives the handle of my WIN32 component (HWND component). In my constructor, I do something like that :
EdgeBrowser::EdgeBrowser(HWND hwnd)
{
_hwnd = hwnd;
EdgeBrowser::_beginAsyncOperation = true;
this->CreateWebView();
while (EdgeBrowser::_beginAsyncOperation)
{
Sleep(10);
MSG msg;
for (int nmsg = 0; nmsg < 50; ++nmsg)
{
int rc = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (rc == 0)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
And in a part of my "CreateWebView" function with the different listeners :
void EdgeBrowser::CreateWebView
{
// other code
HRESULT hr = CreateCoreWebView2EnvironmentWithOptions(nullptr, userDataDir.c_str(),nullptr,Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(this,&EdgeBrowser::OnCreateCoreWebView2EnvironmentCompletedHandler).Get());
}
HRESULT EdgeBrowser::OnEnvironmentReadyCompletedHandler(HRESULT result, ICoreWebView2Environment* env)
{
HRESULT createBrowserControlsResult = m_uiEnv->CreateCoreWebView2Controller(this->_thisHandler, Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(this,&EdgeBrowser::OnCreateCoreWebView2ControllerCompletedHandler).Get());
HRESULT createBrowserOptionsResult = m_uiEnv->CreateCoreWebView2Controller(this->_thisHandler,Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( this,&EdgeBrowser::OnCreateCoreWebView2ControllerOptionsCompletedHandler).Get());
}
HRESULT EdgeBrowser::OnCreateCoreWebView2ControllerOptionsCompletedHandler(HRESULT result, ICoreWebView2Controller* host)
{
m_optionsController = host;
HRESULT getOptWebViewResult = m_optionsController->get_CoreWebView2(&m_optionsWebView);
//other code
EdgeBrowser::_beginAsyncOperation = false;
return S_OK;
}
The WebView2 control requires a message loop to run on the UI thread on which it is created (see this page for more info on WebView2 threading). You can see the WebView2APISample sample app as a sample C++ Win32 HWND based application.

Detecting CTRL+Wheel with CHtmlView

I know how to set the zoom factor for a CHtmlView:
HRESULT CChristianLifeMinistryHtmlView::SetZoomFactor(long iZoom, bool bRefreshBrowser /*true*/)
{
HRESULT hr = S_OK;
VARIANT vZoom;
m_lZoomFactor = iZoom;
if (bRefreshBrowser)
{
vZoom.vt = VT_I4;
vZoom.lVal = iZoom;
hr = ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &vZoom, nullptr);
}
return hr;
}
HRESULT CChristianLifeMinistryHtmlView::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
HRESULT hr;
ASSERT(m_pBrowserApp != NULL);
hr = m_pBrowserApp->ExecWB(cmdID, cmdexecopt, pvaIn, pvaOut);
return hr;
}
I have just introduced a CStatusBar into the main editor that encompasses this view and one of my users has stated that they use CTRL + Wheel to change the zoom factor.
I have my menu structure with associated hotkeys that the user can use to change the zoom, thus my status bar pane is updated to the right value they selected.
But when they use the CTRL + Wheel to change the zoom my application is not detecting this. So they zoom in or out to a scale and my status bar pane is staying at the original zoom factor.
With MFC and the CHtmlView web browser control how to I detect when they have changed the zoom using CTRL + Wheel so I can update my status pane?
If this is CHtmlView with Doc/View structure, use PreTranslateMessage to catch messages.
Documentation for WM_MOUSEWHEEL suggests several macros for finding the state of virtual keys and wheel movement:
BOOL CMyHtmlView::PreTranslateMessage(MSG* pmsg)
{
if(pmsg->message == WM_MOUSEWHEEL)
{
int fwKeys = GET_KEYSTATE_WPARAM(pmsg->wParam);
int zDelta = GET_WHEEL_DELTA_WPARAM(pmsg->wParam);
if (fwKeys & MK_CONTROL)
{
//mousewheel + control key is down
TRACE("%d %d\n", zDelta, zDelta / WHEEL_DELTA);
//update statusbar, or return TRUE to handle this manually
}
}
return CHtmlView::PreTranslateMessage(pmsg);
}
CHtmlView also has its own CHtmlView::ExecWB method to set and get the zoom value etc.
CHtmlView::OnUpdateUI should also send notification for the change.
But the browser may not send a signal at the right time. Just make a timer to wait 1 second after detecting CTRL+WHEEL. Example:
BEGIN_MESSAGE_MAP(CMyHtmlView, CHtmlView)
ON_WM_TIMER()
END_MESSAGE_MAP()
const int ID_TIMER_ZOOM = 1;
BOOL CMyHtmlView::PreTranslateMessage(MSG* pmsg)
{
if(pmsg->message == WM_MOUSEWHEEL)
if (GET_KEYSTATE_WPARAM(pmsg->wParam) & MK_CONTROL)
SetTimer(ID_TIMER_ZOOM, 1000, NULL); //start timer for detecting zoom
return CHtmlView::PreTranslateMessage(pmsg);
}
void CMyHtmlView::OnTimer(UINT_PTR timer_id)
{
if(timer_id == ID_TIMER_ZOOM)
{
//get the zoom value
VARIANT vZoom;
vZoom.vt = VT_I4;
vZoom.lVal = 0;
ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, &vZoom);
TRACE("zoom %d\n", vZoom.lVal);
//kill the timer
KillTimer(timer_id);
}
}

C++ Win32 Listen for global keybinds

I am trying to implement global hotkeys on Windows in my C++/Qt application. I used RegisterHotKey, which surprisingly worked and I can see that pressing the combination triggers my event, but since I did not know any other way, I just used a loop, which now blocks my windows and stops it from ever showing up.
You can find my code below. How do I listen for this combination? There certainly has to be another way.
void set_win32_keys(MainWindow *mwin) {
HWND main_hwnd = (HWND)mwin->winId();
RegisterHotKey(main_hwnd, 2, MOD_CONTROL | MOD_SHIFT, 0x32 /*2 key*/);
MSG *msg;
msg = new MSG();
BOOL b_ret;
while ((b_ret = GetMessage(msg, main_hwnd, 0, 0)) != 0) {
if (b_ret == -1) {
qDebug() << "Error";
} else {
if (msg->message == WM_HOTKEY) {
mwin->new_screenshot();
qDebug() << msg;
}
}
}
}
Shameless plug: I have written a library for Qt that provides global hotkeys in a cross-platform manner - and allows the usage of for example QKeySequence to create the hotkey. It allows you to use a QKeySequenceEdit to let the user enter his own shortcut:
https://github.com/Skycoder42/QHotkey
Example:
//MainWindow constructor:
QHotkey *hotkey = new QHotkey(Qt::Key_2, Qt::ControlModifier | Qt::ShiftModifier, true, this);
connect(hotkey, &QHotkey::activated, this, &MainWindow::new_screenshot);
And that's it! Hope it helps
How can I listen to the system hot key bound to the app main window?
Many system events can be caught at main window native event handler. And the original author post actually binds to main window. The below should process the requested message:
class MainWindow : public QMainWindow
{
// ... snip ...
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
// ... snip ...
};
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* pMsg = reinterpret_cast<MSG*>(message);
if (pMsg->message == WM_HOTKEY)
{
// process pMsg->wParam / lParam etc.
// the intended action
this->new_screenshot();
}
// call the parent, could be QWidget::nativeEvent
return QMainWidow::nativeEvent(eventType, message, result);
}
Because of assumption that mwin has QMainWindow*:
HWND main_hwnd = (HWND)mwin->winId();
RegisterHotKey(main_hwnd, 2, MOD_CONTROL | MOD_SHIFT, 0x32 /*2 key*/);

How to Get Tooltip of a Window From Window Handle? [duplicate]

I'm looking for a way to get the tooltip control (if any) which is associated with a given HWND. The text of the tooltip control would be sufficient, too. The closest thing I found is the TTM_GETTEXT message, but it's meant to be sent to the tooltip control itself instead of the tool it's associated with. I don't have a handle to the tooltip control though. Does anybody know how to do this?
All this is done using plain Windows API in C++.
There doesn't seem to be a specific message to get the tip or its text from the control, but this is how MFC's CWnd class implements OnToolHitTest(), which you should be able to adapt to Win32:
INT_PTR SomeFunction(HWND hWndChild, TOOLINFO *pTI)
{
if (hWndChild != NULL) // Your HWND being tested
{
// return positive hit if control ID isn't -1
INT_PTR nHit = _AfxGetDlgCtrlID(hWndChild);
// Replace with GetDlgCtrlID().
// hits against child windows always center the tip
if (pTI != NULL && pTI->cbSize >= sizeof(AFX_OLDTOOLINFO))
{
// setup the TOOLINFO structure
pTI->hwnd = m_hWnd;
pTI->uId = (UINT_PTR)hWndChild;
pTI->uFlags |= TTF_IDISHWND;
pTI->lpszText = LPSTR_TEXTCALLBACK;
// set TTF_NOTBUTTON and TTF_CENTERTIP if it isn't a button
if (!(::SendMessage(hWndChild, WM_GETDLGCODE, 0, 0) & DLGC_BUTTON))
pTI->uFlags |= TTF_NOTBUTTON|TTF_CENTERTIP;
}
return nHit;
}
return -1; // not found
}
Hopefully this will be useful.
To get tooltip text from some control you could use TTN_NEEDTEXT message. It was designed to be used by the ToolTip control, but I cannot see any reason why you could not send it from other place.
You could enumerate the windows looking for a tooltip control that has a parent of the required window. You'll need to supply the window together with the tool id (normally from GetDlgCtrlID)...:
HWND hToolTipWnd = NULL;
BOOL GetToolTipText(HWND hWnd, UINT nId, std::wstring& strTooltip)
{
hToolTipWnd = NULL;
EnumWindows(FindToolTip, (LPARAM)hWnd);
if (hToolTipWnd == NULL)
return FALSE;
WCHAR szToolText[256];
TOOLINFO ti;
ti.cbSize = sizeof(ti);
ti.hwnd = hWnd;
ti.uId = nId;
ti.lpszText = szToolText;
SendMessage(hToolTipWnd, TTM_GETTEXT, 256, (LPARAM)&ti);
strTooltip = szToolText;
return TRUE;
}
BOOL CALLBACK FindToolTip(HWND hWnd, LPARAM lParam)
{
WCHAR szClassName[256];
if (GetClassName(hWnd, szClassName, 256) == 0)
return TRUE;
if (wcscmp(szClassName, L"tooltips_class32") != 0)
return TRUE;
if (GetParent(hWnd) != (HWND)lParam)
return TRUE;
hToolTipWnd = hWnd;
return FALSE;
}
I don't know if the window whose tooltip you want to retrieve is a child of a window you have created.
If this is the case, you can handle the NM_TOOLTIPSCREATED notification, which is sent by a child window to its parent when it creates a tooltip (or should be sent: it is true for common controls but I don't know for other kinds of windows). This notification includes a handle to the tooltip window.