I am using win32 API to develop an Application.I am using WM_LBUTTONDOWN message to handle two operation .
If a click on button X I want to perform operation A.
a)If a double click occur on button X I want to perform operation C as well
that is operation A
followed by operation C.
But while implementing I can either perform operation Aor operation C.
case WM_LBUTTONDOWN:
{
overallClicks++;
left1.x = LOWORD(lParam);
left1.y = HIWORD(lParam);
wsprintf(waCoord, _T("my coordinates are (%i,%i)"), left1.x, left1.y);
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
if (fun()) {
//do something
}
else {
MessageBox(NULL, _T("yo"), _T("yo"), MB_OK);
}
return 0;
// dwLastClickTime= GetMessageTime();
//SetTimer(hWnd,0,GetDoubleClickTime(),0);
//break;
// handleDoubleClicks(hWnd, message, wParam, lParam, ptLastClickPos, dwLastClickTime);
}
case WM_TIMER:
{
HandleTimer(hWnd, message, wParam, lParam);
}
LRESULT HandleTimer(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
BOOL i = KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
// wchar_t* ptr = ;
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
else if (click_count == 2)
{
MessageBox(hWnd, waCoord, TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else if (click_count == 3)
{
MessageBox(hWnd, waCoord, TEXT("I appear when triple clicked"), MB_OKCANCEL);
}
else if (click_count > 3) {
MessageBox(hWnd, waCoord, TEXT("I appear when rage clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
I would like elaborate for example I am double clicking on disabled button I want to show pop up that I have double clicked as well as that button is disabled.
With the help of an answer from your previous case.
Because your code logic uses if...else... conditional statements. The way I can think of is to add an additional timer in the case of double-click to complete the action when clicked.
void CALLBACK f(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
EnableWindow(hwndButton, 0);
}
...
LRESULT CALLBACK OwnerDrawButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), point.x, point.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
SetTimer(NULL, 0, 100, (TIMERPROC)&f);
}
else if (click_count == 2)
{
SetTimer(NULL, 0, 100, (TIMERPROC)&f);
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
break;
case WM_LBUTTONDOWN:
{
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
return 0;
}
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, &OwnerDrawButtonProc, 1);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
Remove the CS_DBLCLKS style when using the button control.
Updated:
Because the button is disabled, I'm sorry I didn't see this. In this way, the message of the parent window can only be used to determine whether the mouse coordinates are within the range of the button. If it is, double-click to perform operation C.
Only need to modify part of the code of the parent window:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static RECT rc;
static POINT pt = { 0 };
rc.left = 10;
rc.top = 10;
rc.right = 110;
rc.bottom = 110;
switch (message)
{
case WM_CREATE:
{
hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"OK", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON , // Styles
10, // x position
10, // y position
100, // Button width
100, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
DWORD class_style = GetClassLongPtr(hwndButton, GCL_STYLE);
SetClassLongPtr(hwndButton, GCL_STYLE, class_style & (~CS_DBLCLKS));
SetWindowSubclass(hwndButton, &OwnerDrawButtonProc, IDC_OWNERDRAWBUTTON, 0);
return TRUE;
}
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 2)
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
case WM_LBUTTONDOWN:
{
POINT p;
p.x = GET_X_LPARAM(lParam);
p.y = GET_Y_LPARAM(lParam);
if (PtInRect(&rc, p))
{
pt = p;
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
}
return 0;
}
...
Debug:
Related
I am having troubles painting my static text controls. I have done some reading on this matter, and I have also tried some codes, but none of them worked. The closest that I managed to get was until the text control detects my mouse hover event. For this, I use control subclassing. However, I don't know what I can do to paint the text controls upon mouse hover.
My questions are:
I am confused whether to place the code responsible for painting the text control either in WM_MOUSEMOVE or WM_MOUSEHOVER in the subclass. The reason is because in the WM_MOUSEMOVE, I set it so that when the rectangle area of the text control detects the cursor, painting should happen. At the same time, I feel weird because shouldn't that particular role already be done by WM_MOUSEHOVER?
I really need help on how I could highlight the text control when the mouse is hovered.
// global text control handler
HWND txtHwnd; //somewhere in the global area of codes
//class for mouse event tracking
class MouseTrackEvents
{
bool m_bMouseTracking;
public:
MouseTrackEvents() : m_bMouseTracking(false) {}
void OnMouseMove(HWND hwnd)
{
if (!m_bMouseTracking)
{
// Enable mouse tracking.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER;
tme.dwHoverTime = 100; //0.1s
TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}
void Reset(HWND hwnd)
{
m_bMouseTracking = false;
}
};
//subclass proc for text control
LRESULT CALLBACK OwnerTxtProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
//local mouse track object
MouseTrackEvents mouseTrack;
const int numOfMsg = 4;
int myMsgBox[numOfMsg]; //limit to only 4
HBRUSH hbrBkgndA = CreateSolidBrush(RGB(0, 255, 0));
//just want to print what wparam is..
int wmId, wmEvent;
wchar_t wParamHI[1000];
wchar_t wParamLO[1000];
//for painting
COLORREF hbrHighlight;
//HBRUSH hbrHighlight;
HDC txtHDC;
RECT txtRect;
POINT txtPt;
RECT txtRt;
switch (uMsg) {
case WM_CREATE: {
//testing purposes
myMsgBox[0] = MessageBox(nullptr, L"Yessir!", L":D", MB_OK | MB_ICONINFORMATION);
break;
}
case WM_MOUSEMOVE: {
mouseTrack.OnMouseMove(hWnd); //activate mouse tracking
GetWindowRect(hWnd, &txtRt); //see what value lies within
GetCursorPos(&txtPt);
if (PtInRect(&txtRt, txtPt)) {
//to check whether cursor is in text rect or not
MessageBox(nullptr, L"Okea..nice..!", L":D", MB_OK | MB_ICONINFORMATION);
//i dont know what to do here
//i was thinking that painting should be placed here...
//HBRUSH hbrBkgndEdit = CreateSolidBrush(RGB(100, 100, 255));
}
else {
//to check whether cursor is in text rect or not
MessageBox(nullptr, L"Oh noooo!", L":D", MB_OK | MB_ICONINFORMATION);
}
break;
}
case WM_MOUSEHOVER: {
//do something when txt ctrl is hovered
//to test whether wm_mousehover works, and the text control is mouse hovered
//myMsgBox[1] = MessageBox(nullptr, L"Yahooooo!", L":D", MB_OK | MB_ICONINFORMATION);
OutputDebugString(L"--------------This text control is being hovered---------------\n");
//testing painting when hovered
//plan is to send message to hChild to manage the painting since it is the parent window
//HDC theHDC = (HDC)wParam;
//SendMessage(hWnd, WM_CTLCOLORSTATIC, (WPARAM)theHDC, (LPARAM)txtHwnd);
//SendMessage(hWnd, WM_CTLCOLORSTATIC, (WPARAM)theHDC, lParam);
//for painting
//hbrHighlight = (COLORREF)(GetSysColor(COLOR_HIGHLIGHT));
//HDC hdcStatic = (HDC)wParam;
////SetTextColor(hdcStatic, RGB(0, 0, 0));
//SetBkColor(hdcStatic, hbrHighlight);
//for painting II
//HDC txtCtrlMe = (HDC)wParam;
//SetTextColor(txtCtrl, RGB(0, 0, 0));
//SetBkColor(txtCtrlMe, RGB(0, 255, 0));
//SendMessage(hChild, WM_CTLCOLORSTATIC, (WPARAM)txtCtrlMe, (LPARAM)txtHwnd);
//DeleteBrush(hbrBkgndA);
mouseTrack.Reset(hWnd);
//return (INT_PTR)hbrHighlight;
//mouseTrack.Reset(hWnd);
break;
//return TRUE;
}
//case WM_CTLCOLORSTATIC:
//{
// HDC txtCtrlMe = (HDC)wParam;
// //SetTextColor(txtCtrl, RGB(0, 0, 0));
// SetBkColor(txtCtrlMe, RGB(0, 255, 0));
// if (hbrBkgndA == NULL)
// {
// hbrBkgndA = CreateSolidBrush(RGB(255, 255, 255)); //eqivalent to delete brush objet
// }
// return (INT_PTR)hbrBkgndA;
// //break;
//}
//painting
/*
SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
SendMessage(hChild, WM_CTLCOLORSTATIC, (WPARAM)txtCtrlMe, (LPARAM)txtHwnd);
*/
//you can just ignore this, this is just for me to see whats inside wParam of the subclass
case WM_LBUTTONDOWN: {
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
int HI = swprintf_s(wParamHI, 1000, L"wParamHI: %d", wmEvent);
MessageBox(nullptr, wParamHI, L":D", MB_OK | MB_ICONINFORMATION);
int LO = swprintf_s(wParamLO, 1000, L"wParamLO: %d", wmId);
MessageBox(nullptr, wParamLO, L":D", MB_OK | MB_ICONINFORMATION);
break;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
//child window proc, which contains the static text control
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
//...some other codes...
txtHwnd = CreateWindow(L"Static", L"Hello World!", WS_VISIBLE | WS_CHILD | SS_NOTIFY, 100, 100, 120, 15, hChild, (HMENU)testingTxtID, nullptr, nullptr);
//control subclassing
//a.k.a attaching subclass proc to the static text control
SetWindowSubclass(txtHwnd, OwnerTxtProc, 0, 0);
//...some other codes...
default: {
return DefWindowProc(hChild, message, wParam, lParam);
}
return 0;
}
Please ignore the codes I commented out in WM_MOUSEHOVER and also WM_CTLCOLORSTATIC inside OwnerTxtProc(...). They are just codes that I used to try to paint the text control, which didn't work.
All painting operations for your control should be only inside of a WM_CTLCOLORSTATIC handler, or even a WM_PAINT handler.
To trigger a repaint of the control, simply invalidate the control's client area using InvalidateRect().
If you want to change the painting conditions, store the relevant information in variables that the painting code uses, and then update those variables before invalidating the control.
Try something like this:
HWND txtHwnd;
bool bMouseTracking = false;
COLORREF bkgndColor = ...; // whatever you want...
COLORREF txtColor = ...; // whatever you want...
HBRUSH hbrBkgnd = nullptr;
const UINT APP_CTLCOLORSTATIC = WM_APP + 1;
LRESULT CALLBACK StaticTxtProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
switch (uMsg) {
case WM_NCDESTROY: {
RemoveWindowSubclass(hWnd, StaticTxtProc, uIdSubclass);
if (hbrBkgnd) {
DeleteBrush(hbrBkgnd);
hbrBkgnd = NULL;
}
bMouseTracking = false;
break;
}
case WM_MOUSEMOVE: {
if (!bMouseTracking) {
TRACKMOUSEEVENT tme = {};
tme.cbSize = sizeof(tme);
tme.hwndTrack = hWnd;
tme.dwFlags = TME_HOVER;
tme.dwHoverTime = 100; //0.1s
bMouseTracking = TrackMouseEvent(&tme);
}
RECT txtRt;
GetWindowRect(hWnd, &txtRt);
POINT txtPt;
GetCursorPos(&txtPt);
if (PtInRect(&txtRt, txtPt)) {
bkgndColor = ...; // whatever you want...
txtColor = ...; // whatever you want...
InvalidateRect(hWnd, NULL, TRUE);
}
break;
}
case WM_MOUSEHOVER: {
mMouseTracking = false;
bkgndColor = ...; // whatever you want...
txtColor = ...; // whatever you want...
InvalidateRect(hWnd, NULL, TRUE);
break;
}
case APP_CTLCOLORSTATIC: {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, txtColor);
SetBkColor(hdc, bkgndColor);
if (hbrBkgnd)
DeleteBrush(hbrBkgnd);
hbrBkgnd = CreateSolidBrush(bkgndColor);
return reinterpret_cast<LRESULT>(bkgndColor);
}
case WM_LBUTTONDOWN: {
// ...
break;
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE: {
bkgndColor = ...; // whatever you want...
txtColor = ...; // whatever you want...
txtHwnd = CreateWindow(L"Static", L"Hello World!", WS_VISIBLE | WS_CHILD | SS_NOTIFY, 100, 100, 120, 15, hChild, (HMENU)testingTxtID, nullptr, nullptr);
SetWindowSubclass(txtHwnd, StaticTxtProc, 0, 0);
break;
}
case WM_CTLCOLORSTATIC: {
return SendMessage(reinterpret_cast<HWND>(lParam), APP_CTLCOLORSTATIC, wParam, 0);
}
//...some other codes...
default: {
return DefWindowProc(hChild, message, wParam, lParam);
}
}
return 0;
}
(Posting solution on behalf of the question author to move it to the answer space).
I managed to deal with my problem on this matter.
//global variable(s)
COLORREF bkgndColor;
COLORREF txtColor;
HBRUSH hbrBkgnd = nullptr;
const UINT APP_CTLCOLORSTATIC = WM_APP + 1;
//class for mouse event
class MouseTrackEvents
{
bool m_bMouseTracking;
public:
MouseTrackEvents() : m_bMouseTracking(false) {}
void OnMouseMove(HWND hwnd)
{
if (!m_bMouseTracking)
{
// Enable mouse tracking.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = 10; //1ms
TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}
void Reset(HWND hwnd)
{
m_bMouseTracking = false;
}
};
//proc for static text contorl subclass
LRESULT CALLBACK OwnerTxtProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
//local mouse track variable
MouseTrackEvents mouseTrack;
RECT txtRt;
GetWindowRect(hWnd, &txtRt);
POINT txtPt;
GetCursorPos(&txtPt);
switch (uMsg) {
//...some other codes...
case WM_NCDESTROY: {
RemoveWindowSubclass(hWnd, OwnerTxtProc, uIdSubclass);
if (hbrBkgnd) {
DeleteBrush(hbrBkgnd);
hbrBkgnd = NULL;
}
mouseTrack.Reset(hWnd);
break;
}
case WM_MOUSEMOVE: {
mouseTrack.OnMouseMove(hWnd); //activate mouse tracking
break;
}
case WM_MOUSEHOVER: {
if (PtInRect(&txtRt, txtPt)) {
OutputDebugString(L"--------------This text control is being hovered---------------\n");
bkgndColor = RGB(0, 0, 200); // blue
txtColor = RGB(200, 0, 0); // red
InvalidateRect(hWnd, NULL, FALSE);
}
else {
OutputDebugString(L"--------------This text control is being left---------------\n");
bkgndColor = RGB(100, 0, 0); // red bg
txtColor = RGB(0, 100, 0); // green txt
InvalidateRect(hWnd, NULL, FALSE);
}
mouseTrack.Reset(hWnd);
break;
}
case WM_MOUSELEAVE: {
if (!(PtInRect(&txtRt, txtPt))) {
OutputDebugString(L"--------------This text control is being hovered---------------\n");
bkgndColor = RGB(100, 0, 0); // red bg
txtColor = RGB(0, 100, 0); // green txt
InvalidateRect(hWnd, NULL, FALSE);
}
mouseTrack.Reset(hWnd);
break;
}
case APP_CTLCOLORSTATIC: {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, txtColor);
SetBkColor(hdc, bkgndColor);
if (hbrBkgnd) {
DeleteBrush(hbrBkgnd);
}
hbrBkgnd = CreateSolidBrush(bkgndColor);
//return reinterpret_cast<LRESULT&>(bkgndColor); //--> error --> so i added '&'
return (LRESULT)hbrBkgnd;
}
//...some other codes...
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
//parent of static text control
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//...some other codes...
switch (message)
{
case WM_CTLCOLORSTATIC:
{
return SendMessage(reinterpret_cast<HWND>(lParam), APP_CTLCOLORSTATIC, wParam, 0);
}
case WM_CREATE: //put all sorts of stuff when the context menu is called
{
//font to be set to
hFont = CreateFont(17, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Segoe UI"));
//set font of the textCtrl
//doesnt work if handler target = hChild
for (int i = 0; i < textCtrlSize; i++) {
SendMessage(textCtrl[i], WM_SETFONT, (WPARAM)hFont, TRUE);
}
bkgndColor = RGB(100, 0, 0); // red bg
txtColor = RGB(0, 100, 0); // green txt
txtHwnd = CreateWindow(L"Static", L"Hello World!", WS_VISIBLE | WS_CHILD | SS_NOTIFY, 100, 100, 120, 30, hChild, (HMENU)testingTxtID, nullptr, nullptr);
SetWindowSubclass(txtHwnd, OwnerTxtProc, 0, 0);
break;
}
//...some other codes...
default:
return DefWindowProc(hChild, message, wParam, lParam);
}
return 0;
}
LRESULT handleDoubleClicks(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, POINT ptLastClickPos, DWORD dwLastClickTime)
{
DWORD dwClickTime = GetMessageTime();
POINT ptClickPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
switch(message)
{
case WM_LBUTTONDOWN:
if (dwLastClickTime + GetDoubleClickTime() > dwClickTime
&& abs(ptLastClickPos.x - ptClickPos.x) < GetSystemMetrics(SM_CXDOUBLECLK)
&& abs(ptLastClickPos.y - ptClickPos.y) < GetSystemMetrics(SM_CYDOUBLECLK))
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else
{
dwLastClickTime = dwClickTime;
ptLastClickPos = ptClickPos;
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), ptLastClickPos.x, ptLastClickPos.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
This is function i have made to handle double click:
This function is called when windows recieve WM_LBUTTONDOWN it will take the time of the message and coordinate of the click and will transfer it to the function here i want the fuction to recieve another message WM_LBUTTONDOWN and determine the time of the message and compare with the previous click time and the co ordinates to identify if it is a double click.
But this is not working .May be I am Wrong with the approach I am newbie Pls help me to solve this problem.
case WM_LBUTTONDOWN:
{
dwLastClickTime= GetMessageTime();
// SetTimer(hWnd,0,GetDoubleClickTime(),0);
ptLastClickPos.x = LOWORD(lParam);
ptLastClickPos.y = HIWORD(lParam);
handleDoubleClicks(hWnd, message, wParam, lParam, ptLastClickPos, dwLastClickTime);
}
You could use SetTimer, after one click, not immediately judge it as a click, but start the timer, check whether there is another click within the timer range, if there is, it is judged as double-click, if not, and the previous time is determined as a single click.
#define TIMER_ID 10
static int click_count = 0;
static POINT point = { 0 };
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), point.x, point.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
else if(click_count == 2)
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else if (click_count == 3)
{
MessageBox(hWnd, TEXT("Triple click"), TEXT("I appear when triple clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
break;
case WM_LBUTTONDOWN:
{
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
And make sure your window doesn't have CS_DBLCLKS style. Otherwise, the second WM_LBUTTONDOWN message that would normally be generated becomes a WM_LBUTTONDBLCLK message, according to the document: Double Clicks
So basically I have this program that makes a transparent overlay for a game so I can make a kill counter. However, when I click on the game with the overlay on, nothing happens. I managed to make it so when you click on it then it sends a message to the game telling it to shoot, however, when I tried the same for moving my characters head it was just laggy and snappy. When I would move my head quickly, my cursor would also fly out of the game window. How can I fix this so when I play the game it would be like its not even there.
I have tried sending the message and setting the window active AND using setcapture. However, none of these worked. I have tried looking at other places but they didn't work either.
/* This is my while(true) loop: */
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg); // translates virtual-key messages into character messages
DispatchMessage(&msg); // dispatches a message to WindowProc
}
if (gameProcId == 0)
{
gameProcId = GetProcId(L"ac_client.exe");
}
if (gameWnd == NULL)
{
gameWnd = FindWindow(NULL, L"AssaultCube");
}
if ((gameProc == NULL) && (gameProcId != 0))
{
gameProc = OpenProcess(PROCESS_VM_READ, false, gameProcId); // opens an existing local process and returns a handle to it
}
if (gameProc != NULL)
{
if ((!init_ok) || ((loops % 20) == 0))
{
RECT client_rect;
#pragma warning (suppress: 6387)
GetClientRect(gameWnd, &client_rect); // gets a windows coordinates, upper-left corner is (0,0)
w_res.X = client_rect.right;
w_res.Y = client_rect.bottom;
RECT bounding_rect;
#pragma warning (suppress: 6387)
GetWindowRect(gameWnd, &bounding_rect); // gets dimensions of a window
if (!init_ok)
{
if ((w_pos.X != bounding_rect.left) || (w_pos.Y != bounding_rect.top))
{
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top,
client_rect.right, client_rect.bottom, false);
w_pos.X = bounding_rect.left;
w_pos.Y = bounding_rect.top;
}
//SetCursorPos(w_pos.X * 4, w_pos.Y * 4);
//ClipCursor(&gameRect);
}
else
{
if ((bounding_rect.left == 0) && (bounding_rect.top == 0))
{
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top, // changes both the position and dimension of a window
client_rect.right, client_rect.bottom, false);
}
MoveWindow(hWnd, bounding_rect.left, bounding_rect.top, client_rect.right,
client_rect.bottom, false);
}
init_ok = true;
}
}
if (loops % 10 == 0)
{
if (FindWindow(NULL, L"AssaultCube") == NULL)
{
SendMessage(hWnd, WM_CLOSE, NULL, NULL); // calls WindowProc() and sends the message to a window
}
}
loops++;
if (loops > 100) loops = 0;
Render();
}
}
/* This is my WindowProc() function: */
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}break;
case WM_LBUTTONDOWN:
{
PostMessage(gameWnd, message, wParam, lParam);
return 0;
}
case WM_MOUSEMOVE:
{
SendMessage(gameWnd, message, wParam, lParam);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
You didn't post enough code to attempt to solve this problem, we don't see your call to CreateWindowEx().
Here is a working solution for a win32 overlay:
#include <iostream>
#include <windows.h>
using namespace std;
//global forward declerations
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void cleanUpObjects(HPEN pen);
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
RECT overlayWindowRect;
RECT gameWindowRect;
HWND gameWindowHandle;
gameWindowHandle = FindWindowA(0, "AssaultCube");
GetWindowRect(gameWindowHandle, &gameWindowRect);
WNDCLASSEX w;
w.cbSize = sizeof(WNDCLASSEX);
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.cbClsExtra = 0;
w.cbWndExtra = 0;
w.hInstance = hInstance;
w.hIcon = NULL;
w.hCursor = NULL;
w.hbrBackground = (HBRUSH)0;
w.lpszMenuName = NULL;
w.lpszClassName = "ClassName";
w.hIconSm = NULL;
if (!RegisterClassEx(&w))
{
MessageBox(NULL, "Could not Register Class", "Window Title", NULL);
return -1;
}
HWND hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT, "ClassName", "Window",
WS_CAPTION,
gameWindowRect.left, //x
gameWindowRect.top, // y
gameWindowRect.right - gameWindowRect.left, // width
gameWindowRect.bottom - gameWindowRect.top, // height
NULL, NULL,
hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, "Call to create window failed", "Win32 Guided tour", NULL);
return -1;
}
else
{
GetWindowRect(hWnd, &overlayWindowRect);
}
// Remove Borders around window
SetWindowLong(hWnd, GWL_STYLE, GetWindowLong(hWnd, GWL_STYLE) & ~(WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_BORDER));
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
// Make the Background Transparent
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 255, LWA_COLORKEY); // Replaces color white with transparancey
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
HDC myHDC = GetDC(hWnd);
// Drawing Stuff
HPEN myPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
HPEN originalPen;
originalPen = (HPEN)SelectObject(myHDC, myPen);
//main loop waits for messages
MSG msg;
while (true)
{
//peekmessage allows for program to do multiple things at once. faster than getmessage()
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// if msg is quit, quit
if (msg.message == WM_QUIT)
break;
}
else
{
Rectangle(myHDC, 200, 200, 300, 400);
ZeroMemory(&gameWindowRect, sizeof(gameWindowRect)); //clear out the struct
GetWindowRect(gameWindowHandle, &gameWindowRect); // retrieves the games xy and height width and stores in gamewindowrect
if (gameWindowRect.right != overlayWindowRect.right) // checks if the x coordinates are the same
{
ZeroMemory(&gameWindowRect, sizeof(gameWindowRect)); // clear out struct once again
GetWindowRect(gameWindowHandle, &gameWindowRect); // get the dimensions of the game window again
MoveWindow(hWnd, gameWindowRect.left, gameWindowRect.top, gameWindowRect.right - gameWindowRect.left, gameWindowRect.bottom - gameWindowRect.top, TRUE);
// moves window to specific spot
}
}
Sleep(5);
}
cleanUpObjects(myPen);
cleanUpObjects(originalPen);
return msg.wParam;
}
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
HDC hdc;
switch (uMsg)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
DestroyWindow(hWnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
return 0;
}
//cleans up objects
void cleanUpObjects(HPEN pen)
{
DeleteObject(pen);
}
I'm developing a Win32 application to capture video using Windows Media Foundation. I have to display Play/Pause/Stop bitmap image on video window with transparent. I have created a modeless dialog box and shown the transparent image on the dialog using below code.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmID;
switch (unMessage)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_BTN_VIDEOSTART:
InitModelessDialog();
break;
}
break;
}
return CallWindowProc ( g_lpfnWndProc, hWnd, unMessage, wParam, lParam );
}
void InitModelessDialog()
{
DIBSECTION ds;
DWORD dwFlag = MID_EXT_STYLES | MID_CLR_KEY | MID_ALPHA_VAL;
g_hWndVideoPause = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_DLG_VIDEORECORD), g_hwndPreview, DlgProc_VideoPause);
g_hPauseBmp = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP_PAUSE), IMAGE_BITMAP, 0, 0, 0);
GetObject(g_hPauseBmp, sizeof(ds), &ds);
g_hPauseDC = CreateCompatibleDC(NULL);
SelectObject(g_hPauseDC, g_hPauseBmp);
if(dwFlag & MID_EXT_STYLES)
SetWindowLong(g_hWndVideoPause, GWL_EXSTYLE, GetWindowLong(g_hWndVideoPause, GWL_EXSTYLE) | (WS_EX_LAYERED | WS_EX_TRANSPARENT));
if(dwFlag & (MID_CLR_KEY | MID_ALPHA_VAL))
{
DWORD dwTemp = 0;
if(dwFlag & MID_ALPHA_VAL)
dwTemp = LWA_ALPHA;
if(dwFlag & MID_CLR_KEY)
dwTemp |= LWA_COLORKEY;
SetLayeredWindowAttributes(g_hWndVideoPause, UI_COLOR_KEY, (255 * UI_TRANSPARENCY_PERCENT) / 100, dwTemp);
}
SetParent(g_hWndVideoPause,g_hwndPreview);
dlgWidth = ds.dsBm.bmWidth;
dlgHeight = ds.dsBm.bmHeight;
SetWindowPos(g_hWndVideoPause, HWND_TOP, 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, SWP_SHOWWINDOW | SWP_NOMOVE);
HDC hDlgDC = GetDC(g_hWndVideoPause);
StretchBlt(hDlgDC, 0, 0, dlgWidth, dlgHeight, g_hPauseDC, 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, SRCCOPY);
ReleaseDC(g_hWndVideoPause, hDlgDC);
if(g_hPauseDC)
{
DeleteDC(g_hPauseDC);
g_hPauseDC = NULL;
}
if(g_hPauseBmp)
{
DeleteObject(g_hPauseBmp);
g_hPauseBmp = NULL;
}
}
INT_PTR CALLBACK DlgProc_VideoPause(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
PAINTSTRUCT ps;
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_PAINT:
{
HDC hDC = GetDC(hDlg);
if(g_hPauseDC)
{
StretchBlt(hDC, 0, 0, dlgWidth, dlgHeight, g_hPauseDC, 0, 0, dlgWidth, dlgHeight, SRCCOPY);
}
ReleaseDC(hDlg, hDC);
}
break;
case WM_ERASEBKGND:
{
return 1;
}
break;
case WM_LBUTTONDOWN:
OutputDebugString(L"DlgProc_VideoPause WM_LBUTTONDOWN pressed\r\n");
break;
case WM_KEYDOWN:
OutputDebugString(L"DlgProc_VideoPause WM_KEYDOWN pressed\r\n");
break;
}
return (INT_PTR)FALSE;
}
When clicking on the drawn image, WM_KEYDOWN event is going to parent window. I wanna receive the WM_LBUTTONDOWN and WM_KEYDOWN event in my dialog proc window.What I have to do to receive this notification in my dialog proc?
I didn't create my dialog as Child window since I couldn't apply transparent for my child dialog.So only I'm creating a modeless dialog box.
Am I missing anything here?Please help me to solve this issue.
Thanks in advance.
How do I change the text color from an edit box on button push? (Win32/C++).
I know how to change the text font (i.e. to use in WM_COMMAND, SendMessage() with
WM_SETFONT).
On changing text color I think that I need an interaction betweenWM_COMMAND, WM_CTLCOLOREDIT, and SendMessage() but don't know with what kind of parameter .
Thank you.
I've figured how to do this on single button.
One more question please. If I use the code above for 3 different buttons, it doesn't behave as expected . There is a snippet :
case IDC_BUTTON3:
{
textFlagRed = textFlagRed;
textFlagBlue = !textFlagBlue;
textFlagGreen = !textFlagGreen;
InvalidateRect(textArea2, NULL, TRUE);
break;
}
case IDC_BUTTON4:
{
textFlagGreen = textFlagGreen;
textFlagBlue = !textFlagBlue;
textFlagRed = !textFlagRed;
InvalidateRect(textArea2, NULL, TRUE);
break;
}
case IDC_BUTTON5:
{
textFlagBlue = textFlagBlue;
textFlagRed = !textFlagRed;
textFlagGreen = !textFlagGreen;
InvalidateRect(textArea2, NULL, TRUE);
break;
}
and in WM_CTLCOLORSTATIC
if (textFlagRed && (HWND)lParam == textArea2)
{
HBRUSH hbr = (HBRUSH) DefWindowProc(hwnd, message, wParam, lParam);
SetTextColor((HDC) wParam, RGB(255, 0, 0));
return (BOOL) hbr;
}
else if (textFlagBlue && (HWND)lParam == textArea2)
{
HBRUSH hbr = (HBRUSH) DefWindowProc(hwnd, message, wParam, lParam);
SetTextColor((HDC) wParam, RGB(0, 0, 255));
return (BOOL) hbr;
}
else if (textFlagGreen && (HWND)lParam == textArea2)
{
HBRUSH hbr = (HBRUSH) DefWindowProc(hwnd, message, wParam, lParam);
SetTextColor((HDC) wParam, RGB(0, 255, 0));
return (BOOL) hbr;
}
break;
Always is the blue color.
You need to
a) a global boolean to indicate if the colour needs to be chaanged (say bEditRed)
b) on button push: set/toggle bEditRed and invalidate the edit box InvalidateRect(hWndEdit, NULL, TRUE)
c) handle the `WM_CTLCOLOREDIT' message in your dialog proc:
case WM_CTLCOLOREDIT:
{ if (bEditRed && (HWND)lParam == hWndEdit)
{ HBRUSH hbr = (HBRUSH) DefWindowProc(hDlg, iMessage, wParam, lParam);
SetTextColor((HDC) wParam, RGB(255, 0, 0));
return (BOOL) hbr;
}
return FALSE;
}
An alternative to Edward's answer is to use
RedrawWindow(windowHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
instead of
InvalidateRect(windowHandle, NULL, TRUE)
The former will immediately redraw your window, while the latter will not redraw it until the main window is available again.