Тема: WinApi Робота з вікном
Добрий день. Одним із завдань є змусити вікно рухатися по периметру екрана проти годинникової стрілки після натискання Ентер, за годинниковою при натисканні пробілу і зупитини при Ескейп.
Все це діло реалізовано через таймери: коли потрібно створюється або убивається відповідний таймер,
Ескейп працює безвідмовно. З пробілом ніби все теж нормально, а от при натисканні Ентеру відбувається якесь дикунство: 1. екран може просто зупинитися в кутку, почати розширюватися, втікати за межі екрану, почати рухатися в два рази швидше, продовжити рух ЗА годинниковою стрілкою.
Ось код:
#include <iostream>
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int xWindowSize = GetSystemMetrics(SM_CXSCREEN);        // ширина екрану у пікселях
int yWindowSize = GetSystemMetrics(SM_CYSCREEN);        // висота екрану у пікселях
RECT rcWindow;
int cxWindowClient;        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
int cyWindowClient;        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
int cyWindowTitle;            // висота заголовка
int cyWindowBorder;            // ширина рамки вікна
int cxWindowBorder;            // ширина рамки вікна
enum Direction
{
    left, right, up, down
};
int move = 0;
static int dir = Direction::down;
void changeDirectionToOposite(int &dir)
{
    if (dir == Direction::down)
    {
        dir = Direction::up;
    }
    if (dir == Direction::up)
    {
        dir = Direction::down;
    }
    if (dir == Direction::left)
    {
        dir = Direction::right;
    }
    if (dir == Direction::right)
    {
        dir = Direction::left;
    }
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static wchar_t szAppName[] = L"DemoFig";
    WNDCLASSEX wc;
    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    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)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wc);
    HWND hwnd;
    hwnd = CreateWindow(szAppName, L"Демонстрація таймерів", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    //UpdateWindow(hwnd); 
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}//    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) 
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
    const UINT IDTIMER = 23454;
    const UINT IDTIMERSHOW = 21123454;
    const UINT IDTIMER_Reverse = 222;
    const UINT IDTIMER_Clockwise = 111;
    HDC hdc;
    PAINTSTRUCT ps;
    switch (iMsg)
    {
    case WM_CREATE:
        SetTimer(hwnd, IDTIMER, 100, NULL);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_TIMER:
    {
        switch (wParam)
        {
        case IDTIMER:
            wchar_t buf[444];
            SYSTEMTIME st;
            //GetSystemTime( &st );
            GetLocalTime(&st);
            wsprintf(buf, L" Сьогодні %02i.%02i.%i.    Зараз %02i:%02i:%02i ", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond);
            SetWindowText(hwnd, buf);
            break;
        case IDTIMER_Reverse: //проти часової стрілки
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            if (dir == Direction::down) //вниз && rcWindow.bottom != yWindowSize
            {
                MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.bottom >= yWindowSize)
                {
                    rcWindow.top = yWindowSize - (rcWindow.bottom - rcWindow.top);
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::right;
                }
            }
            else if (dir == Direction::right) //вправо && rcWindow.right != xWindowSize
            {
                MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.right >= xWindowSize)
                {
                    rcWindow.left = xWindowSize - (rcWindow.right - rcWindow.left);
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::up;
                }
            }
            else if (dir == Direction::up) //вверх && rcWindow.top != 0
            {
                MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.top <= 0)
                {
                    MoveWindow(hwnd, rcWindow.left, 0, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::left;
                }
            }
            else if (dir == Direction::left) //вліво && rcWindow.left != 0
            {
                MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.left <= 0)
                {
                    MoveWindow(hwnd, 0, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::down;
                }
            }
        }
        case IDTIMER_Clockwise: // за годинниковою стрілкою
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            if (dir == Direction::down) //вниз && rcWindow.bottom != yWindowSize
            {
                MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.bottom >= yWindowSize)
                {
                    rcWindow.top = yWindowSize - (rcWindow.bottom - rcWindow.top);
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::left;
                }
            }
            else if (dir == Direction::right) //вправо && rcWindow.right != xWindowSize
            {
                MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.right >= xWindowSize)
                {
                    rcWindow.left = xWindowSize - (rcWindow.right - rcWindow.left);
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::down;
                }
            }
            else if (dir == Direction::up) //вверх && rcWindow.top != 0
            {
                MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.top <= 0)
                {
                    MoveWindow(hwnd, rcWindow.left, 0, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::right;
                }
            }
            else if (dir == Direction::left) //вліво && rcWindow.left != 0
            {
                MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                if (rcWindow.left <= 0)
                {
                    MoveWindow(hwnd, 0, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                    dir = Direction::up;
                }
            }
        }
        case IDTIMERSHOW:    // показуємо приховане вікно
            SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
            KillTimer(hwnd, IDTIMERSHOW);
            break;
        }
    }
    break;
#pragma region MOVE
    case WM_KEYDOWN:
    {
        switch (wParam)
        {
        case L'Q':        // ставить вікно у лівий верхній кут
            SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE);
            break;
        case L'Z':        // ставить вікно у правий нижній кут
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            int dx = cxWindowClient + cxWindowBorder - rcWindow.right;                        // на скільки змістити праворуч
            int dy = cyWindowClient + cyWindowBorder + cyWindowTitle - rcWindow.bottom;        // на скільки зсунути донизу
            OffsetRect(&rcWindow, dx, dy);
            //SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
            MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
        }
        break;
        case L'H':        // Згортає вікно 
            SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
            SetTimer(hwnd, IDTIMERSHOW, 3000, NULL);
            break;
        case L'R':        // Розгортає вікно 
        {
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            SetWindowPos(hwnd, NULL, 0, 0, cxWindowClient + cxWindowBorder * 2, cyWindowClient + cyWindowBorder + cyWindowTitle, SWP_SHOWWINDOW);
        }
        case VK_LEFT:
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            if (rcWindow.left != 0)
            {
                if (GetAsyncKeyState(VK_SHIFT))
                {
                    MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else if (GetAsyncKeyState(VK_CONTROL))
                {
                    MoveWindow(hwnd, rcWindow.left - 20, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else
                {
                    MoveWindow(hwnd, rcWindow.left - 1, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
            }
            break;
        }
        case VK_RIGHT:
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            if (rcWindow.right != xWindowSize)
            {
                if (GetAsyncKeyState(VK_SHIFT))
                {
                    MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else if (GetAsyncKeyState(VK_CONTROL))
                {
                    MoveWindow(hwnd, rcWindow.left + 20, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else
                {
                    MoveWindow(hwnd, rcWindow.left + 1, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
            }
            break;
        }
        case VK_UP:
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            //int dx = cxWindowClient + cxWindowBorder - rcWindow.right;                        // на скільки змістити праворуч
            //int dy = 0;        // на скільки зсунути донизу
            //OffsetRect(&rcWindow, dx, dy);
            //SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
            if (rcWindow.top != 0)
            {
                if (GetAsyncKeyState(VK_SHIFT))
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else if (GetAsyncKeyState(VK_CONTROL))
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top - 20, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top - 1, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
            }
            break;
        }
        case VK_DOWN:
        {
            GetWindowRect(hwnd, &rcWindow);    // отримує положення і розміри вікна
            cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN);        // розмір клієнтської зони вікна у повноекранному режимі у пікселях
            cyWindowTitle = GetSystemMetrics(SM_CYCAPTION);            // висота заголовка
            cyWindowBorder = GetSystemMetrics(SM_CYBORDER);            // ширина рамки вікна
            cxWindowBorder = GetSystemMetrics(SM_CXBORDER);            // ширина рамки вікна
            //int dx = cxWindowClient + cxWindowBorder - rcWindow.right;                        // на скільки змістити праворуч
            //int dy = 0;        // на скільки зсунути донизу
            //OffsetRect(&rcWindow, dx, dy);
            //SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
            if (rcWindow.bottom != yWindowSize)
            {
                if (GetAsyncKeyState(VK_SHIFT))
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else if (GetAsyncKeyState(VK_CONTROL))
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top + 20, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
                else
                {
                    MoveWindow(hwnd, rcWindow.left, rcWindow.top + 1, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
                }
            }
            break;
        }
#pragma endregion
        case VK_RETURN: // при натисканні Ентер
        {
            KillTimer(hwnd, IDTIMER_Clockwise); // вбиваємо таймер за годинниковою
            changeDirectionToOposite(dir); // змінюємо напрямок на протилежний
            SetTimer(hwnd, IDTIMER_Reverse, 100, NULL); // запускаємо таймер проти годинникової стрілки по клавіші ENTER
            break;
        }
        case VK_SPACE:  // при натисканні пробілу Space bar
        {
            KillTimer(hwnd, IDTIMER_Reverse);
            changeDirectionToOposite(dir);
            SetTimer(hwnd, IDTIMER_Clockwise, 100, NULL);// запускаємо таймер за годинниковою стрілкою
            break;
        }
        case VK_ESCAPE: // при натисканні Escape
        {
            KillTimer(hwnd, IDTIMER_Reverse);
            KillTimer(hwnd, IDTIMER_Clockwise);
            dir = Direction::down;
            break;
        }
        break;
        }
    }
    break;
    }
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
} // LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) звернути увагу, думаю, треба на case VK_RETURN:, case IDTIMER_Reverse: