Detect mouse movement?

I know I've asked quite a few questions on this forum, but, here's another. Hopefully my last for a little while at least.

If anyone knows how to detect the movment of the mouse (i.e where it is on my window), that's what I'm hoping to find out.

I have Googled for it, but not found anything promising.

Is there a WIN32 API function for this, or some other way of doing it?

Thank you.
There are tons of methods, posted many times for 15 years
See Google Groups, Win32
Handle the mouse move message (WM_MOUSEMOVE)

http://msdn.microsoft.com/en-us/library/ms645616(VS.85).aspx
if you want to capture mouse movement even when your window is not active then you can create a mouse hook..
read about creating windows hooks.. because wm_mousemove will stop working when some other window gets the focus otherwise as grey wolf said wm_mousemove is enough.

http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx


for this you need to learn how to create dll's and a little bit of win32 experience.
Ok. Thanks guys.

I don't think I'm ready to create a .dll yet; so I'll use wm_mousemove.
Wow. I've never come across a more confusing MSDN article. Usually they're easily understood, with examples and things.

I don't quite understand what they're saying? What do I do with this:
1
2
3
4
WM_MOUSEMOVE

    WPARAM wParam
    LPARAM lParam;


Could someone explain?

Also these (
1
2
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
) don't name types. How are they supposed to be used?
Last edited on
Do you know what a window procedure is? Then you know what a message is. When handling the WM_MOUSEMOVE message, the lParam of the window procedure has the x and y position of the mouse encoded in its high and low word. GET_X_LPARAM(lParam) gets the X position, etc.
Yes, I think I understand.

So, this should be my LRESULT CALLBACK WindowProcedure() function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

switch (message) {
case WM_DESTROY: 
     PostQuitMessage (0); 
     break;
case WM_MOUSEMOVE:
     return DefWindowProc(hwnd, message, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
     break;
default: 
     return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}


I'm quite new to WinAPI programming. The point of this is to track the mouse and draw a line where it has been. Then I'm going to create one of those steady-hand games, where, for the real-life ones, you move the cursor along a metal track and if you touch it, the circuit completes and you hear a beep. Like that Operation game.
Last edited on
That's the idea, but you can't just call the default window procedure. In fact, you generally return 0 instead of calling the default procedure for the messages that you intercept and handle. Here's a simple skeleton for a WindowsAPI program. Also consider that there are portable alternatives which can hide some detail or make it object-oriented, such as wxWidgets, Qt, SDL, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <windows.h>

#define WINDOW_POS_X   0
#define WINDOW_POS_Y   0
#define CLIENT_SIZE_X  400
#define CLIENT_SIZE_Y  300
#define COLOR_BACK     RGB(   0,   0,  80 )
#define COLOR_FORE     RGB( 200, 200,  50 )

HBRUSH hbrBack;
BOOL do_mouse_move = FALSE;

void wmLButtonDblClk( HWND hwnd, WPARAM wp, LPARAM lp )
{
    InvalidateRect( hwnd, NULL, TRUE ); // erase window
}

void wmLButtonDown( HWND hwnd, WPARAM wp, LPARAM lp )
{
    do_mouse_move = true;
    SetCapture( hwnd ); // so we'll get the button-up msg even
                        // if the cursor is off of the window
}

void wmLButtonUp( HWND hwnd, WPARAM wp, LPARAM lp )
{
    do_mouse_move = false;
    ReleaseCapture();
}

void wmMouseMove( HWND hwnd, WPARAM wp, LPARAM lp )
{
    POINT p;
    HDC hdc;
    if( !do_mouse_move ) return;
    p = (POINT) { LOWORD( lp ), HIWORD( lp ) }; // x-pos, y-pos
    hdc = GetDC( hwnd );
    SetPixelV( hdc, p.x, p.y, COLOR_FORE );
    ReleaseDC( hwnd, hdc );
}

void wmDestroy( HWND hwnd, WPARAM wp, LPARAM lp )
{
    PostQuitMessage( 0 );
}

LRESULT CALLBACK wndproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
    switch( msg )
    {
//  case WM_CREATE:        wmCreate(        hwnd, wp, lp );  break;
//  case WM_PAINT:         wmPaint(         hwnd, wp, lp );  break;
    case WM_MOUSEMOVE:     wmMouseMove(     hwnd, wp, lp );  break;
    case WM_LBUTTONDOWN:   wmLButtonDown(   hwnd, wp, lp );  break;
    case WM_LBUTTONUP:     wmLButtonUp(     hwnd, wp, lp );  break;
    case WM_LBUTTONDBLCLK: wmLButtonDblClk( hwnd, wp, lp );  break;
    case WM_DESTROY:       wmDestroy(       hwnd, wp, lp );  break;
    default:        return DefWindowProc(   hwnd, msg, wp, lp );
    }
    return 0;
}

HWND createWindow( HINSTANCE hinst, char *appname )
{
    WNDCLASSEX wc = { sizeof( wc ) };
    DWORD style = WS_POPUPWINDOW|WS_CAPTION;
    RECT rect = { 0, 0, CLIENT_SIZE_X, CLIENT_SIZE_Y };
    AdjustWindowRect( &rect, style, FALSE ); // TRUE if menu

    wc.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    wc.lpfnWndProc   = wndproc;
    wc.hInstance     = hinst;
    wc.hIcon         = LoadIcon( hinst, appname );
    wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH) hbrBack;
    wc.lpszMenuName  = appname;
    wc.lpszClassName = appname;
    wc.hIconSm       = (HICON) LoadImage( hinst, appname, IMAGE_ICON,
                        SM_CXSMICON, SM_CYSMICON, LR_DEFAULTCOLOR );
    RegisterClassEx( &wc );

    return CreateWindowEx( 0, appname, appname, style | WS_VISIBLE,
        WINDOW_POS_X, WINDOW_POS_Y,
        rect.right - rect.left, rect.bottom - rect.top,
        NULL, NULL, hinst, NULL );
}

int WINAPI WinMain( HINSTANCE hinst, HINSTANCE unused,
                    PSTR cmd, int show )
{
    char *appName = "SimpleDraw";
    MSG msg;
    hbrBack = CreateSolidBrush( COLOR_BACK );
    createWindow( hinst, appName );

    while( GetMessage( &msg, NULL, 0, 0 ))
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    DeleteObject( hbrBack );
    return msg.wParam;
}


-- All I needed to do was change do_mouse_move to true... and it works =]

Thanks for all your help.

Here's the code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/********************************************************************************/
/* This first GUI program of mine is intended to draw a blue line where the     */
/* user has moved their mouse. It was compiled in Bloodshed Dev-C++ 4.9.9.2;    */
/* I used a GUI which was generated by the compiler and edited by me.           */
/* I also was helped by the wonderful users of cplusplus.com's forums =] Thanks.*/
/********************************************************************************/

#include <windows.h>
#define COLOR_LINE           RGB(5, 5, 255) // Blue

HBRUSH hbrBack;
BOOL do_mouse_move = FALSE;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void wmMouseMove(HWND, WPARAM, LPARAM);
void Do_Draw(HDC, WPARAM, LPARAM);
void wmLButtonDown(HWND, WPARAM, LPARAM);
void wmLButtonUp(HWND, WPARAM, LPARAM);

char szClassName[] = "MouseTrack";

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) {
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;

wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);

wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; // Use the default background colour (grey)

if (!RegisterClassEx (&wincl)) {
  return 0;
}
// Create the Window
hwnd = CreateWindowEx (0, szClassName, "Mouse Tracker", WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL,
                       hThisInstance, NULL);

ShowWindow (hwnd, nFunsterStil);

while (GetMessage (&messages, NULL, 0, 0)) {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
}

return messages.wParam;
}

// This function is called by DispatchMessage()
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) {
switch (message) {
    case WM_MOUSEMOVE:
         wmMouseMove(hwnd, wp, lp);
         break;
    case WM_LBUTTONDOWN:
         wmLButtonDown(hwnd, wp, lp);
         break;
    case WM_LBUTTONUP:
         wmLButtonUp(hwnd, wp, lp);
         break;
    case WM_DESTROY:
         PostQuitMessage(0);       // Send WM_QUIT
         break;

    default:
    return DefWindowProc(hwnd, message, wp, lp);
    }

return 0;
}

void wmLButtonDown(HWND hwnd, WPARAM wp, LPARAM lp) {
do_mouse_move=true;
}

void wmLButtonUp(HWND hwnd, WPARAM wp, LPARAM lp) {
do_mouse_move=false;
}

void wmMouseMove(HWND hwnd, WPARAM wp, LPARAM lp) {
POINT p;
HDC hdc;

if(!do_mouse_move) return;
p = (POINT) { LOWORD(lp), HIWORD(lp) }; // The x & y positions
hdc = GetDC(hwnd);
Do_Draw(hdc, p.x, p.y);
ReleaseDC(hwnd, hdc);
}

void Do_Draw(HDC hdc, WPARAM wp, LPARAM lp) { // This function will draw a line where the user's cursor has been.
HPEN LineOld;
HPEN Line;
Line=CreatePen(PS_SOLID, 7, COLOR_LINE);
LineOld=(HPEN)SelectObject(hdc, Line);

MoveToEx(hdc, wp, lp, NULL);
LineTo(hdc, wp, lp);

SelectObject(hdc, LineOld);
DeleteObject(Line);
}


I removed SetCapture(hwnd) because it was not allowing the user to close the program - you had to right click the instance on the task bar and click "Close window" or you had to go to a different window and then bring it back up again without clicking the GUI so that you could close it.

The only problem now is that if the user tries to draw the line to fast, the line is printed wrong (it comes up with dots)
Last edited on
You need to save the cursor location when the user presses the LBUTTON. And you should SetCapture(), but you also then must use ReleaseCapture() in wmLButtonUp. Here's a rewrite and cleanup or your code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <windows.h>
#define COLOR_FORE    RGB(220,230,200)
#define COLOR_BACK    RGB(50,80,120)
#define PEN_THICKNESS 5

HBRUSH g_hbrBack;
HPEN   g_hpenFore;
POINTS g_oldPoint;
char szClassName[] = "MouseTrack";

LRESULT CALLBACK WindowProc (HWND, UINT, WPARAM, LPARAM);
void wmMouseMove (HWND hwnd, WPARAM wp, LPARAM lp);
void wmLButtonDown (HWND hwnd, WPARAM wp, LPARAM lp);
void wmLButtonUp (HWND hwnd, WPARAM wp, LPARAM lp);
void wmLButtonDblClk (HWND hwnd, WPARAM wp, LPARAM lp);

int WINAPI WinMain (HINSTANCE hinst, HINSTANCE nil, LPSTR arg, int cmdShow) {
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wc;

    // Create these here and let the OS delete them on exit.
    g_hbrBack = CreateSolidBrush (COLOR_BACK);
    g_hpenFore = CreatePen (PS_SOLID, PEN_THICKNESS, COLOR_FORE);

    wc.cbSize = sizeof (WNDCLASSEX);
    wc.hInstance = hinst;
    wc.lpszClassName = szClassName;
    wc.lpfnWndProc = WindowProc;
    wc.style = CS_DBLCLKS;
    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH) g_hbrBack;

    if (!RegisterClassEx (&wc)) return 0;

    hwnd = CreateWindowEx (0, szClassName, "Mouse Tracker",
                           WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT,
                           544, 375, HWND_DESKTOP, NULL,
                           hinst, NULL);
    ShowWindow (hwnd, cmdShow);

    while (GetMessage (&msg, NULL, 0, 0)) {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WindowProc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    switch (msg) {
    case WM_MOUSEMOVE:
        wmMouseMove (hwnd, wp, lp);
        break;
    case WM_LBUTTONDOWN:
        wmLButtonDown (hwnd, wp, lp);
        break;
    case WM_LBUTTONUP:
        wmLButtonUp (hwnd, wp, lp);
        break;
    case WM_LBUTTONDBLCLK:
        wmLButtonDblClk (hwnd, wp, lp);
        break;
    case WM_DESTROY:
        PostQuitMessage (0);
        break;
    default:
        return DefWindowProc (hwnd, msg, wp, lp);
    }
    return 0;
}

void wmLButtonDblClk (HWND hwnd, WPARAM wp, LPARAM lp) {
    InvalidateRect (hwnd, 0, 1);
}

void wmLButtonDown (HWND hwnd, WPARAM wp, LPARAM lp) {
    g_oldPoint = MAKEPOINTS (lp);
    SetCapture (hwnd);
}

void wmLButtonUp (HWND hwnd, WPARAM wp, LPARAM lp) {
    ReleaseCapture();
}

void wmMouseMove (HWND hwnd, WPARAM wp, LPARAM lp) {
    POINTS p;
    HDC hdc;

    if (wp != MK_LBUTTON) return;

    p = MAKEPOINTS (lp); // Cursor x,y coords
    hdc = GetDC (hwnd);
    SelectObject (hdc, g_hpenFore);
    MoveToEx (hdc, g_oldPoint.x, g_oldPoint.y, 0);
    LineTo (hdc, p.x, p.y);
    g_oldPoint = p;
    ReleaseDC (hwnd, hdc);
}

Thanks =]

This forum is excellent. Final question before I mark this as solved:

How can I implement this so that it works:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
char col=getch(); // Allow the user to choose the colour

switch (col) {
case 'r':
     Line=CreatePen(PS_SOLID, 7, COLOR_RED);
     break;
case 'g':
     Line=CreatePen(PS_SOLID, 7, COLOR_BLUE);
     break;
case 'b':
     Line=CreatePen(PS_SOLID, 7, COLOR_GREEN);
     break;
case 'p':
     Line=CreatePen(PS_SOLID, 7, COLOR_PURPLE);
     break;
case 'y':
     Line=CreatePen(PS_SOLID, 7, COLOR_YELLOW);
     break;
case 'R':
     Line=CreatePen(PS_SOLID, 7, COLOR_RED);
     break;
case 'G':
     Line=CreatePen(PS_SOLID, 7, COLOR_BLUE);
     break;
case 'B':
     Line=CreatePen(PS_SOLID, 7, COLOR_GREEN);
     break;
case 'P':
     Line=CreatePen(PS_SOLID, 7, COLOR_PURPLE);
     break;
case 'Y':
     Line=CreatePen(PS_SOLID, 7, COLOR_YELLOW);
     break;
default:
     Line=CreatePen(PS_SOLID, 7, COLOR_BLACK);
}


Obviously getch() is not the way to go about this...
Last edited on
With reference to the code in my last post, add this function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void wmKeyDown (HWND hwnd, WPARAM wp, LPARAM lp) {
    switch (wp) {
    case VK_ESCAPE:
        PostMessage (hwnd, WM_QUIT, 0, 0);
        break;

    case 'R': case 'G': case 'B':
        {
            COLORREF color;
            DeleteObject (g_hpenFore);
            switch (wp) {
                case 'R': color = RGB(200,0,0); break;
                case 'G': color = RGB(0,200,0); break;
                case 'B': color = RGB(0,0,200); break;
            }
            g_hpenFore = CreatePen (PS_SOLID, PEN_THICKNESS, color);
        }
        break;
    }
}


And add this case to WindowProc's switch:

1
2
3
    case WM_KEYDOWN:
        wmKeyDown (hwnd, wp, lp);
        break;

Thanks, but it is still not working. I've done everything I could think of, but for whatever reason it still doesn't work. Here's the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) {
switch (message) {
    case WM_MOUSEMOVE:
         wmMouseMove(hwnd, wp, lp);
         break;
    case WM_LBUTTONDOWN:
         wmLButtonDown(hwnd, wp, lp);
         break;
    case WM_LBUTTONUP:
         wmLButtonUp(hwnd, wp, lp);
         break;

         break;
    case WM_DESTROY:
         PostQuitMessage(0);       // Send WM_QUIT
         break;
    case WM_KEYDOWN:
        wmKeyDown(hwnd, wp, lp);
        break;
    default:
         return DefWindowProc(hwnd, message, wp, lp);
         }

return 0;
}

void wmLButtonDown(HWND hwnd, WPARAM wp, LPARAM lp) {
g_oldPoint = MAKEPOINTS(lp);
SetCapture(hwnd);
}

void wmLButtonUp(HWND hwnd, WPARAM wp, LPARAM lp) {
ReleaseCapture();
}

void wmMouseMove(HWND hwnd, WPARAM wp, LPARAM lp) {
POINTS p;
HDC hdc;

if (wp!=MK_LBUTTON) return;

p=MAKEPOINTS(lp);
hdc=GetDC(hwnd);
SelectObject(hdc, g_hpenFore);
MoveToEx(hdc, g_oldPoint.x, g_oldPoint.y, 0);
LineTo(hdc, p.x, p.y);
g_oldPoint=p;
ReleaseDC(hwnd, hdc);
}

void wmKeyDown (HWND hwnd, WPARAM wp, LPARAM lp) {
    switch (wp) {
    case VK_ESCAPE:
        PostMessage (hwnd, WM_QUIT, 0, 0);
        break;
    case 'R': case 'G': case 'B': case 'P': case 'Y': 
    case 'r': case 'g': case 'b': case 'p': case 'y': {
         COLORREF color;
         DeleteObject (g_hpenFore);
         switch (wp) {
                case 'R':
                     color=COLOR_RED;
                     break;
                case 'G':
                     color=COLOR_GREEN;
                     break;
                case 'B':
                     color=COLOR_BLUE;
                     break;
                case 'P':
                     color=COLOR_PURPLE;
                     break;
                case 'Y':
                     color=COLOR_YELLOW;
                     break;
                case 'r':
                     color=COLOR_RED;
                     break;
                case 'g':
                     color=COLOR_GREEN;
                     break;
                case 'b':
                     color=COLOR_BLUE;
                     break;
                case 'p':
                     color=COLOR_PURPLE;
                     break;
                case 'y':
                     color=COLOR_YELLOW;
                     break;
                default:
                     color=COLOR_BLACK;
                     break;
            g_hpenFore=CreatePen(PS_SOLID, 7, color);
        }
        break;
        }
    }
}


By the way, I'm sorry for all the problems, but thanks alot. You didn't have to help me, and aren't really getting anything in return, but you're helping anyway, so thanks.
Last edited on
I can't tell what's wrong because you've only posted a partial program. It looks like it might work if the rest of it were there. Have you defined things like COLOR_RED, etc?

Also, WM_KEYDOWN messages don't distinguish between case, so you can remove all of the lowercase letters. If you need to distinguish case you would handle the WM_CHAR message.
Ok. I've defined all of what I've used.

It compiles, but the colour does not change.

This is the current code for the entire thing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <windows.h>
#include <conio.h>
#define COLOR_RED    RGB(255, 0, 0  )
#define COLOR_BLUE   RGB(5, 5, 255  )
#define COLOR_GREEN  RGB(0, 255, 0  )
#define COLOR_PURPLE RGB(255, 0, 255)
#define COLOR_YELLOW RGB(255, 255, 0)
#define COLOR_BLACK  RGB(0, 0, 0    )

HBRUSH g_hbrBack;
HPEN   g_hpenFore;
POINTS g_oldPoint;

BOOL do_mouse_move = FALSE;

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void wmMouseMove(HWND, WPARAM, LPARAM);
void Do_Draw(HDC, WPARAM, LPARAM);
void wmLButtonDown(HWND, WPARAM, LPARAM);
void wmLButtonUp(HWND, WPARAM, LPARAM);
void wmKeyDown(HWND, WPARAM, LPARAM);
void wmLButtonDblClk(HWND, WPARAM, LPARAM);

char szClassName[] = "MouseTrack";

int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) {

HWND hwnd;
MSG messages;
WNDCLASSEX wincl;

wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);

wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; // Use the default background colour (grey)

if (!RegisterClassEx (&wincl)) {
  return 0;
}
// Create the Window
hwnd = CreateWindowEx (0, szClassName, "Mouse Tracker", WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL,
                       hThisInstance, NULL);

ShowWindow (hwnd, nFunsterStil);

while (GetMessage (&messages, NULL, 0, 0)) {
  TranslateMessage(&messages);
  DispatchMessage(&messages);
}

return messages.wParam;
}


// This function is called by DispatchMessage()
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) {
switch (message) {
    case WM_MOUSEMOVE:
         wmMouseMove(hwnd, wp, lp);
         break;
    case WM_LBUTTONDOWN:
         wmLButtonDown(hwnd, wp, lp);
         break;
    case WM_LBUTTONUP:
         wmLButtonUp(hwnd, wp, lp);
         break;
    case WM_DESTROY:
         PostQuitMessage(0);       // Send WM_QUIT
         break;
    case WM_KEYDOWN:
        wmKeyDown(hwnd, wp, lp);
        break;
    default:
         return DefWindowProc(hwnd, message, wp, lp);
         }

return 0;
}

void wmLButtonDown(HWND hwnd, WPARAM wp, LPARAM lp) {
g_oldPoint=MAKEPOINTS(lp);
SetCapture(hwnd);
}

void wmLButtonUp(HWND hwnd, WPARAM wp, LPARAM lp) {
ReleaseCapture();
}

void wmKeyDown (HWND hwnd, WPARAM wp, LPARAM lp) {
    switch (wp) {
    case VK_ESCAPE:
        PostMessage(hwnd, WM_QUIT, 0, 0);
        break;
    case 'R': case 'G': case 'B': case 'P': case 'Y': {
         COLORREF color;
         DeleteObject (g_hpenFore);
         switch (wp) {
                case 'R':
                     color=COLOR_RED;
                     break;
                case 'G':
                     color=COLOR_GREEN;
                     break;
                case 'B':
                     color=COLOR_BLUE;
                     break;
                case 'P':
                     color=COLOR_PURPLE;
                     break;
                case 'Y':
                     color=COLOR_YELLOW;
                     break;
                default:
                     color=COLOR_BLACK;
                     break;
            g_hpenFore=CreatePen(PS_SOLID, 7, color);
        }
        break;
        }
    }
}

void wmMouseMove(HWND hwnd, WPARAM wp, LPARAM lp) {
POINTS p;
HDC hdc;

if (wp!=MK_LBUTTON) return;

p=MAKEPOINTS(lp);
hdc=GetDC(hwnd);
SelectObject(hdc, g_hpenFore);
MoveToEx(hdc, g_oldPoint.x, g_oldPoint.y, 0);
LineTo(hdc, p.x, p.y);
g_oldPoint=p;
ReleaseDC(hwnd, hdc);
}
Last edited on
You want to move this just outside the brace that ends the switch (it's currently inside, in a position that ensures it will never be executed):
g_hpenFore=CreatePen(PS_SOLID, 7, color);

You probably want to use essentially the same line to set a default starting color in WinMain.
It worked! Thanks!

Now I'll add more colours and get my own little MS-Paint running =]

I'll work on making a steady hand game now. That was the point of this - to learn what will be required to do that.

I'll mark the topic as solved now.

Thanks - http://i44.tinypic.com/24mc68h.png
Last edited on
Topic archived. No new replies allowed.