Computer Science Canada

Paint Program that Works Anywhere

Author:  HRI [ Thu Jun 02, 2011 6:36 pm ]
Post subject:  Paint Program that Works Anywhere

I've started developing a nifty little tool (great for class) for Windows that lets you paint on the screen anywhere you want. Note that I do plan to build on it and make use of the window (yes, it's in there for future use really).

c++:


#define _WIN32_WINNT 0x0500 // used for GetConsoleWindow()
#include <windows.h> // used for all windows functions
#include <iostream> // used for cin and cout
#include <cstdlib> // used for system
using std::cout;
using std::cin;

HWND cmd = GetConsoleWindow(); // get handle to console window
HWND hwnd; // handle for window

const char g_szClassName[] = "myWindowClass"; // window class name

HDC hdc = GetDC(NULL); // get handle to device context (for graphics) of entire screen

HBRUSH brush = CreateSolidBrush (RGB(0,0,0)); // black brush
HBRUSH white = CreateSolidBrush (RGB(255,255,255)); // white brush (using this later to create canvases)

HPEN pen = CreatePen(PS_NULL,0,RGB(0,0,0)); // black invisible pen

int r=20; // radius of circle
POINT m; // mouse position

void select() // make console window active (it's a bit stubborn...)
{
    RECT rect; // contains left/right/top/bottom
    GetWindowRect(cmd, &rect); // get console window's coordinates
    SetWindowPos(cmd,HWND_TOP,rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top,SWP_SHOWWINDOW); // make console window active
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) // random window procedure
{

    SelectObject(hdc,brush); // select the current brush
    GetCursorPos(&m); // get mouse position
    Ellipse(hdc,m.x-r,m.y-r,m.x+r,m.y+r); // draw a circle of radius r at mouse
    SelectObject(hdc,pen); // select current pen
    Ellipse(hdc,m.x-r,m.y-r,m.x+r,m.y+r); // draw a circle with the pen (annoying black outlines if I don't do this)
}

void changeColour() // change colour of circle
{
    ShowWindow(cmd,SW_SHOWNORMAL); // show console window
    SetFocus(cmd); // set the focus (input) to console window

    int r = -1, g = -1, b = -1; // colours (1 to 255)

    while (r < 0 || r > 255)
    {
        cout << "Red: "; // prompt for red amount
        cin >> r; // input red amount
    }

    while (g < 0 || g > 255)
    {
        cout << "Green: "; // prompt for green amount
        cin >> g; // input green amount
    }

    while (b < 0 || b > 255)
    {
        cout << "Blue: "; // prompt for blue amount
        cin >> b; // input blue amount
    }

    system("cls"); // clear screen
    ShowWindow(cmd,SW_HIDE); // hide console window

    brush = CreateSolidBrush(RGB(r,g,b)); // change the brush to that colour
    pen = CreatePen(PS_SOLID,0,RGB(r,g,b)); // change the pen to that colour
}

void changeSize() // change the radius
{
    ShowWindow(cmd,SW_SHOWNORMAL); // show console window
    SetFocus(cmd); // give console window focus

    int size = -1; // new radius

    while (size < 0 || size > 50)
    {
        cout << "Size: "; // prompt for new size
        cin >> size; // input new size
        system ("cls"); // clear screen
    }

    r=size; // set radius to equal size

    ShowWindow(cmd,SW_HIDE); // hide console window
}

// main function
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nShowCmd) {

    ShowWindow (cmd, SW_HIDE); // hide console window

    WNDCLASSEX wc; // windows class

    // initialize data members of class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc)) // register class
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // create window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "The title of my window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
        NULL, NULL, hInstance, NULL);

    if(hwnd == NULL) // check to make sure window is created
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, SW_HIDE); // hide window
    UpdateWindow(hwnd);

    INPUT move; // move mouse from bottom right to current location
    move.type=0; // mouse input
    move.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; // used to give absolute coordinates, not relative

    INPUT up; // move mouse button up
    up.type=0; // mouse input
    up.mi.dwFlags=0x0004; // left button up

    INPUT down; // move mouse button down
    down.type=0; // mouse input
    down.mi.dwFlags=0x0002; // left button down

    bool mouse; // used to check whether left button has been released

    while(1) // infinite loop
    {
        if (GetAsyncKeyState (VK_LBUTTON) & 0x8000) // if left button is down
        {
            if (!mouse) // if it was up before
            {
                GetCursorPos(&m); // get mouse position
                SetCursorPos(GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); // set cursor to bottom right

                SendInput(1,&down,sizeof(down)); // push left button down

                move.mi.dx=(m.x * 65535 / GetSystemMetrics(SM_CXSCREEN)); // set the coordinates of move to where mouse was
                move.mi.dy=(m.y * 65535 / GetSystemMetrics(SM_CYSCREEN));

                SendInput(1,&move,sizeof(move)); // move mouse back (dragging since left button is down)

                mouse = true; // button has been pushed down
            }

            WndProc (hwnd,WM_LBUTTONDOWN,0,0); // call the window procedure (only this executes if the button remains down)
        }

        if (!(GetAsyncKeyState(VK_LBUTTON) & 0x8000)) // if left mouse button is up
        {
            mouse = false; // set variable to false so that it will drag from bottom right next press again
        }

        if (GetAsyncKeyState(0x31) & 0x8000) changeColour(); // if '1' is pressed, change the colour
        if (GetAsyncKeyState(0x32) & 0x8000) changeSize(); // if '2' is pressed, change the size
    }

    return 0;
}


It should compile and run fine, but as of a couple hours ago, the computer doesn't seem to want to compile anything...
Also, a small note: There is no way to quit this program in a user-friendly manner. That means either log off, shut down, or type taskkill /f /im <filename>.exe into command prompt.

If you notice anything that could be written better (as in codewise, not programming practices, I know it's all messy), feel free to share.
A final note, if you know of a way to make it not use all the CPU it can, I'd be happy to hear.

Suggestions on future additions, ideas on fixing existing code, and constructive criticism are appreciated!

FUTURE UPDATE IDEAS:
-a palette of colours rather than entering RGB (or even a few sliders and a sample)
-ability to make a white rectangle as a canvas
-storing the screen so I can redraw it when the console window is gone or something updates (ideas on that would be nice)
-ability to trap (or release) the cursor within the latest canvas created
-when I get the dang hook working, ability to scroll for size adjustment
-different shapes, lines etc
-an interface for all this stuff with a hotkey (probably where that window could be nice)
-umm...nuke the annoying circles and make an actual path? (working on this next I hope, main idea I have is storing old coordinates and drawing some circles along the way, but I don't know how that's going to work when they make curves)
-figuring out how to get it to not continue to move stuff (i.e. there's no more selection box on the desktop because it drags from the bottom right now, but you can still move icons around)
-oh! an exit button or something would be great :p

EDIT: really bad to forget this: Great site for learning beginning Windows API programming, exactly where I stole a version of the window from since it takes so long to write it out.

Author:  Velocity [ Mon Jan 16, 2012 9:38 am ]
Post subject:  RE:Paint Program that Works Anywhere

nice game, works perfectly.


: