2025-11-28 00:35:46 +09:00

248 lines
7.3 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#pragma once
#define MAX_LOADSTRING 100 // Maximal size of a string used in application
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <stdio.h>
#include <tchar.h>
// Other Headers
#include "Program.h"
#include "resource.h"
// Global Variables
wchar_t g_windowClass[MAX_LOADSTRING]; // Name of window class
wchar_t g_mainTitle[MAX_LOADSTRING]; // Application main window title
wchar_t g_touchHitTestingOnText[MAX_LOADSTRING]; // Touch hit testing button label (enabled)
wchar_t g_touchHitTestingOffText[MAX_LOADSTRING]; // Touch hit testing button label (disabled)
wchar_t g_resetText[MAX_LOADSTRING]; // Reset button label
int g_width; // The client windows width
int g_height; // The client windows height
CProgram *g_driver; // Encapsulates all Touch/Mouse Event handling
// Forward declaration of the window procedure
LRESULT CALLBACK WndProc(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM);
// Register Window Class
ATOM MyRegisterClass(_In_ HINSTANCE hInst)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = g_windowClass;
ATOM atom = RegisterClassEx(&wc);
if (atom == NULL)
{
fprintf(stderr, "RegisterClassEx failed with error code %u\n", GetLastError());
}
return atom;
}
// Initialize program instance
bool InitInstance(_In_ HINSTANCE hinst, _In_ int cmdShow)
{
bool success = TRUE;
// Create maximized window
HWND hWnd = CreateWindowEx(0, g_windowClass, g_mainTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hinst, 0);
if (hWnd == nullptr)
{
fprintf(stderr, "CreateWindowEx failed with error code %u\n", GetLastError());
success = false;
}
// Create and initialize touch and mouse handler
if (success)
{
g_driver = new(std::nothrow) CProgram();
if (g_driver == nullptr)
{
fprintf(stderr, "Failed to allocate memory for new object.\n");
success = false;
}
if (success)
{
success = g_driver->Initialize(hWnd, g_touchHitTestingOnText, g_touchHitTestingOffText, g_resetText);
}
}
if (success)
{
ShowWindow(hWnd, cmdShow);
UpdateWindow(hWnd);
}
else if (g_driver != nullptr)
{
delete g_driver;
g_driver = nullptr;
}
return success;
}
// Program entry point
int APIENTRY wWinMain(_In_ HINSTANCE hinst, _In_opt_ HINSTANCE /*hinstPrev*/, _In_ LPWSTR /*lpCmdLine*/, _In_ int /*nCmdShow*/)
{
// Initialize localized global strings
if (LoadString(hinst, IDS_WINDOW, g_windowClass, MAX_LOADSTRING) == 0)
{
fprintf(stderr, "LoadString() failed with error code %u.\n", GetLastError());
return -1;
}
if (LoadString(hinst, IDS_CAPTION, g_mainTitle, MAX_LOADSTRING) == 0)
{
fprintf(stderr, "LoadString() failed with error code %u.\n", GetLastError());
return -1;
}
if (LoadString(hinst, IDS_TOUCHHITTESTING_ON, g_touchHitTestingOnText, MAX_LOADSTRING) == 0)
{
fprintf(stderr, "LoadString() failed with error code %u.\n", GetLastError());
return -1;
}
if (LoadString(hinst, IDS_TOUCHHITTESTING_OFF, g_touchHitTestingOffText, MAX_LOADSTRING) == 0)
{
fprintf(stderr, "LoadString() failed with error code %u.\n", GetLastError());
return -1;
}
if (LoadString(hinst, IDS_RESET, g_resetText, MAX_LOADSTRING) == 0)
{
fprintf(stderr, "LoadString() failed with error code %u.\n", GetLastError());
return -1;
}
// D2D automatically handles high DPI settings
SetProcessDPIAware();
// Register Class
if (!MyRegisterClass(hinst))
{
return -1;
}
// Initialize Application
if (!InitInstance(hinst, SW_SHOWMAXIMIZED))
{
return -1;
}
// Main message loop
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
delete g_driver;
g_driver = nullptr;
return 0;
}
// Processes messages for main Window
LRESULT CALLBACK WndProc(_In_ HWND hWnd, _In_ UINT msg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
PAINTSTRUCT ps;
switch (msg)
{
case WM_DESTROY:
if (g_driver != nullptr)
{
delete g_driver;
g_driver = nullptr;
}
PostQuitMessage(0);
return 1;
case WM_SIZE:
g_width = LOWORD(lParam);
g_height = HIWORD(lParam);
break;
case WM_PAINT:
BeginPaint(hWnd, &ps);
g_driver->RenderInitialState(g_width, g_height);
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
{
if (msg == WM_MOUSEMOVE)
{
// Filter left button only
if (LOWORD(wParam) != MK_LBUTTON)
{
break;
}
}
// Create and process mouse event
INPUT_EVENT inputEvent;
inputEvent.pt.y = HIWORD(lParam);
inputEvent.pt.x = LOWORD(lParam);
inputEvent.eventSource = EVENT_SOURCE_MOUSE;
inputEvent.eventType = (msg == WM_LBUTTONDOWN) ? EVENT_TYPE_DOWN :
(msg == WM_MOUSEMOVE) ? EVENT_TYPE_MOVE : EVENT_TYPE_UP;
inputEvent.cursorId = CURSOR_ID_MOUSE;
g_driver->ProcessInputEvent(&inputEvent, 1);
}
break;
case WM_TOUCHHITTESTING:
// Do smart Touch hit testing
return g_driver->OnTouchHitTesting((PTOUCH_HIT_TESTING_INPUT)lParam);
case WM_POINTERDOWN:
case WM_POINTERUPDATE:
case WM_POINTERUP:
{
// Create and process pointer events
INPUT_EVENT inputEvent;
inputEvent.pt.y = HIWORD(lParam);
inputEvent.pt.x = LOWORD(lParam);
// Pointer position is in screen coordinates, convert to client coordinates
ScreenToClient(hWnd, &inputEvent.pt);
// Program works with any pointer input (touch, pen).
// But only touch input can initialize smart Touch hit testing.
inputEvent.eventSource = EVENT_SOURCE_POINTER;
inputEvent.eventType = (msg == WM_POINTERDOWN) ? EVENT_TYPE_DOWN :
(msg == WM_POINTERUPDATE) ? EVENT_TYPE_MOVE : EVENT_TYPE_UP;
inputEvent.cursorId = GET_POINTERID_WPARAM(wParam);
g_driver->ProcessInputEvent(&inputEvent, 1);
}
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}