#include "pch.h" #ifdef ICAP #include "..\..\extern\icecap4\include\icecap.h" #endif ///////////////////////////////////////////////////////////////////////////// // // Handy painting function // ///////////////////////////////////////////////////////////////////////////// void FillSolidRect(HDC hdc, const WinRect& rect, COLORREF color) { HBRUSH hbrush = CreateSolidBrush(color); ::FillRect(hdc, &rect, hbrush); DeleteObject(hbrush); } ////////////////////////////////////////////////////////////////////////////// // // Window // ////////////////////////////////////////////////////////////////////////////// void Window::Construct() { m_pfnWndProc = DefWindowProc; m_bHit = false; m_bShowMouse = true; m_bMouseInside = false; m_sizeMin = WinPoint(0, 0); m_hcursor = NULL; } Window::Window(): m_pwindowParent(NULL), m_hmenu(NULL), m_hwnd(NULL), m_bSizeable(false), m_bHasMinimize(false), m_bHasMaximize(false), m_bHasSysMenu(false), m_bTopMost(false), m_nID(0) { Construct(); } Window::Window( Window* pwindowParent, const WinRect& rect, const ZString& strTitle, const ZString& strClass, Style style, HMENU hmenu, StyleEX styleEX ) : m_pwindowParent(pwindowParent), m_style(style), m_styleEX(styleEX), m_hmenu(hmenu), m_bSizeable(true), m_bHasSysMenu(false), m_bTopMost(false), m_bHasMinimize(true), m_bHasMaximize(true) { Construct(); if (m_pwindowParent) { m_style.Set(StyleChild()); } else { m_style.Set( StylePopup() | StyleCaption() | StyleMaximizeBox() | StyleMinimizeBox() | StyleSysMenu() | StyleThickFrame() ); // set a default arrow cursor for topmost windows m_hcursor = LoadCursor(NULL, IDC_ARROW); } m_style.Set(StyleVisible() | StyleClipChildren() | StyleClipSiblings()); m_rect = rect; AdjustWindowRect(&m_rect, m_style.GetWord(), m_hmenu != NULL); if (strClass.IsEmpty()) { m_hwnd = ::CreateWindowEx( m_styleEX.GetWord(), TEXT(GetTopLevelWindowClassname()), #ifdef DREAMCAST TEXT("Title"), #else strTitle, #endif m_style.GetWord(), CW_USEDEFAULT, CW_USEDEFAULT, //m_rect.XMin(), m_rect.YMin(), m_rect.XSize(), m_rect.YSize(), pwindowParent ? pwindowParent->GetHWND() : NULL, m_hmenu, GetModuleHandle(NULL), this ); } else { m_hwnd = ::CreateWindowEx( m_styleEX.GetWord(), #ifdef DREAMCAST TEXT("Window"), TEXT("Title"), #else strClass, strTitle, #endif m_style.GetWord(), CW_USEDEFAULT, CW_USEDEFAULT, //m_rect.XMin(), m_rect.YMin(), m_rect.XSize(), m_rect.YSize(), pwindowParent ? pwindowParent->GetHWND() : NULL, m_hmenu, GetModuleHandle(NULL), this ); s_mapWindow.Set(m_hwnd, this); m_pfnWndProc = (WNDPROC)::GetWindowLong(m_hwnd, GWL_WNDPROC); ::SetWindowLong(m_hwnd, GWL_WNDPROC, (DWORD)Win32WndProc); } m_styleEX.SetWord(::GetWindowLong(m_hwnd, GWL_EXSTYLE)); if (m_pwindowParent) { m_pwindowParent->AddChild(this); } } BOOL Window::Create( Window* pwindowParent, const WinRect& rect, LPCSTR szTitle, LPCSTR szClass, Style style, HMENU hmenu, UINT nID, StyleEX styleEX ) { Construct(); m_style.Set(style); m_styleEX.Set(styleEX); m_style.Set(StyleVisible() | StyleClipChildren() | StyleClipSiblings()); m_rect = rect; m_pwindowParent = pwindowParent; m_hmenu = hmenu; m_nID = nID; if (!m_pwindowParent) { // set a default arrow cursor for topmost windows m_hcursor = LoadCursor(NULL, IDC_ARROW); } m_hwnd = ::CreateWindowEx( styleEX.GetWord(), #ifdef DREAMCAST TEXT("Window"), TEXT("Title"), #else szClass ? szClass : "Window", szTitle, #endif m_style.GetWord(), m_rect.left, m_rect.top, m_rect.XSize(), m_rect.YSize(), pwindowParent ? pwindowParent->GetHWND() : NULL, hmenu ? hmenu : (HMENU) nID, GetModuleHandle(NULL), this); s_mapWindow.Set(m_hwnd, this); m_pfnWndProc = (WNDPROC)::GetWindowLong(m_hwnd, GWL_WNDPROC); if ((WNDPROC)m_pfnWndProc != (WNDPROC)Win32WndProc) { ::SetWindowLong(m_hwnd, GWL_WNDPROC, (DWORD)Win32WndProc); } else { m_pfnWndProc = DefWindowProc; } m_styleEX.SetWord(::GetWindowLong(m_hwnd, GWL_EXSTYLE)); ::GetClientRect(GetHWND(), &m_rectClient); return TRUE; } Window::~Window() { DestroyWindow(m_hwnd); s_mapWindow.Remove(m_hwnd); EnableIdleFunction(false); } ////////////////////////////////////////////////////////////////////////////// // // Sizing // ////////////////////////////////////////////////////////////////////////////// void Window::CalcStyle() { if (m_bTopMost) { m_styleEX.Set(StyleEXTopMost()); } else { m_styleEX.Clear(StyleEXTopMost()); } if (m_bSizeable) { m_style.Clear(StyleBorder()); m_style.Set(StyleThickFrame()); } else { m_style.Clear(StyleThickFrame()); m_style.Set(StyleBorder()); } if (m_bHasMaximize) { m_style.Set(StyleMaximizeBox()); } else { m_style.Clear(StyleMaximizeBox()); } if (m_bHasMinimize) { m_style.Set(StyleMinimizeBox()); } else { m_style.Clear(StyleMinimizeBox()); } if (m_bHasMinimize || m_bHasMaximize || m_bSizeable) { m_style.Set(StyleCaption()); } else { m_style.Clear(StyleCaption()); } if (m_bHasSysMenu) { m_style.Set(StyleSysMenu()); } else { m_style.Clear(StyleSysMenu()); } ::SetWindowLong(m_hwnd, GWL_STYLE, m_style.GetWord()); ::SetWindowLong(m_hwnd, GWL_EXSTYLE, m_styleEX.GetWord()); } void Window::SetTopMost(bool bTopMost) { ZAssert(m_pwindowParent == NULL); //if (m_bTopMost != bTopMost) { m_bTopMost = bTopMost; CalcStyle(); //} } void Window::SetSizeable(bool bSizeable) { ZAssert(m_pwindowParent == NULL); if (m_bSizeable != bSizeable) { m_bSizeable = bSizeable; CalcStyle(); } } void Window::SetHasMinimize(bool bHasMinimize) { if (m_bHasMinimize != bHasMinimize) { m_bHasMinimize = bHasMinimize; CalcStyle(); } } void Window::SetHasMaximize(bool bHasMaximize) { if (m_bHasMaximize != bHasMaximize) { m_bHasMaximize = bHasMaximize; CalcStyle(); } } void Window::SetHasSysMenu(bool bSysMenu) { if (m_bHasSysMenu != bSysMenu) { m_bHasSysMenu = bSysMenu; CalcStyle(); } } void Window::UpdateRect() { ::GetWindowRect(m_hwnd, &m_rect); ::GetClientRect(m_hwnd, &m_rectClient); WinPoint pointOffset = ClientToScreen(WinPoint(0, 0)); if (m_pwindowParent) { pointOffset = m_pwindowParent->ScreenToClient(pointOffset); } m_rectClient.Offset(pointOffset); if (m_pwindowParent) { m_pwindowParent->ChildRectChanged(this); } } void Window::ChildRectChanged(Window* pchild) { } void Window::RectChanged() { } void Window::SetRect(const WinRect& rect) { MoveWindow(m_hwnd, rect.XMin(), rect.YMin(), rect.XSize(), rect.YSize(), true); } void Window::SetClientRect(const WinRect& rectClient) { WinRect rect = rectClient; AdjustWindowRect(&rect, m_style.GetWord(), m_hmenu != NULL); SetRect(rect); } void Window::SetPosition(const WinPoint& point) { SetWindowPos(m_hwnd, NULL, point.X(), point.Y(), 0, 0, SWP_NOSIZE | SWP_NOZORDER); } void Window::SetSize(const WinPoint& point) { SetWindowPos(m_hwnd, NULL, 0, 0, point.X(), point.Y(), SWP_NOMOVE | SWP_NOZORDER); } void Window::SetClientSize(const WinPoint& point) { WinRect rect = GetClientRect(); rect.SetSize(point); SetClientRect(rect); } void Window::SetMinimumClientSize(const WinPoint& point) { WinRect rect(WinPoint(0, 0), point); AdjustWindowRect(&rect, m_style.GetWord(), m_hmenu != NULL); m_sizeMin = rect.Size(); } ////////////////////////////////////////////////////////////////////////////// // // Children // ////////////////////////////////////////////////////////////////////////////// void Window::AddChild(Window* pchild) { ZAssert(pchild != NULL); m_listChildren.PushFront(pchild); } void Window::RemoveChild(Window* pchild) { ZAssert(m_listChildren.Find(pchild)); m_listChildren.Remove(pchild); } void Window::RemoveAllChildren() { m_listChildren.SetEmpty(); } ////////////////////////////////////////////////////////////////////////////// // // Input // ////////////////////////////////////////////////////////////////////////////// TList > g_listKeyboardInputFilters; void Window::AddKeyboardInputFilter(IKeyboardInput* pkeyboardInput) { g_listKeyboardInputFilters.PushEnd(pkeyboardInput); } void Window::RemoveKeyboardInputFilter(IKeyboardInput* pkeyboardInput) { g_listKeyboardInputFilters.Remove(pkeyboardInput); } ////////////////////////////////////////////////////////////////////////////// // // Timers // ////////////////////////////////////////////////////////////////////////////// class Timer : public IObjectSingle { public: Time m_when; float m_delta; TRef m_psink; Timer(IEventSink* psink, float delta, Time when) : m_psink(psink), m_delta(delta), m_when(when) { } bool Trigger(Time now) { return m_psink->OnEvent(NULL); } }; class TimerCompare { public: bool operator () (const Timer* ptimer1, const Timer* ptimer2) { return ptimer1->m_when > ptimer2->m_when; } }; class TimerEquals { public: bool operator () (const Timer* ptimer1, const Timer* ptimer2) { return ptimer1->m_psink == ptimer2->m_psink; } }; typedef TList, TimerEquals, TimerCompare> TimerList; TimerList g_listTimers; void CallTimers() { Time now = Time::Now(); while (g_listTimers.GetCount() != 0) { TRef ptimer = g_listTimers.GetFront(); if (now < ptimer->m_when) { break; } g_listTimers.PopFront(); if (ptimer->Trigger(now)) { g_listTimers.InsertSorted( new Timer( ptimer->m_psink, ptimer->m_delta, Time::Now() + ptimer->m_delta ) ); } } } void Window::AddSink(IEventSink* psink) { AddSink(psink, 1.0f); } void Window::AddSink(IEventSink* psink, float delta) { g_listTimers.InsertSorted(new Timer(psink, delta, Time::Now() + delta)); } void Window::RemoveSink(IEventSink* psink) { g_listTimers.Remove(new Timer(psink, 0, 0)); } ITimerEventSource* Window::GetTimer() { return this; } ////////////////////////////////////////////////////////////////////////////// // // Keyboard // ////////////////////////////////////////////////////////////////////////////// bool Window::OnKey(const KeyState& ks) { bool bTranslate = false; if (m_pkeyboardInputFocus) { if (m_pkeyboardInputFocus->OnKey(this, ks, bTranslate) && !bTranslate) { return true; } } return false; } bool Window::OnChar(const KeyState& ks) { if (m_pkeyboardInputFocus) { if (m_pkeyboardInputFocus->OnChar(this, ks)) { return true; } } return false; } bool Window::IsFocus(IKeyboardInput* pinput) { return m_pkeyboardInputFocus == pinput; } IKeyboardInput* Window::GetFocus() { return m_pkeyboardInputFocus; } void Window::SetFocus(IKeyboardInput* pinput) { if (m_pkeyboardInputFocus != NULL) { m_pkeyboardInputFocus->SetFocusState(false); } m_pkeyboardInputFocus = pinput; m_pkeyboardInputFocus->SetFocusState(true); } void Window::RemoveFocus(IKeyboardInput* pinput) { ZAssert(m_pkeyboardInputFocus == pinput); m_pkeyboardInputFocus->SetFocusState(false); m_pkeyboardInputFocus = NULL; } ////////////////////////////////////////////////////////////////////////////// // // Mouse // ////////////////////////////////////////////////////////////////////////////// PFNTrackMouseEvent Window::s_pfnTrackMouseEvent; bool Window::OnMouseMessage(UINT message, UINT nFlags, const WinPoint& pointArg) { return true; } void Window::SetCursorPos(const Point& point) { WinPoint pointScreen( (int)point.X(), m_rectClient.YSize() - 1 - (int)point.Y() ); SetCursorPos(pointScreen); } ////////////////////////////////////////////////////////////////////////////// // // The hierarchy of images changed so fake a mouse move to redo hit testing // ////////////////////////////////////////////////////////////////////////////// void Window::DoHitTest() { POINT point; ::GetCursorPos(&point); ::SetCursorPos(point.x, point.y); } ////////////////////////////////////////////////////////////////////////////// // // Windows APIs // ////////////////////////////////////////////////////////////////////////////// void Window::SetCursorPos(const WinPoint& point) { WinPoint pointScreen = ClientToScreen(point); ::SetCursorPos(pointScreen.X(), pointScreen.Y()); } ZString Window::GetText() const { int length = GetWindowTextLength(m_hwnd) + 1; if (length == 0) { return ZString(); } else { char* pch = new char[length]; GetWindowText(m_hwnd, pch, length); ZString str(pch); delete[] pch; return str; } } HCURSOR Window::GetCursor() const { if (m_hcursor != NULL) { return m_hcursor; } else { // inherit our cursor from our parent window if (GetParent() != NULL) { return GetParent()->GetCursor(); } else { return NULL; } } } void Window::ShowMouse(bool bShow) { if (m_bShowMouse != bShow) { m_bShowMouse = bShow; ::ShowCursor(m_bShowMouse); } } void Window::CaptureMouse() { ::SetCapture(m_hwnd); } void Window::ReleaseMouse() { ::ReleaseCapture(); } void Window::ShowCursor(bool bShow) { ZUnimplemented(); } bool Window::OnVScroll(UINT nSBCode, UINT nPos, HWND hwnd) { return false; } bool Window::OnHScroll(UINT nSBCode, UINT nPos, HWND hwnd) { return false; } void Window::OnPaint(HDC hdc, const WinRect& rect) { } bool Window::OnCommand(WPARAM wParam, LPARAM lParam) { return false; } bool Window::OnSysCommand(UINT uCmdType, const WinPoint& point) { return false; } bool Window::OnActivate(UINT nState, bool bMinimized) { return false; } bool Window::OnActivateApp(bool bActive) { return false; } bool Window::OnTimer() { return false; } DWORD Window::OriginalWndProc( UINT message, WPARAM wParam, LPARAM lParam ) { return CallWindowProc(m_pfnWndProc, m_hwnd, message, wParam, lParam); } WinPoint MakePoint(LPARAM lParam) { WORD x = LOWORD(lParam); WORD y = HIWORD(lParam); int fx = *(short int*)(&x); int fy = *(short int*)(&y); return WinPoint(fx, fy); } void Window::OnClose() { ::PostQuitMessage(0); } void Window::OnDestroy() { } bool Window::OnWindowPosChanging(WINDOWPOS* pwp) { if ((pwp->flags & SWP_NOSIZE) == 0) { if (pwp->cx < m_sizeMin.X()) { pwp->cx = m_sizeMin.X(); if (pwp->x != m_rect.XMin()) { pwp->x = m_rect.XMax() - m_sizeMin.X(); } } if (pwp->cy < m_sizeMin.Y()) { pwp->cy = m_sizeMin.Y(); if (pwp->y != m_rect.YMin()) { pwp->y = m_rect.YMax() - m_sizeMin.Y(); } } } return true; } void Window::SetCursor(HCURSOR hcursor) { POINT pntCursorPos; HWND hwndBelowCursor; m_hcursor = hcursor; // send an update cursor message to the window under the cursor if (GetCursorPos(&pntCursorPos)) { hwndBelowCursor = WindowFromPoint(pntCursorPos); if (hwndBelowCursor) { // REVIEW: ideally we'd send a WM_NCHITTEST message to figure out // which cursor to set, but if the app below the cursor was frozen // that could freeze us too. ::PostMessage(hwndBelowCursor, WM_SETCURSOR, (unsigned)hwndBelowCursor, MAKELONG(HTCLIENT, WM_MOUSEMOVE)); } } } DWORD Window::WndProc( UINT message, WPARAM wParam, LPARAM lParam ) { switch (message) { case WM_CLOSE: OnClose(); return 0; case WM_DESTROY: OnDestroy(); return 0; case WM_PAINT: PAINTSTRUCT paint; BeginPaint(GetHWND(), &paint); OnPaint(paint.hdc, paint.rcPaint); EndPaint(GetHWND(), &paint); return 0; case WM_MOVE: case WM_SIZE: UpdateRect(); RectChanged(); break; case WM_TIMER: if (OnTimer()) return 0; break; case WM_HSCROLL: if (OnHScroll((int)LOWORD(wParam), (short int) HIWORD(wParam), (HWND)lParam)) return 0; break; case WM_VSCROLL: if (OnVScroll((int)LOWORD(wParam), (short int) HIWORD(wParam), (HWND)lParam)) return 0; break; case WM_COMMAND: if (OnCommand(wParam, lParam)) return 0; break; case WM_SYSCOMMAND: if (OnSysCommand(wParam & 0xFFF0, MakePoint(lParam))) return 0; break; case WM_ACTIVATE: if (OnActivate(LOWORD(wParam), HIWORD(wParam) != 0)) return 0; break; case WM_ACTIVATEAPP: if (OnActivateApp(wParam != 0)) return 0; break; case WM_CHAR: { KeyState ks; ks.vk = wParam; ks.bShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; ks.bControl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; ks.countRepeat = LOWORD(lParam); return !OnChar(ks); } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: { KeyState ks; ks.vk = wParam; ks.bShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; ks.bControl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; ks.bAlt = (message == WM_SYSKEYUP || message == WM_SYSKEYDOWN) && (lParam & (1 << 29)); // See help for WM_SYSKEYDOWN ks.bDown = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN); ks.countRepeat = LOWORD(lParam); return !OnKey(ks); } break; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_MOUSEMOVE: case WM_MOUSELEAVE: { WinPoint point(MakePoint(lParam)); WinPoint pointMouse( point.X(), m_rectClient.YSize() - 1 - point.Y() ); // // Handle mouse leave // if (message == WM_MOUSELEAVE) { if (m_bMouseInside) { m_bMouseInside = false; OnMouseMessage(WM_MOUSELEAVE, 0, pointMouse); } } else { // // Handle mouse enter // if (!m_bMouseInside) { m_bMouseInside = true; OnMouseMessage(0, 0, pointMouse); if (s_pfnTrackMouseEvent) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = m_hwnd; tme.dwHoverTime = HOVER_DEFAULT; ZVerify(s_pfnTrackMouseEvent(&tme)); } } // // Handle the mouse message // DWORD ret = OnMouseMessage(message, wParam, pointMouse) ? 0 : 1; } return true; } break; case WM_SETCURSOR: // // use the custom cursor for the client area // if (LOWORD(lParam) == HTCLIENT) { ::SetCursor(NULL); } else { ::SetCursor(GetCursor()); } break; case WM_WINDOWPOSCHANGING: if (OnWindowPosChanging((LPWINDOWPOS)lParam)) return 0; break; } return m_pfnWndProc(m_hwnd, message, wParam, lParam); } ////////////////////////////////////////////////////////////////////////////// // // Idle processing // ////////////////////////////////////////////////////////////////////////////// TRef > g_plistIdle; void Window::DoIdle() { } void Window::EnableIdleFunction(bool bEnable) { if (g_plistIdle) { if (bEnable) { ZAssert(!g_plistIdle->Find(this)); g_plistIdle->PushFront(this); } else { g_plistIdle->Remove(this); } } } void CallIdleFunctions() { TList::Iterator iter(*g_plistIdle); while (!iter.End()) { iter.Value()->DoIdle(); iter.Next(); } } ////////////////////////////////////////////////////////////////////////////// // // Win32 code // ////////////////////////////////////////////////////////////////////////////// TMap Window::s_mapWindow; DWORD CALLBACK Window::Win32WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { Window* pwindow; if (message == WM_CREATE && NULL != (pwindow = (Window*)(((CREATESTRUCT *)lParam)->lpCreateParams))) { pwindow->m_hwnd = hwnd; s_mapWindow.Set(hwnd, pwindow); } else { if (!s_mapWindow.Find(hwnd, pwindow)) { pwindow = NULL; } } if (pwindow) { return pwindow->WndProc(message, wParam, lParam); } else { return DefWindowProc(hwnd, message, wParam, lParam); } } HRESULT Window::StaticInitialize() { g_plistIdle = new TList; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)Win32WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 4; wc.hInstance = GetModuleHandle(NULL); wc.hIcon = LoadIcon(NULL, ID_APP_ICON); wc.hCursor = NULL; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = GetTopLevelWindowClassname(); RegisterClass(&wc); // // See if TrackMouseEvent exists // #ifndef DREAMCAST s_pfnTrackMouseEvent = (PFNTrackMouseEvent)GetProcAddress( GetModuleHandle("user32"), "TrackMouseEvent" ); #endif return S_OK; } HRESULT Window::StaticTerminate() { g_plistIdle = NULL; return S_OK; } Window* Window::WindowFromHWND(HWND hwnd) { Window* pwindow = NULL; if (!s_mapWindow.Find(hwnd, pwindow)) pwindow = NULL; return pwindow; } bool g_bContinuousIdle = true; void Window::SetContinuousIdle(bool b) { g_bContinuousIdle = b; } #ifdef ICAP int Window::s_countProfile = 0; bool Window::s_bProfileStarted = false; void Window::ToggleProfiling(int count) { if (count == -1) { if (s_countProfile == 0) { s_countProfile = -1; } else { s_countProfile = 0; } } else { s_countProfile = count; } } bool Window::IsProfiling() { return s_bProfileStarted; } #endif HRESULT Window::MessageLoop() { MSG msg; while (true) { // // Turn on Profiling // #ifdef ICAP if (s_bProfileStarted) { if (s_countProfile == 0) { MarkProfile(2); StopProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID); s_bProfileStarted = false; } } else { if (s_countProfile != 0) { StartProfile(PROFILE_THREADLEVEL, PROFILE_CURRENTID); MarkProfile(1); s_bProfileStarted = true; } if (s_countProfile > 0) { s_countProfile--; } } #endif // // Call Timers and Idle functions // CallTimers(); CallIdleFunctions(); // // Handles Win32 messages // bool bAnyMessage = true; if (g_bContinuousIdle) { bAnyMessage = ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0; } else { ::GetMessage(&msg, NULL, 0, 0); } if (bAnyMessage) { do { if (msg.message == WM_QUIT) { s_mapWindow.SetEmpty(); return S_OK; } switch (msg.message) { case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYDOWN: case WM_KEYUP: { KeyState ks; ks.vk = msg.wParam; ks.bAlt = (msg.message == WM_SYSKEYUP || msg.message == WM_SYSKEYDOWN) && (msg.lParam & (1 << 29)); // See help for WM_SYSKEYDOWN ks.bShift = (GetKeyState(VK_SHIFT) & 0x8000) !=0; ks.bControl = (GetKeyState(VK_CONTROL) & 0x8000) !=0; ks.bDown = (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN); ks.countRepeat = LOWORD(msg.lParam); bool fHandled = false; bool fForceTranslate = false; TList >::Iterator iter(g_listKeyboardInputFilters); while (!iter.End() && !fHandled) { fHandled = iter.Value()->OnKey(NULL, ks, fForceTranslate); iter.Next(); } if (!fHandled) { fHandled = (::DispatchMessage(&msg) == 0); } if (!fHandled || fForceTranslate) { ::TranslateMessage(&msg); } } break; case WM_CHAR: { KeyState ks; ks.vk = msg.wParam; ks.bShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; ks.bControl = (GetKeyState(VK_CONTROL) & 0x8000) !=0; ks.countRepeat = LOWORD(msg.lParam); bool fHandled = false; TList >::Iterator iter(g_listKeyboardInputFilters); while (!iter.End() && !fHandled) { fHandled = iter.Value()->OnChar(NULL, ks); iter.Next(); } if (fHandled) { break; } } // // intentional fallthrough // default: ::DispatchMessage(&msg); break; } } while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); } } }