#include "pch.h"
#ifdef ICAP
#include "..\..\extern\icecap4\include\icecap.h"
#endif
void FillSolidRect(HDC hdc, const WinRect& rect, COLORREF color)
{
HBRUSH hbrush = CreateSolidBrush(color);
::FillRect(hdc, &rect, hbrush);
DeleteObject(hbrush);
}
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()
);
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.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.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) {
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);
}
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);
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();
}
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();
}
TList<TRef<IKeyboardInput> > g_listKeyboardInputFilters;
void Window::AddKeyboardInputFilter(IKeyboardInput* pkeyboardInput)
{
g_listKeyboardInputFilters.PushEnd(pkeyboardInput);
}
void Window::RemoveKeyboardInputFilter(IKeyboardInput* pkeyboardInput)
{
g_listKeyboardInputFilters.Remove(pkeyboardInput);
}
class Timer : public IObjectSingle {
public:
Time m_when;
float m_delta;
TRef<IEventSink> 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<TRef<Timer>, TimerEquals, TimerCompare> TimerList;
TimerList g_listTimers;
void CallTimers()
{
Time now = Time::Now();
while (g_listTimers.GetCount() != 0) {
TRef<Timer> 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;
}
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;
}
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);
}
void Window::DoHitTest()
{
POINT point;
::GetCursorPos(&point);
::SetCursorPos(point.x, point.y);
}
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 {
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;
if (GetCursorPos(&pntCursorPos)) {
hwndBelowCursor = WindowFromPoint(pntCursorPos);
if (hwndBelowCursor) {
::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)); 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()
);
if (message == WM_MOUSELEAVE) {
if (m_bMouseInside) {
m_bMouseInside = false;
OnMouseMessage(WM_MOUSELEAVE, 0, pointMouse);
}
} else {
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));
}
}
DWORD ret =
OnMouseMessage(message, wParam, pointMouse)
? 0
: 1;
}
return true;
}
break;
case WM_SETCURSOR:
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);
}
TRef<TList<Window*> > 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<Window*>::Iterator iter(*g_plistIdle);
while (!iter.End()) {
iter.Value()->DoIdle();
iter.Next();
}
}
TMap<HWND, Window* > 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<Window*>;
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);
#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) {
#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
CallTimers();
CallIdleFunctions();
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)); 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.vk == 44); ks.countRepeat = LOWORD(msg.lParam);
bool fHandled = false;
bool fForceTranslate = false;
TList<TRef<IKeyboardInput> >::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<TRef<IKeyboardInput> >::Iterator iter(g_listKeyboardInputFilters);
while (!iter.End() && !fHandled) {
fHandled = iter.Value()->OnChar(NULL, ks);
iter.Next();
}
if (fHandled) {
break;
}
}
default:
::DispatchMessage(&msg);
break;
}
} while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
}
}