LRESULT TouchEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (global.status) { case global.GS_PLAYING: { if (global.isGamePaused) return 0; UINT cInputs = LOWORD(wParam); PTOUCHINPUT pInputs = (PTOUCHINPUT)malloc(sizeof(TOUCHINPUT) * cInputs); if (pInputs) { POINT cliCoord = { 0 }; ClientToScreen(hWnd, &cliCoord); if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) { for (UINT i = 0; i < cInputs; i++) { int track; double ix = double(pInputs[i].x / 100 - cliCoord.x) / WNDWIDTH; double iy = double(pInputs[i].y / 100 - cliCoord.y) / WNDHEIGHT; if (ix < 0. || ix > 1.) continue; if (iy <= 0.26) track = 0; else if (iy <= 0.5) track = 1; else if (iy <= 0.76) track = 2; else track = 3; if (global.heroes[i].jpCount == 0 || (pInputs[i].dwFlags & TOUCHEVENTF_DOWN)) DoJump(track); } CloseTouchInputHandle((HTOUCHINPUT)lParam); } free(pInputs); } return 0; break; } default: break; } return DefWindowProc(hWnd, message, wParam, lParam); }
LRESULT ofTouch::processTouch(HWND hWnd, WPARAM wParam, LPARAM lParam) { //return DefWindowProc(hWnd, WM_TOUCH, wParam, lParam); BOOL bHandled = FALSE; UINT cInputs = LOWORD(wParam); PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs]; if (pInputs){ if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))){ for (UINT i=0; i < cInputs; i++){ TOUCHINPUT ti = pInputs[i]; //do something with each touch input entry if (ti.dwFlags & TOUCHEVENTF_DOWN){ OnTouchDown(ti.dwID, TOUCH_COORD_TO_PIXEL(ti.x)-ofGetWindowPositionX(), TOUCH_COORD_TO_PIXEL(ti.y)-ofGetWindowPositionY()); } else if (ti.dwFlags & TOUCHEVENTF_MOVE){ OnTouchMove(ti.dwID, TOUCH_COORD_TO_PIXEL(ti.x)-ofGetWindowPositionX(), TOUCH_COORD_TO_PIXEL(ti.y)-ofGetWindowPositionY()); } if (ti.dwFlags & TOUCHEVENTF_UP){ OnTouchUp(ti.dwID, TOUCH_COORD_TO_PIXEL(ti.x)-ofGetWindowPositionX(), TOUCH_COORD_TO_PIXEL(ti.y)-ofGetWindowPositionY()); } } bHandled = TRUE; }else{ /* handle the error here */ } delete [] pInputs; }else{ /* handle the error here, probably out of memory */ } if (bHandled){ // if you handled the message, close the touch input handle and return CloseTouchInputHandle((HTOUCHINPUT)lParam); return 0; }else{ // if you didn't handle the message, let DefWindowProc handle it return DefWindowProc(hWnd, WM_TOUCH, wParam, lParam); } }
/* Static Functions */ LRESULT CALLBACK WMTouchEventSource::wmTouchProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { assert(prevWndProc); assert(instance); if(msg == WM_TABLET_QUERYSYSTEMGESTURESTATUS) { return (TABLET_DISABLE_PRESSANDHOLD | TABLET_DISABLE_PENTAPFEEDBACK | TABLET_DISABLE_PENBARRELFEEDBACK | TABLET_DISABLE_TOUCHUIFORCEON | TABLET_DISABLE_TOUCHUIFORCEOFF | TABLET_DISABLE_TOUCHSWITCH | TABLET_DISABLE_FLICKS); } else if(msg == WM_TOUCH) { // WM_TOUCH message can contain several messages from different contacts // packed together. // Message parameters need to be decoded: unsigned int numInputs = (unsigned int) wParam; // Number of actual per-contact messages TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; // Allocate the storage for the parameters of the per-contact messages if (ti == NULL) { return 0; } // Unpack message parameters into the array of TOUCHINPUT structures, each // representing a message for one single contact. if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message // handler. for (unsigned int i = 0; i < numInputs; ++i) { if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { instance->touchDown(&ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { instance->touchMove(&ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { instance->touchUp(&ti[i]); } } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] ti; } else if((msg == WM_LBUTTONDOWN) && ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH)) { // ignore clicks caused by touches return 0; } else { LRESULT result = CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam); return result; } return NULL; }
LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { Win32Window* wnd = reinterpret_cast<Win32Window*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); static const unsigned int MOUSEEVENTF_FROMTOUCH = 0xff515700; switch (message) { case WM_KEYDOWN: if (wnd->eventHandler) { Key key = VirtualToXliKey(wParam); if (key != KeyUnknown && wnd->eventHandler->OnKeyDown(wnd, key)) return 0; /* else TranslateMessage(&msg); */ } break; case WM_KEYUP: if (wnd->eventHandler) { Key key = VirtualToXliKey(wParam); if (key != KeyUnknown && wnd->eventHandler->OnKeyUp(wnd, key)) return 0; } break; case WM_CHAR: if (wnd->eventHandler && wnd->eventHandler->OnTextInput(wnd, (String)(char)(unsigned char)(int)wParam)) return 0; break; case WM_MOUSEMOVE: if (wnd->eventHandler && wnd->eventHandler->OnMouseMove(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) return 0; break; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646265(v=vs.85).aspx /* case WM_MOUSELEAVE: if (wnd->eventHandler && wnd->eventHandler->OnMouseMove(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) return 0; break; */ case WM_MBUTTONDOWN: if (wnd->eventHandler && wnd->eventHandler->OnMouseDown(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonMiddle)) return 0; break; case WM_MBUTTONUP: if (wnd->eventHandler && wnd->eventHandler->OnMouseUp(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonMiddle)) return 0; break; case WM_LBUTTONDOWN: if (wnd->eventHandler && wnd->eventHandler->OnMouseDown(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonLeft)) return 0; break; case WM_LBUTTONUP: if (wnd->eventHandler && wnd->eventHandler->OnMouseUp(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonLeft)) return 0; break; case WM_RBUTTONDOWN: if (wnd->eventHandler && wnd->eventHandler->OnMouseDown(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonRight)) return 0; break; case WM_RBUTTONUP: if (wnd->eventHandler && wnd->eventHandler->OnMouseUp(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), MouseButtonRight)) return 0; break; case WM_MOUSEWHEEL: if (wnd->eventHandler && wnd->eventHandler->OnMouseWheel(wnd, Vector2i(0, GET_WHEEL_DELTA_WPARAM(wParam)))) return 0; break; case WM_MOUSEHWHEEL: if (wnd->eventHandler && wnd->eventHandler->OnMouseWheel(wnd, Vector2i(GET_WHEEL_DELTA_WPARAM(wParam), 0))) return 0; break; case WM_XBUTTONDOWN: if (wnd->eventHandler && wnd->eventHandler->OnMouseDown(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MouseButtonX1 : MouseButtonX2)) return 0; break; case WM_XBUTTONUP: if (wnd->eventHandler && wnd->eventHandler->OnMouseUp(wnd, Vector2i(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? MouseButtonX1 : MouseButtonX2)) return 0; break; case WM_TOUCH: if (wnd->eventHandler) { int numInputs = LOWORD(wParam); if (numInputs) { PTOUCHINPUT touchPoints = (PTOUCHINPUT)alloca(numInputs * sizeof(TOUCHINPUT)); if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, touchPoints, sizeof(TOUCHINPUT))) { for (int i = 0; i < numInputs; i++) { TOUCHINPUT ti = touchPoints[i]; if (ti.dwFlags & TOUCHEVENTF_DOWN) wnd->eventHandler->OnTouchDown(wnd, Vector2((float)ti.x / 100.0f, (float)ti.y / 100.0f), ti.dwID); if (ti.dwFlags & TOUCHEVENTF_MOVE) wnd->eventHandler->OnTouchMove(wnd, Vector2((float)ti.x / 100.0f, (float)ti.y / 100.0f), ti.dwID); if (ti.dwFlags & TOUCHEVENTF_UP) wnd->eventHandler->OnTouchUp(wnd, Vector2((float)ti.x / 100.0f, (float)ti.y / 100.0f), ti.dwID); } CloseTouchInputHandle((HTOUCHINPUT)lParam); } else { Error->WriteLine("WARNING: Error reading touchpoint info."); } return 0; } } break; case WM_SIZE: if (wnd->eventHandler) { wnd->eventHandler->OnSizeChanged(wnd); return 0; } break; case WM_CLOSE: if (wnd->eventHandler) { if (wnd->eventHandler->OnClosing(wnd)) return 0; } DestroyWindow(hWnd); break; case WM_QUIT: wnd->closed = true; if (wnd->eventHandler) { wnd->eventHandler->OnClosed(wnd); return 0; } break; case WM_DESTROY: PostQuitMessage(0); wnd->closed = true; if (wnd->eventHandler) { wnd->eventHandler->OnClosed(wnd); return 0; } break; } return DefWindowProc(hWnd, message, wParam, lParam); }
LRESULT CALLBACK DisplayProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_ACTIVATE: break; case WM_SETFOCUS: break; case WM_SIZE: break; case WM_ERASEBKGND: return DefWindowProc(hWnd, message, wParam, lParam); // Poor man's touch - mouse input. We send the data both as an input_state pointer, // and as asynchronous touch events for minimal latency. case WM_LBUTTONDOWN: { // Hack: Take the opportunity to show the cursor. mouseButtonDown = true; { lock_guard guard(input_state.lock); input_state.mouse_valid = true; input_state.pointer_down[0] = true; int factor = g_Config.iWindowZoom == 1 ? 2 : 1; input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor; input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor; } TouchInput touch; touch.id = 0; touch.flags = TOUCH_DOWN; touch.x = input_state.pointer_x[0]; touch.y = input_state.pointer_y[0]; NativeTouch(touch); SetCapture(hWnd); break; } case WM_MOUSEMOVE: { // Hack: Take the opportunity to show the cursor. mouseButtonDown = (wParam & MK_LBUTTON) != 0; int cursorX = GET_X_LPARAM(lParam); int cursorY = GET_Y_LPARAM(lParam); if (abs(cursorX - prevCursorX) > 1 || abs(cursorY - prevCursorY) > 1) { hideCursor = false; SetTimer(hwndMain, TIMER_CURSORMOVEUPDATE, CURSORUPDATE_MOVE_TIMESPAN_MS, 0); } prevCursorX = cursorX; prevCursorY = cursorY; { lock_guard guard(input_state.lock); int factor = g_Config.iWindowZoom == 1 ? 2 : 1; input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor; input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor; } if (wParam & MK_LBUTTON) { TouchInput touch; touch.id = 0; touch.flags = TOUCH_MOVE; touch.x = input_state.pointer_x[0]; touch.y = input_state.pointer_y[0]; NativeTouch(touch); } } break; case WM_LBUTTONUP: { // Hack: Take the opportunity to hide the cursor. mouseButtonDown = false; { lock_guard guard(input_state.lock); input_state.pointer_down[0] = false; int factor = g_Config.iWindowZoom == 1 ? 2 : 1; input_state.pointer_x[0] = GET_X_LPARAM(lParam) * factor; input_state.pointer_y[0] = GET_Y_LPARAM(lParam) * factor; } TouchInput touch; touch.id = 0; touch.flags = TOUCH_UP; touch.x = input_state.pointer_x[0]; touch.y = input_state.pointer_y[0]; NativeTouch(touch); ReleaseCapture(); break; } // Actual touch! Unfinished case WM_TOUCH: { // TODO: Enabling this section will probably break things on Windows XP. // We probably need to manually fetch pointers to GetTouchInputInfo and CloseTouchInputHandle. #if ENABLE_TOUCH UINT inputCount = LOWORD(wParam); TOUCHINPUT *inputs = new TOUCHINPUT[inputCount]; if (GetTouchInputInfo((HTOUCHINPUT)lParam, inputCount, inputs, sizeof(TOUCHINPUT))) { for (int i = 0; i < inputCount; i++) { // TODO: process inputs here! } if (!CloseTouchInputHandle((HTOUCHINPUT)lParam)) { // error handling } } else { // GetLastError() and error handling } delete [] inputs; return DefWindowProc(hWnd, message, wParam, lParam); #endif } case WM_PAINT: return DefWindowProc(hWnd, message, wParam, lParam); default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
LRESULT CALLBACK DisplayProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_ACTIVATE: break; case WM_SETFOCUS: break; case WM_SIZE: break; case WM_ERASEBKGND: return DefWindowProc(hWnd, message, wParam, lParam); case WM_LBUTTONDOWN: { lock_guard guard(input_state.lock); input_state.mouse_valid = true; input_state.pointer_down[0] = true; input_state.pointer_x[0] = GET_X_LPARAM(lParam); input_state.pointer_y[0] = GET_Y_LPARAM(lParam); if (g_Config.iWindowZoom == 1) { input_state.pointer_x[0] *= 2; input_state.pointer_y[0] *= 2; } } break; case WM_MOUSEMOVE: { lock_guard guard(input_state.lock); input_state.pointer_x[0] = GET_X_LPARAM(lParam); input_state.pointer_y[0] = GET_Y_LPARAM(lParam); if (g_Config.iWindowZoom == 1) { input_state.pointer_x[0] *= 2; input_state.pointer_y[0] *= 2; } } break; case WM_LBUTTONUP: { lock_guard guard(input_state.lock); input_state.pointer_down[0] = false; input_state.pointer_x[0] = GET_X_LPARAM(lParam); input_state.pointer_y[0] = GET_Y_LPARAM(lParam); if (g_Config.iWindowZoom == 1) { input_state.pointer_x[0] *= 2; input_state.pointer_y[0] *= 2; } } break; case WM_TOUCH: { // TODO: Enabling this section will probably break things on Windows XP. // We probably need to manually fetch pointers to GetTouchInputInfo and CloseTouchInputHandle. #if ENABLE_TOUCH UINT inputCount = LOWORD(wParam); TOUCHINPUT *inputs = new TOUCHINPUT[inputCount]; if (GetTouchInputInfo((HTOUCHINPUT)lParam, inputCount, inputs, sizeof(TOUCHINPUT))) { for (int i = 0; i < inputCount; i++) { // TODO: process inputs here! } if (!CloseTouchInputHandle((HTOUCHINPUT)lParam)) { // error handling } } else { // GetLastError() and error handling } delete [] inputs; return DefWindowProc(hWnd, message, wParam, lParam); #endif } case WM_PAINT: return DefWindowProc(hWnd, message, wParam, lParam); default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
static void OnMouseMessage(LCUI_Event ev, void *arg) { MSG *msg = arg; LCUI_SysEventRec sys_ev; static POINT mouse_pos = { 0, 0 }; sys_ev.type = LCUI_NONE; switch (msg->message) { case WM_MOUSEMOVE: { POINT new_pos; GetCursorPos(&new_pos); ScreenToClient(msg->hwnd, &new_pos); sys_ev.motion.x = new_pos.x; sys_ev.motion.y = new_pos.y; sys_ev.motion.xrel = new_pos.x - mouse_pos.x; sys_ev.motion.yrel = new_pos.y - mouse_pos.y; mouse_pos.x = new_pos.x; mouse_pos.y = new_pos.y; sys_ev.type = LCUI_MOUSEMOVE; break; } case WM_LBUTTONDOWN: sys_ev.type = LCUI_MOUSEDOWN; sys_ev.button.button = LCUI_KEY_LEFTBUTTON; sys_ev.button.x = mouse_pos.x; sys_ev.button.y = mouse_pos.y; SetCapture(msg->hwnd); break; case WM_LBUTTONUP: sys_ev.type = LCUI_MOUSEUP; sys_ev.button.button = LCUI_KEY_LEFTBUTTON; sys_ev.button.x = mouse_pos.x; sys_ev.button.y = mouse_pos.y; ReleaseCapture(); break; case WM_RBUTTONDOWN: sys_ev.type = LCUI_MOUSEDOWN; sys_ev.button.button = LCUI_KEY_RIGHTBUTTON; sys_ev.button.x = mouse_pos.x; sys_ev.button.y = mouse_pos.y; SetCapture(msg->hwnd); break; case WM_RBUTTONUP: sys_ev.type = LCUI_MOUSEUP; sys_ev.button.button = LCUI_KEY_RIGHTBUTTON; sys_ev.button.x = mouse_pos.x; sys_ev.button.y = mouse_pos.y; ReleaseCapture(); break; case WM_MOUSEWHEEL: sys_ev.type = LCUI_MOUSEWHEEL; sys_ev.wheel.x = mouse_pos.x; sys_ev.wheel.y = mouse_pos.y; sys_ev.wheel.delta = GET_WHEEL_DELTA_WPARAM(msg->wParam); break; #ifdef ENABLE_TOUCH_SUPPORT case WM_TOUCH: { UINT i, n = LOWORD(msg->wParam); PTOUCHINPUT inputs = NEW(TOUCHINPUT, n); HTOUCHINPUT handle = (HTOUCHINPUT)msg->lParam; if (inputs == NULL) { break; } sys_ev.type = LCUI_TOUCH; sys_ev.touch.n_points = n; sys_ev.touch.points = NEW(LCUI_TouchPointRec, n); if (sys_ev.touch.points == NULL) { free(inputs); break; } if (!GetTouchInputInfo(handle, n, inputs, sizeof(TOUCHINPUT))) { free(inputs); break; } for (i = 0; i < n; ++i) { POINT pos; pos.x = inputs[i].x / 100; pos.y = inputs[i].y / 100; ScreenToClient(msg->hwnd, &pos); sys_ev.touch.points[i].x = pos.x; sys_ev.touch.points[i].y = pos.y; sys_ev.touch.points[i].id = inputs[i].dwID; if (inputs[i].dwFlags & TOUCHEVENTF_PRIMARY) { sys_ev.touch.points[i].is_primary = TRUE; } else { sys_ev.touch.points[i].is_primary = FALSE; } if (inputs[i].dwFlags & TOUCHEVENTF_DOWN) { sys_ev.touch.points[i].state = LCUI_TOUCHDOWN; } else if (inputs[i].dwFlags & TOUCHEVENTF_UP) { sys_ev.touch.points[i].state = LCUI_TOUCHUP; } else if (inputs[i].dwFlags & TOUCHEVENTF_MOVE) { sys_ev.touch.points[i].state = LCUI_TOUCHMOVE; } } free(inputs); if (!CloseTouchInputHandle(handle)) { break; } break; } #endif default: break; } if (sys_ev.type != LCUI_NONE) { LCUI_TriggerEvent(&sys_ev, NULL); LCUI_DestroyEvent(&sys_ev); } }
// // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // Full redraw: draw complete collection of finished strokes and // also all the strokes that are currently in drawing. g_StrkColFinished.Draw(hdc); g_StrkColDrawing.Draw(hdc); EndPaint(hWnd, &ps); break; case WM_TOUCH: { // A WM_TOUCH message can contain several messages from different contacts // packed together. unsigned int numInputs = (int) wParam; // Number of actual per-contact messages TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; // Allocate the storage for the parameters of the per-contact messages // Unpack message parameters into the array of TOUCHINPUT structures, each // representing a message for one single contact. if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message // handler. for (unsigned int i=0; i<numInputs; ++i) { if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { OnTouchDownHandler(hWnd, ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { OnTouchMoveHandler(hWnd, ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { OnTouchUpHandler(hWnd, ti[i]); } } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] ti; } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
LRESULT WinWindow::WndProc(UINT message, WPARAM wParam, LPARAM lParam) { SetFocus(mWindowHandle); switch (message) { case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(mWindowHandle, &ps); EndPaint(mWindowHandle, &ps); } break; case WM_DESTROY: //DestroyWindow(hWnd); PostQuitMessage(0); break; case WM_LBUTTONDOWN: if (MK_LBUTTON == wParam) { SetCapture(mWindowHandle); short xi = Math::ClampAboveZero((short)LOWORD(lParam)); short yi = Math::ClampAboveZero((short)HIWORD(lParam)); float x = Math::Clamp((float)xi, 0.f, mSize.Width); float y = mSize.Height - Math::Clamp((float)yi, 0.f, mSize.Height); double timeStamp = Application::Instance().TimeStamp(); Touch touch(TouchPhase::Began, 0, timeStamp, mpp(x, y), Point2F::Zero); TouchEventArg e(TouchPhase::Began, touch); InputManager::Instance().TouchesBegan(e); mPrevMouseTouch = touch; } break; case WM_MOUSEMOVE: if (MK_LBUTTON == wParam) { short xi = Math::ClampAboveZero((short)LOWORD(lParam)); short yi = Math::ClampAboveZero((short)HIWORD(lParam)); float x = Math::Clamp((float)xi, 0.f, mSize.Width); float y = mSize.Height - Math::Clamp((float)yi, 0.f, mSize.Height); double timeStamp = Application::Instance().TimeStamp(); Touch touch(TouchPhase::Moved, 0, timeStamp, mpp(x, y), mPrevMouseTouch.Pos); TouchEventArg e(TouchPhase::Moved, touch); InputManager::Instance().TouchesMoved(e); mPrevMouseTouch = touch; } else { short xi = Math::ClampAboveZero((short)LOWORD(lParam)); short yi = Math::ClampAboveZero((short)HIWORD(lParam)); float x = Math::Clamp((float)xi, 0.f, mSize.Width); float y = mSize.Height - Math::Clamp((float)yi, 0.f, mSize.Height); ApplicationStatics::Instance().SetDebugTouch(mpp(x, y)); } break; case WM_LBUTTONUP: { short xi = Math::ClampAboveZero((short)LOWORD(lParam)); short yi = Math::ClampAboveZero((short)HIWORD(lParam)); float x = Math::Clamp((float)xi, 0.f, mSize.Width); float y = mSize.Height - Math::Clamp((float)yi, 0.f, mSize.Height); double timeStamp = Application::Instance().TimeStamp(); Touch touch(TouchPhase::Ended, 0, timeStamp, mpp(x, y), mPrevMouseTouch.Pos); TouchEventArg e(TouchPhase::Ended, touch); InputManager::Instance().TouchesEnded(e); ReleaseCapture(); mPrevMouseTouch = Touch::Zero; } break; case WM_TOUCH: { unsigned int numInputs = (unsigned int)wParam; TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // Handle each contact point for (unsigned int i = 0; i < numInputs; ++i) { /* handle ti[i] */ } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete[] ti; } break; case WM_GESTURE: { GESTUREINFO gi; ZeroMemory(&gi, sizeof(GESTUREINFO)); gi.cbSize = sizeof(gi); BOOL bResult = GetGestureInfo((HGESTUREINFO)lParam, &gi); bool isHandled = false; if (bResult) { switch (gi.dwID) { case GID_BEGIN: break; case GID_END: break; case GID_ZOOM: // Code for zooming goes here isHandled = true; break; case GID_PAN: // Code for panning goes here isHandled = true; break; case GID_ROTATE: // Code for rotation goes here isHandled = true; break; case GID_TWOFINGERTAP: // Code for two-finger tap goes here isHandled = true; break; case GID_PRESSANDTAP: // Code for roll over goes here isHandled = true; break; default: // A gesture was not recognized break; } } else { DWORD dwErr = GetLastError(); if (dwErr > 0) { MessageBoxW(mWindowHandle, L"Error!", L"Could not retrieve a GESTUREINFO structure.", MB_OK); } } CloseGestureInfoHandle((HGESTUREINFO)lParam); if (isHandled) { return 0; } else { return DefWindowProc(mWindowHandle, message, wParam, lParam); } } break; case WM_SIZE: switch (wParam) { case SIZE_RESTORED: case SIZE_MAXIMIZED: { Size2F newSize; newSize.Width = (float)LOWORD(lParam); newSize.Height = (float)HIWORD(lParam); OnResize(newSize); Application::Instance().Wakeup(); Application::Instance().Resume(); } break; case SIZE_MINIMIZED: Application::Instance().Pause(); Application::Instance().Sleep(); break; } break; case WM_KEYDOWN: { KeyDownEventArg e((uint)wParam, (uint)lParam); InputManager::Instance().KeyDown(e); } break; case WM_KEYUP: { KeyUpEventArg e((uint)wParam, (uint)lParam); InputManager::Instance().KeyUp(e); } break; case WM_CHAR: { CharInputEventArg e((uint)wParam, (uint)lParam); InputManager::Instance().CharInput(e); } break; case WM_MOUSEWHEEL: { short scrollPos = (short)HIWORD(wParam); short key = (short)LOWORD(wParam); ScrollEventArg e(scrollPos, key); InputManager::Instance().Scroll(e); } break; default: return DefWindowProc(mWindowHandle, message, wParam, lParam); } return 0; }
void InputTouchCheck( UINT iMsg , WPARAM wParam ,LPARAM lParam ) { //タッチ情報の更新 TOUCHINPUT touch[CPadManager::enTouchMax ]; int num= LOWORD( wParam ); HTOUCHINPUT hinput= reinterpret_cast<HTOUCHINPUT>( lParam ); if( GetTouchInputInfo( hinput, num, &touch[0], sizeof(TOUCHINPUT) ) ) { for( int ii= 0 ; ii< num ; ii++ ) { TOUCHINPUT* p= &touch[ii]; gxBool bFind = gxFalse; //スクリーン座標に変換する POINT pt; pt.x = p->x/100; pt.y = p->y/100; ScreenToClient( g_pWindows->m_hWindow , &pt ); //どれを更新するか? for( Sint32 jj=0; jj<CPadManager::enTouchMax; jj++) { if( p->dwID == m_pTouchDevice[jj].id ) { //既にタッチされているものが更新された Sint32 n = jj; bFind = gxTrue; // m_pTouchDevice[jj].nx = pt.x; // m_pTouchDevice[jj].ny = pt.y; m_pTouchDevice[jj].x = pt.x; m_pTouchDevice[jj].y = pt.y; m_pTouchDevice[jj].psh = gxTrue; m_pTouchDevice[jj].bUse = gxTrue; if( p->dwFlags&TOUCHEVENTF_UP ) { // m_pTouchDevice[jj].ex = pt.x; // m_pTouchDevice[jj].ey = pt.y; m_pTouchDevice[jj].x = pt.x; m_pTouchDevice[jj].y = pt.y; m_pTouchDevice[jj].psh = gxFalse; } break; } } if( bFind ) { continue; } //新規IDがきた for( Sint32 jj=0; jj<CPadManager::enTouchMax; jj++) { if( !m_pTouchDevice[jj].bUse ) { //使っていないものを発見した m_pTouchDevice[jj].id = p->dwID; m_pTouchDevice[jj].bUse = gxTrue; // m_pTouchDevice[jj].sx = pt.x; // m_pTouchDevice[jj].sy = pt.y; // m_pTouchDevice[jj].nx = m_pTouchDevice[ii].sx; // m_pTouchDevice[jj].ny = m_pTouchDevice[ii].sy; m_pTouchDevice[jj].x = pt.x; m_pTouchDevice[jj].y = pt.y; m_pTouchDevice[jj].psh = gxTrue; break; } } //開いてるのがないから無視する // ... } } }
void WMTouchPlugin::onTouch(HWND hWnd, WPARAM wParam, LPARAM lParam) { BOOL bHandled = FALSE; UINT cInputs = LOWORD(wParam); PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs]; if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))){ AC_DEBUG << "found " << cInputs << " Cursors!"; for (UINT i=0; i < cInputs; i++){ const TOUCHINPUT & ti = pInputs[i]; // create a y60 event for each InputInfo GenericEventPtr myEvent(new GenericEvent("onWMTouch", _myEventSchemaDocument, _myEventValueFactory)); NodePtr myNode = myEvent->getNode(); asl::Vector2f myPosition = product(Vector2f(static_cast<float>(ti.x), static_cast<float>(ti.y)), 0.01f); asl::Vector2f myCalibratedRelativePosition = asl::Vector2f(0.0, 0.0); float myWidth = _calibrationPositionTopRight[0] - _calibrationPositionBottomLeft[0]; float myHeight = _calibrationPositionTopRight[1] - _calibrationPositionBottomLeft[1]; if (myWidth != 0) { myCalibratedRelativePosition[0] = (myPosition[0] - _calibrationPositionBottomLeft[0]) / myWidth; } if (myHeight != 0) { myCalibratedRelativePosition[1] = (myPosition[1] - _calibrationPositionBottomLeft[1]) / myHeight; } myNode->appendAttribute<int>("id", ti.dwID); myNode->appendAttribute<Vector2f>("position", myPosition); myNode->appendAttribute<Vector2f>("calibrated_relative_position", myCalibratedRelativePosition); if (ti.dwMask & TOUCHINPUTMASKF_CONTACTAREA) { myNode->appendAttribute<Vector2f>("contactarea", product(Vector2f(static_cast<float>(ti.cxContact), static_cast<float>(ti.cyContact)), 0.01f)); } myNode->appendAttribute<bool>("inrange", (ti.dwFlags & TOUCHEVENTF_INRANGE) != 0); myNode->appendAttribute<bool>("primary", (ti.dwFlags & TOUCHEVENTF_PRIMARY) != 0); myNode->appendAttribute<bool>("nocoalesce", (ti.dwFlags & TOUCHEVENTF_NOCOALESCE) != 0); myNode->appendAttribute<bool>("palm", (ti.dwFlags & TOUCHEVENTF_PALM) != 0); // Note: we seem to be getting duplicate events, probably due to the way we are hooking the msg queue. // So we filter the events here. Only queue a DOWN event if the cursor wasn't down yet, // and only queue an UP or MOVE event if the cursor was down. if ((ti.dwFlags & TOUCHEVENTF_DOWN) != 0 && _downCursors.find(ti.dwID) == _downCursors.end()) { myNode->appendAttribute<DOMString>("type", "down"); _queuedEvents.push_back(myEvent); _downCursors.insert(ti.dwID); } else if ((ti.dwFlags & TOUCHEVENTF_UP) != 0 && _downCursors.find(ti.dwID) != _downCursors.end()) { myNode->appendAttribute<DOMString>("type", "up"); _queuedEvents.push_back(myEvent); _downCursors.erase(ti.dwID); } else if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0 && _downCursors.find(ti.dwID) != _downCursors.end()) { _queuedEvents.push_back(myEvent); myNode->appendAttribute<DOMString>("type", "move"); } } bHandled = TRUE; }else{ /* handle the error here */ AC_ERROR << errorDescription(lastError()); } // clean up delete [] pInputs; if (bHandled){ // if you handled the message, close the touch input handle and return CloseTouchInputHandle((HTOUCHINPUT)lParam); return; } };
static LRESULT CALLBACK GetMsgProc(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { switch(code) { case HC_ACTION: { LPMSG msg = (LPMSG)lParam; //for (HandleList::iterator it = s_windows->begin(); it != s_windows->end(); ++it) //{ // RegisterTouchWindow(*it, TOUCH_FLAGS); //} /* if(keyboardHandle != NULL) { FixWindowForTouch(keyboardHandle); } */ // to register all windows as touch-capable /* if (msg->hwnd != 0) { bool found = false; for (int i = 0; i < registeredWindows.size(); ++i) if (registeredWindows[i] == msg->hwnd) { found = true; break; } if (!found) { RegisterTouchWindow(msg->hwnd, TOUCH_FLAGS); char buf[10240]; sprintf(buf, "registering %d; adr = %x\n", msg->hwnd, windowsToRegister); trace(buf); registeredWindows.push_back(msg->hwnd); } } */ /* while (windowsToRegister.size() > 0) { RegisterTouchWindow(windowsToRegister.back(), TOUCH_FLAGS); // register also all child windows to receive touch long userData = 0; EnumChildWindows(windowsToRegister.back(), enumChildWindowsCallback, userData); windowsToRegister.pop_back(); } */ /* char buf[10240]; sprintf(buf, "searching %d, size = %d adr = %x\n", msg->hwnd, wtrCount, windowsToRegister); trace(buf); */ #if 0 int pos = -1; for (int i = 0; i < /*windowsToRegister.size()*/wtrCount; ++i) { /* char buf[10240]; sprintf(buf, "vector[%d] = %d\n", i, windowsToRegister[i]); trace(buf); */ if (windowsToRegister[i] == msg->hwnd) { /* char buf[10240]; sprintf(buf, "is found in vector at pos: %d\n", i); trace(buf); */ pos = i; } } //std::vector<HWND>::iterator pos = std::find(windowsToRegister.begin(), windowsToRegister.end(), msg->hwnd); //if (pos != windowsToRegister.end()) if (pos >= 0) { RegisterTouchWindow(msg->hwnd, TOUCH_FLAGS); //windowsToRegister.erase(pos); for (int i = pos + 1; i < wtrCount; ++i) windowsToRegister[i - 1] = windowsToRegister[i]; --wtrCount; /* char buf[10240]; sprintf(buf, "registering known window %d\n", msg->hwnd); trace(buf); */ FILE* trace = fopen("c:\\patrice\\patrice.txt", "a"); if (trace != 0) { TCHAR windowTitle[1024]; GetWindowText(msg->hwnd, windowTitle, 1024); TCHAR className[1024]; GetClassName(msg->hwnd, className, 1024); fwprintf(trace, L"%s - %s\n", windowTitle, className); fclose(trace); } } #endif //if (!IsTouchWindow(msg->hwnd, NULL)) //{ // if (RegisterTouchWindow(msg->hwnd, TOUCH_FLAGS)) // { // touchRegistered = true; // } //} //TMP //FixWindowForTouch(msg->hwnd); //END TMP // a window is candidate for registering for touch (or back to gesture) // if its class is TmioEngineWin or Internet Explorer_Server // and the window or one of its ancertors has been declared with TouchEnable or GestureEnable HWND hwnd = msg->hwnd; TCHAR className[1024]; if (hwnd != 0 && GetClassName(hwnd, className, 1024)) { if (wcsncmp(className, L"TmioEngineWin", 1024) == 0 || wcsncmp(className, L"Internet Explorer_Server", 1024) == 0) { while (hwnd != 0) // loop thru ancestors { int i = findWindowHandle(hwnd); if (i != -1) { if (isTouch[i]) FixWindowForTouch(msg->hwnd); else FixWindowForGesture(msg->hwnd); break; } hwnd = GetParent(hwnd); } } } switch(msg->message) { case WM_TOUCH: { // WM_TOUCH message can contain several messages from different contacts // packed together. // Message parameters need to be decoded: unsigned int numInputs = (unsigned int) msg->wParam; // Number of actual per-contact messages TOUCHINPUT* ti = new TOUCHINPUT[numInputs]; // Allocate the storage for the parameters of the per-contact messages if (ti == NULL) { break; } //int maxTouchInputs = GetSystemMetrics(SM_MAXIMUMTOUCHES); // Unpack message parameters into the array of TOUCHINPUT structures, each // representing a message for one single contact. if (GetTouchInputInfo((HTOUCHINPUT)msg->lParam, numInputs, ti, sizeof(TOUCHINPUT))) { // For each contact, dispatch the message to the appropriate message // handler. for (unsigned int i = 0; i < numInputs; ++i) { if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { OnTouchDownHandler(msg->hwnd, ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { OnTouchMoveHandler(msg->hwnd, ti[i]); } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { OnTouchUpHandler(msg->hwnd, ti[i]); } } } CloseTouchInputHandle((HTOUCHINPUT)lParam); delete [] ti; } break; /* case WM_GESTURE: { trace("WM_GESTURE\n"); } break; */ case WM_QUIT: UninitializeTouch(); break; case WM_APP + 5: int arg0 = LOWORD(msg->wParam); int arg1 = HIWORD(msg->wParam); int arg2 = LOWORD(msg->lParam); int arg3 = HIWORD(msg->lParam); if(arg0 == EX_DESTROYWINDOW) { DestroyWindow((HWND)msg->lParam); } break; } break; } } } return CallNextHookEx(0, code, wParam, lParam); }
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { //sprintf_s(s_buf, "GetMsgProc\n"); //WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); if (!s_initialized) { if (!AttachConsole(g_consoleId)) { FreeConsole(); AttachConsole(g_consoleId); } s_out = GetStdHandle(STD_OUTPUT_HANDLE); // TODO: we don't really close it sprintf_s(s_buf, "Attached console\n"); WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); if (!g_mouseHook) { g_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, g_this, 0); // mouse_ll global only (requires process with message loop) if (g_mouseHook) { sprintf_s(s_buf, "Installed mouse hook\n"); WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); } else { sprintf_s(s_buf, "Could not install mouse hook\n"); WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); } } if (g_detect_screen_size) { HWND win = GetDesktopWindow(); RECT rec; GetWindowRect(win, &rec); g_screen_height = rec.bottom; g_screen_width = rec.right; } sprintf_s(s_buf, "X-Offset: %i Y-Offset: %i Width: %i Height: %i\n", g_screen_offsetX, g_screen_offsetY, g_screen_width, g_screen_height); WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); s_cursors.reset(new CursorMap); s_cursorBuf.reset(new CursorMap); s_server.reset(new TUIO::TuioServer(g_host, g_serverPort)); sprintf_s(s_buf, "Created server (%s:%i)\n", g_host, g_serverPort); WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); s_timer = SetTimer(g_targetWnd, TIMER_IDENTIFIER, TIMER_CALL_TIME, 0); s_initialized = true; } if (nCode < 0) // do not process message { return CallNextHookEx(0, nCode, wParam, lParam); } switch (nCode) { case HC_ACTION: { LPMSG msg = (LPMSG)lParam; // register everything for touch // Note: pretty ugly but seems to be the only possibility to register every window RegisterTouchWindow(msg->hwnd, TOUCH_FLAGS); switch (msg->message) { case WM_TOUCH: { //sprintf_s(s_buf, "Touches received:\n"); //WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); UINT cInputs = LOWORD(msg->wParam); PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs]; if (NULL != pInputs) { if (GetTouchInputInfo((HTOUCHINPUT)msg->lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) { s_server->initFrame(TUIO::TuioTime::getSessionTime()); // process pInputs for (UINT i=0; i<cInputs; ++i) { //sprintf_s(s_buf, "ID: %i, X: %i, Y: %i\n", pInputs[i].dwID, pInputs[i].x, pInputs[i].y); //WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); std::map<DWORD, TUIO::TuioCursor*>::iterator cursorIt = s_cursors->find(pInputs[i].dwID); if (cursorIt != s_cursors->end()) { // found s_server->updateTuioCursor(cursorIt->second, ((pInputs[i].x*0.01f)+g_screen_offsetX)/(float)(g_screen_width+g_screen_offsetX), ((pInputs[i].y*0.01f)+g_screen_offsetY)/(float)(g_screen_height+g_screen_offsetY)); (*s_cursorBuf)[pInputs[i].dwID] = cursorIt->second; s_cursors->erase(cursorIt); } else { // not found (*s_cursorBuf)[pInputs[i].dwID] = s_server->addTuioCursor( ((pInputs[i].x*0.01f)+g_screen_offsetX)/(float)(g_screen_width+g_screen_offsetX), ((pInputs[i].y*0.01f)+g_screen_offsetY)/(float)(g_screen_height+g_screen_offsetY)); } } for (std::map<DWORD, TUIO::TuioCursor*>::iterator it = s_cursors->begin(); it != s_cursors->end(); ++it) { s_server->removeTuioCursor(it->second); } s_cursors->clear(); std::auto_ptr<CursorMap> tmp(s_cursorBuf); s_cursorBuf = s_cursors; s_cursors = tmp; s_server->commitFrame(); } } delete[] pInputs; } break; case WM_TIMER: { //if (msg->wParam == TIMER_IDENTIFIER) //{ BOOL frameOpen(false); for (std::map<DWORD, TUIO::TuioCursor*>::iterator it = s_cursors->begin(); it != s_cursors->end();) { long delta = TUIO::TuioTime::getSessionTime().getTotalMilliseconds() - it->second->getTuioTime().getTotalMilliseconds(); if (delta > MAX_CURSOR_IDLE_TIME) { if (!frameOpen) { s_server->initFrame(TUIO::TuioTime::getSessionTime()); frameOpen = true; } s_server->removeTuioCursor(it->second); std::map<DWORD, TUIO::TuioCursor*>::iterator tmp = it++; s_cursors->erase(tmp); //sprintf_s(s_buf, "Removed cursor due to time limit\n"); //WriteConsole(s_out, s_buf, strlen(s_buf), &s_ccount, 0); } else { ++it; } } if (frameOpen) { s_server->commitFrame(); } //} } break; } } break; } return CallNextHookEx(0, nCode, wParam, lParam); }
// Processes messages for main Window LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { PTOUCHINPUT pInputs; TOUCHINPUT tInput; HTOUCHINPUT hInput; int iNumContacts; POINT ptInputs; PAINTSTRUCT ps; // Handle each type of inData and based on which event we handle continue processing // the inData for manipulations by calling the ComTouchDriver switch (msg) { case WM_TOUCH: iNumContacts = LOWORD(wParam); hInput = (HTOUCHINPUT)lParam; pInputs = new (std::nothrow) TOUCHINPUT[iNumContacts]; // Get each touch input info and feed each TOUCHINPUT into the process input handler if(pInputs != NULL) { if(GetTouchInputInfo(hInput, iNumContacts, pInputs, sizeof(TOUCHINPUT))) { for(int i = 0; i < iNumContacts; i++) { // Bring touch input info into client coordinates ptInputs.x = pInputs[i].x/100; ptInputs.y = pInputs[i].y/100; ScreenToClient(g_hWnd, &ptInputs); pInputs[i].x = ptInputs.x; pInputs[i].y = ptInputs.y; g_ctDriver->ProcessInputEvent(&pInputs[i]); } g_ctDriver->ProcessChanges(); } } delete [] pInputs; CloseTouchInputHandle(hInput); break; // For each Mouse event build a TOUCHINPUT struct and feed into the process input handler case WM_LBUTTONDOWN: FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_DOWN, (DWORD)GetMessageTime(),LOWORD(lParam),HIWORD(lParam)); g_ctDriver->ProcessInputEvent(&tInput); break; case WM_MOUSEMOVE: if(LOWORD(wParam) == MK_LBUTTON) { FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_MOVE, (DWORD)GetMessageTime(),LOWORD(lParam), HIWORD(lParam)); g_ctDriver->ProcessInputEvent(&tInput); g_ctDriver->ProcessChanges(); } break; case WM_LBUTTONUP: FillInputData(&tInput, MOUSE_CURSOR_ID, TOUCHEVENTF_UP, (DWORD)GetMessageTime(),LOWORD(lParam), HIWORD(lParam)); g_ctDriver->ProcessInputEvent(&tInput); break; case WM_DESTROY: if(g_ctDriver) { delete g_ctDriver; } PostQuitMessage(0); return 1; case WM_SIZE: g_iCWidth = LOWORD(lParam); g_iCHeight = HIWORD(lParam); break; case WM_PAINT: BeginPaint(g_hWnd, &ps); g_ctDriver->RenderInitialState(g_iCWidth, g_iCHeight); EndPaint(g_hWnd, &ps); break; case WM_TIMER: g_ctDriver->ProcessChanges(); break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; }