case WM_NCHITTEST: {
LRESULT hit = DefWindowProc( hWnd, uMsg, wParam, lParam );
if ( hit == HTCLIENT ) {
hit = HTCAPTION;
SendNotifyMessageA( hWnd, WM_MOUSEMOVE, NULL, MAKELPARAM( LOWORD(lParam), HIWORD(lParam) ) );
pts.x = pts.y = 0;
ClientToScreen( hWnd, &pts );
SendNotifyMessageA( hWnd, WM_EXITSIZEMOVE, NULL,NULL );
return hit;
} } break;
case WM_NCLBUTTONDOWN: { LMB_Dyn[h2] = true; } break;
I'm using this code while I try to move a window by clicking in the client area (anywhere in window). This works fine.
But I have problem correctly receiving the state of the mouse left button and while this code kind of works the problem is that when I do a simple click instead of a "click and move" the LMB_Dyn variable (mouse left button) has some delay (does not immediately get notified that I pressed the mouse button.
How to correctly get the state of the mouse left button while using WM_NCHITTEST?
Mistake: } } break; should read } return hit; }
However, there's something more radical going on here. WM_NCHITTEST is not meant to be used like that and is allowed to be called with coordinates other than the current mouse position. This means your SendNotifyMessageA can send garbage.
I see you have a handler for WM_NCLBUTTONDOWN. Maybe that's all you need. Or, if you're trying to make the window draggable by anywhere on it, that should be like so:
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc( hWnd, uMsg, wParam, lParam );
if ( hit == HTCLIENT ) {
return HTCAPTION;
}
return hit;
}
The documentation for WM_NCLBUTTONDOWN and WM_NCLBUTTONUP says they fire immediately. It's really easy to forget your InvalidateRect call and so not have your screen redraw for you so it appears slow.
Related
I have a call to a dialog box that comes up ok. But now I want to load an .png image onto the dialog box screen at design time.
I cannot seem to get it all together, and I do not have a solid understanding of how to do all this. Any help, sure be helpful.
Somewhere I read that I could move a copy of the png file onto the dialog box screen, all that appeared, when I did, was a large box with a little flower in the middle appeared.
Below is a copy of my dialog box function and function call. All I want to do is just add a png image file onto the dialog screen and have it be shown; at design time and also have it during run time. Nothing fancy, but right to the point.
INT_PTR CALLBACK DialogXProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDOK:
//// just falls thru...
case IDCANCEL:
EndDialog(hwnd, LOWORD(wParam));
}
return 1;
}
case WM_INITDIALOG: {
SendMessage(hwnd, WM_SETICON, ICON_SMALL,
reinterpret_cast<LPARAM>(LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED)));
///ensure focus rectangle is properly draw around control with focus
PostMessage(hwnd, WM_KEYDOWN, 0, 0);
return TRUE;
}
case WM_CLOSE:
break;
default:
return FALSE;
}
}
INT_PTR returnval = DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOGKEPT), 0,
(DLGPROC)DialogXProcedure);
Basically, I want to write a program that shows in a small window the color of the pixel currently pointed by the mouse cursor.
Of course, I could poll the mouse cursor position once in a while, but I would like to opt to a mechanism that calls my code when the mouse cursor has moved, regardless whether it's pointing the current window or not.
Is there some WinAPI trickery that could achieve that functionality?
After some search, I found this:
HHOOK mouseHook =
SetWindowsHookExA(
WH_MOUSE_LL,
LowLevelMouseProc,
hInstance,
0);
...
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (wParam == WM_MOUSEMOVE) {
// Notify me.
}
return 0;
}
I am trying to create a window with behavior similar to cmd.exe, specifically whereby I don't want to support maximizing the window, since I only show fully visible lines of text (vertically). I have come up with two solutions so far:
Solution 1:
case WM_SYSCOMMAND:
if (wParam == SC_MAXIMIZE) {
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
break;
Solution 2:
case WM_SIZE:
if (wParam == SIZE_MAXIMIZED) {
SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
return 0;
}
break;
Unfortunately, the former is only effective if the user explicitly clicks the maximize button in the title bar, or in a context menu. It won't block it if the user simply double clicks the title bar for example.
The problem with the latter solution, for me, is that it causes scrollbars to disappear until you resize the window manually (by dragging the sides). Also, you can sometimes see the window flash before the window size is restored (I did try disabling redrawing before sending WM_SYSCOMMAND/SC_RESTORE, but unfortunately it did not help much).
Is there a better solution that I'm missing?
case WM_SYSCOMMAND:
UINT SysCommandCode = wParam & 0xFFF0;
if (SysCommandCode == SC_MAXIMIZE) {
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
break;
Also it is recommended to remove WS_MAXIMIZEBOX from the windows style (when creating).
As the title says, I would like to move the window only when the user will drag it from a portion of the client area. This will be an imitation of the normal caption bar movement and it's because my form is custom and it doesn't have any title or caption bars. At the moment, I use the code as follows:
...
case WM_NCHITTEST:
return HTCAPTION;
and that works fine for making the user able to move the window no matter where he drags from. I would like to limit this possibility (only the top of the window will allow movement). I haven't tried checking the position of the mouse pressed because I don't know how to do it in the WM_NCHITTEST message.
I use plain Win32 (winapi) C code (no MFC or anything else at the moment) in Visual Studio 2015.
You will run into trouble if you just return HTCAPTION in response to all WM_NCHITTEST messages. You will break things like scrollbars, close buttons, resizing borders, etc. that are all implemented via different HT* values.
You have the right idea, though. You want to make the client area of your window draggable, so you need to trick Windows into thinking that your client area is actually the caption area (which, as you know, is draggable). That code looks like this:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// ...
case WM_NCHITTEST:
{
// Call the default window procedure for default handling.
const LRESULT result = ::DefWindowProc(hWnd, uMsg, wParam, lParam);
// You want to change HTCLIENT into HTCAPTION.
// Everything else should be left alone.
return (result == HTCLIENT) ? HTCAPTION : result;
}
// ...
}
However, based on the image in your question, you appear to want to restrict this to only a certain region of your window. You will need to define exactly what that area is, and then hit-test to see if the user has clicked in that area. Assuming that rcDraggable is a RECT structure that contains the bounds of the red box shown in your image (in screen coordinates), you can use the following code:
static RECT rcDraggable = ...
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// ...
case WM_NCHITTEST:
{
// Call the default window procedure for default handling.
const LRESULT result = ::DefWindowProc(hWnd, uMsg, wParam, lParam);
// Get the location of the mouse click, which is packed into lParam.
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
// You want to change HTCLIENT into HTCAPTION for a certain rectangle, rcDraggable.
// Everything else should be left alone.
if ((result == HTCLIENT) && (PtInRect(&rcDraggable, pt))
{
return HTCAPTION;
}
return result;
}
// ...
}
If you define rcDraggable in terms of client coordinates, you will need to convert it to screen coordinates before doing the hit-testing in response to WM_NCHITTEST. To do that, call the MapWindowPoints function, like so:
RECT rc = rcDraggable;
MapWindowPoints(hWnd, /* a handle to your window */
NULL, /* convert to screen coordinates */
reinterpret_cast<POINT*>(&rc),
(sizeof(RECT) / sizeof(POINT)));
You can call some magic code in WM_LBUTTONDOWN handler, AFAIR this:
ReleaseCapture();
SendMessage(yourWindowHandle, WM_SYSCOMMAND, 0xf012, 0) ;
I used this method a few years ago in Delphi and Windows XP. I think it must be similar for c++. Of course, you can check x and y before doing this.
I'm using ::SendInput to send a mouse click event:
void LeftDown (LONG x_cord, LONG y_cord)
{
INPUT Input={0};
// left down
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN;
Input.mi.dx = x_cord;
Input.mi.dy = y_cord;
Input.mi.dwExtraInfo = 0x12345; //Is this how to use it?
::SendInput(1,&Input,sizeof(INPUT));
}
I want to set the dwExtraInfo to some self defined value and extract it in the WndProc at the target application. Then (for example) I will ignore that click if the dwExtraInfo is set to some specific value:
LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_LBUTTONDOWN)
{
if(GetMessageExtraInfo() == 0x12345) //Is this how to use it?
//ignore
else
//do something
}
}
Is this naive way is the proper way to use dwExtraInfo or is there a better practice? Thanks!
The documentation says:
dwExtraInfo
An additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information.
So yes, use it just as you have shown it in your question.