Engine directory for ticket #1

This commit is contained in:
DavidWyand-GG 2012-09-19 11:15:01 -04:00
parent 352279af7a
commit 7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions

View file

@ -0,0 +1,202 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include <windows.h>
#include <tchar.h>
#include "core/strings/unicode.h"
#include "math/mMath.h"
#include "windowManager/win32/win32Window.h"
#include "windowManager/win32/win32WindowMgr.h"
#include "windowManager/win32/winDispatch.h"
#include "windowManager/win32/win32CursorController.h"
#include "platform/platformInput.h"
#include <zmouse.h>
static struct { U32 id; LPTSTR resourceID; } sgCursorShapeMap[]=
{
{ PlatformCursorController::curArrow, IDC_ARROW },
{ PlatformCursorController::curWait, IDC_WAIT },
{ PlatformCursorController::curPlus, IDC_CROSS },
{ PlatformCursorController::curResizeVert, IDC_SIZEWE },
{ PlatformCursorController::curResizeHorz, IDC_SIZENS },
{ PlatformCursorController::curResizeAll, IDC_SIZEALL },
{ PlatformCursorController::curIBeam, IDC_IBEAM },
{ PlatformCursorController::curResizeNESW, IDC_SIZENESW },
{ PlatformCursorController::curResizeNWSE, IDC_SIZENWSE },
{ PlatformCursorController::curHand, IDC_HAND },
{ 0, 0 },
};
//static const EnumTable::Enums curManagerShapesEnums[] =
//{
// { Win32CursorController::curArrow, "Arrow" },
// { Win32CursorController::curWait, "Wait" },
// { Win32CursorController::curPlus, "Plus" },
// { Win32CursorController::curResizeVert, "ResizeVert" },
// { Win32CursorController::curResizeHorz, "ResizeHorz" },
// { Win32CursorController::curResizeAll, "ResizeAll" },
// { Win32CursorController::curIBeam, "ibeam" },
// { Win32CursorController::curResizeNESW, "ResizeNESW" },
// { Win32CursorController::curResizeNWSE, "ResizeNWSE" },
//};
//
//static const EnumTable gCurManagerShapesTable(8, &curManagerShapesEnums[0]);
// CodeReview I've duplicated this 'cache' trick for system settings
// because they're unlikely to change and calling into the OS for values
// repeatedly is just silly to begin with. [6/29/2007 justind]
U32 Win32CursorController::getDoubleClickTime()
{
static S32 sPlatWinDoubleClicktime = -1;
if( sPlatWinDoubleClicktime == -1 )
sPlatWinDoubleClicktime = GetDoubleClickTime();
return sPlatWinDoubleClicktime;
}
S32 Win32CursorController::getDoubleClickWidth()
{
static S32 sPlatWinDoubleClickwidth = -1;
if( sPlatWinDoubleClickwidth == -1 )
sPlatWinDoubleClickwidth = GetSystemMetrics(SM_CXDOUBLECLK);
return sPlatWinDoubleClickwidth;
}
S32 Win32CursorController::getDoubleClickHeight()
{
static S32 sPlatWinDoubleClickheight = -1;
if( sPlatWinDoubleClickheight == -1 )
sPlatWinDoubleClickheight = GetSystemMetrics(SM_CYDOUBLECLK);
return sPlatWinDoubleClickheight;
}
void Win32CursorController::setCursorPosition( S32 x, S32 y )
{
::SetCursorPos(x, y);
}
void Win32CursorController::getCursorPosition( Point2I &point )
{
POINT rPoint;
::GetCursorPos( &rPoint );
// Return
point.x = rPoint.x;
point.y = rPoint.y;
}
void Win32CursorController::setCursorVisible( bool visible )
{
if( visible )
ShowCursor( true );
else
while( ShowCursor(false) > 0 );
}
bool Win32CursorController::isCursorVisible()
{
CURSORINFO rCursorInfo;
rCursorInfo.cbSize = sizeof(CURSORINFO);
if( !GetCursorInfo( &rCursorInfo ) )
{
//DWORD error = GetLastError();
return false;
}
// rCursorInfo.flags values :
// 0 == Cursor is hidden
// CURSOR_SHOWING == cursor is visible
return (bool)(rCursorInfo.flags == CURSOR_SHOWING);
}
void Win32CursorController::setCursorShape(U32 cursorID)
{
LPTSTR resourceID = NULL;
for(S32 i = 0;sgCursorShapeMap[i].resourceID != NULL;++i)
{
if(cursorID == sgCursorShapeMap[i].id)
{
resourceID = sgCursorShapeMap[i].resourceID;
break;
}
}
if(resourceID == NULL)
return;
HCURSOR cur = LoadCursor(NULL, resourceID);
if(cur)
SetCursor(cur);
}
static HCURSOR gCursorShape = NULL;
void Win32CursorController::setCursorShape( const UTF8 *fileName, bool reload )
{
#ifdef UNICODE
const UTF16 *lFileName = convertUTF8toUTF16( fileName );
#else
const UTF8 *lFileName = fileName;
#endif
if ( !gCursorShape || reload )
gCursorShape = LoadCursorFromFile( lFileName );
if ( gCursorShape )
SetCursor( gCursorShape );
}
// Console function to set the current cursor shape given the cursor shape
// name as defined in the enum above.
//ConsoleFunction( inputPushCursor, void, 2, 2, "inputPushCursor(cursor shape name)" )
//{
// S32 val = 0;
//
// // Find the cursor shape
// if(argc == 2)
// {
// for (S32 i = 0; i < gCurManagerShapesTable.size; i++)
// {
// if (! dStricmp(argv[1], gCurManagerShapesTable.table[i].label))
// {
// val = gCurManagerShapesTable.table[i].index;
// break;
// }
// }
// }
//
// // Now set it
// Win32CursorController* cm = Input::getCursorManager();
// if(cm)
// {
// cm->pushCursor(val);
// }
//}
//// Function to pop the current cursor shape
//ConsoleFunction( inputPopCursor, void, 1, 1, "inputPopCursor()" )
//{
// argc;
// argv;
//
// Win32CursorController* cm = Input::getCursorManager();
// if(cm)
// {
// cm->popCursor();
// }
//}

View file

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _WIN32_CURSORCONTROLLER_H_
#define _WIN32_CURSORCONTROLLER_H_
#include <windows.h>
#include "windowManager/platformCursorController.h"
class Win32CursorController : public PlatformCursorController
{
public:
Win32CursorController( PlatformWindow *owner ) :
PlatformCursorController( owner )
{
pushCursor( PlatformCursorController::curArrow );
};
virtual void setCursorPosition( S32 x, S32 y );
virtual void getCursorPosition( Point2I &point );
virtual void setCursorVisible( bool visible );
virtual bool isCursorVisible();
void setCursorShape( U32 cursorID );
void setCursorShape( const UTF8 *fileName, bool reload );
U32 getDoubleClickTime();
S32 getDoubleClickWidth();
S32 getDoubleClickHeight();
};
#endif

View file

@ -0,0 +1,142 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include "platform/platform.h"
#include "console/console.h"
// from Torque.rc
#define IDI_ICON1 103
// Window Class name
static const TCHAR* c_szSplashClass = L"Torque3DSplashWindow";
static HWND gSplashWndOwner = NULL;
static HWND gSplashWnd = NULL;
static HBITMAP gSplashImage = NULL;
// Registers a window class for the splash and splash owner windows.
static void RegisterWindowClass(HINSTANCE hinst)
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hinst;
wc.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_ICON1));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = c_szSplashClass;
RegisterClass(&wc);
}
static void UnregisterSplashWindowClass(HINSTANCE hinst)
{
WNDCLASSEX classInfo;
if (GetClassInfoEx(hinst,c_szSplashClass,&classInfo))
UnregisterClass(c_szSplashClass,hinst);
}
// Creates the splash owner window and the splash window.
static HWND CreateSplashWindow(HINSTANCE hinst)
{
RegisterWindowClass(hinst);
gSplashWndOwner = CreateWindow(c_szSplashClass, NULL, WS_POPUP,
0, 0, 0, 0, NULL, NULL, hinst, NULL);
return CreateWindowEx(WS_EX_LAYERED, c_szSplashClass, NULL, WS_POPUP | WS_VISIBLE,
0, 0, 0, 0, gSplashWndOwner, NULL, hinst, NULL);
}
// Calls UpdateLayeredWindow to set a bitmap (with alpha) as the content of the splash window.
static void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash)
{
// get the size of the bitmap
BITMAP bm;
GetObject(hbmpSplash, sizeof(bm), &bm);
SIZE sizeSplash = { bm.bmWidth, bm.bmHeight };
// get the primary monitor's info
POINT ptZero = { 0 };
HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorinfo = { 0 };
monitorinfo.cbSize = sizeof(monitorinfo);
GetMonitorInfo(hmonPrimary, &monitorinfo);
// center the splash screen in the middle of the primary work area
const RECT & rcWork = monitorinfo.rcWork;
POINT ptOrigin;
ptOrigin.x = rcWork.left + (rcWork.right - rcWork.left - sizeSplash.cx) / 2;
ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy) / 2;
// create a memory DC holding the splash bitmap
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash);
// paint the window (in the right location) with the alpha-blended bitmap
UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash,
hdcMem, &ptZero, RGB(0, 0, 0), NULL, ULW_OPAQUE);
// delete temporary objects
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
}
void CloseSplashWindow(HINSTANCE hinst)
{
if (gSplashWndOwner)
{
//ShowWindow(gSplashWnd, 0);
DestroyWindow(gSplashWndOwner);
UnregisterSplashWindowClass(hinst);
}
gSplashWndOwner = NULL;
gSplashWnd = NULL;
}
bool Platform::displaySplashWindow()
{
gSplashImage = (HBITMAP) ::LoadImage(0, L"art\\gui\\splash.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!gSplashImage)
return false;
gSplashWnd = CreateSplashWindow(GetModuleHandle(NULL));
if (!gSplashWnd)
return false;
SetSplashImage(gSplashWnd, gSplashImage);
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,231 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _WINDOWMANAGER_WIN32_WIN32WINDOW_
#define _WINDOWMANAGER_WIN32_WIN32WINDOW_
#include <windows.h>
#include "windowManager/platformWindowMgr.h"
#include "gfx/gfxTarget.h"
#include "gfx/gfxStructs.h"
#include "sim/actionMap.h"
class Win32WindowManager;
/// Implementation of a window on Win32.
class Win32Window : public PlatformWindow
{
friend class Win32WindowManager;
friend class GFXPCD3D9Device;
friend class GFXPCD3D9WindowTarget;
friend class GFXD3D8WindowTarget;
public:
struct Accelerator
{
U32 mID;
EventDescriptor mDescriptor;
};
typedef Vector<Accelerator> AcceleratorList;
private:
typedef Vector<ACCEL> WinAccelList;
/// @name Active window list
///
/// Items used to track window instances.
///
/// @{
/// Which manager created us?
Win32WindowManager *mOwningManager;
/// Which window comes next in list?
Win32Window *mNextWindow;
/// @}
/// @name Window Information
///
/// @{
/// Our HWND - Win32 window handle.
HWND mWindowHandle;
/// Our former Parent HWND
HWND mOldParent;
/// The Win32 window style we want to use when windowed.
DWORD mWindowedWindowStyle;
/// The GFX device that we're tied to.
GFXDevice *mDevice;
/// Reference to the render target allocated on this window.
GFXWindowTargetRef mTarget;
/// Our current size/resolution/fullscreen status.
GFXVideoMode mVideoMode;
/// Our position on the desktop.
Point2I mPosition;
/// Windows HACCEL for accelerators
HACCEL mAccelHandle;
/// Keyboard accelerators for menus
WinAccelList mWinAccelList;
/// Is the mouse locked to this window?
bool mMouseLocked;
/// The position the cursor was at when a mouse lock occured
Point2I mMouseLockPosition;
/// Determines whether this window should lock the mouse when it has an opportunity
bool mShouldLockMouse;
/// When set, we don't trigger device resets due to sizing events.
bool mSuppressReset;
/// Menu associated with this window. This is a passive property of the window and is not required to be used at all.
HMENU mMenuHandle;
/// Do we have a fullscreen window style set?
bool mFullscreen;
/// @}
/// Helper to allocate our Win32 window class.
void _registerWindowClass();
void _unregisterWindowClass();
/// Windows message handler callback.
static LRESULT PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
/// Add an accelerator to the list of accelerators for this window. Intended for use by addAccelerators()
void addAccelerator(Accelerator &accel);
/// Remove an accelerator from the list of accelerators for this window. Intended for use by removeAccelerators()
void removeAccelerator(Accelerator &accel);
public:
Win32Window();
~Win32Window();
/// Return the HWND (win32 window handle) for this window.
HWND &getHWND()
{
return mWindowHandle;
}
HMENU &getMenuHandle()
{
return mMenuHandle;
}
void setMenuHandle( HMENU menuHandle )
{
mMenuHandle = menuHandle;
if(!mFullscreen)
SetMenu(mWindowHandle, mMenuHandle);
}
/// Add a list of accelerators to this window
void addAccelerators(AcceleratorList &list);
/// Remove a list of accelerators from this window
void removeAccelerators(AcceleratorList &list);
/// Returns true if @p info matches an accelerator
bool isAccelerator(const InputEventInfo &info);
/// Allow windows to translate messages. Used for accelerators.
bool translateMessage(MSG &msg);
virtual GFXDevice *getGFXDevice();
virtual GFXWindowTarget *getGFXTarget();
virtual void setVideoMode(const GFXVideoMode &mode);
virtual const GFXVideoMode &getVideoMode();
virtual bool clearFullscreen();
virtual bool isFullscreen();
virtual void _setFullscreen(const bool fullscreen);
virtual bool setCaption(const char *cap);
virtual const char *getCaption();
// Window Client Area Extent
virtual void setClientExtent( const Point2I newExtent );
virtual const Point2I getClientExtent();
// Window Bounds
virtual void setBounds(const RectI &newBounds);
virtual const RectI getBounds() const;
// Window Position
virtual void setPosition( const Point2I newPosition );
virtual const Point2I getPosition();
virtual void centerWindow();
virtual bool setSize(const Point2I &newSize);
// Coordinate space conversion.
virtual Point2I clientToScreen( const Point2I& pos );
virtual Point2I screenToClient( const Point2I& pos );
virtual bool isOpen();
virtual bool isVisible();
virtual bool isFocused();
virtual bool isMinimized();
virtual bool isMaximized();
virtual void minimize();
virtual void maximize();
virtual void hide();
virtual void show();
virtual void close();
virtual void restore();
virtual void setFocus();
virtual void setMouseLocked(bool enable);
virtual bool isMouseLocked() const { return mMouseLocked; };
virtual bool shouldLockMouse() const { return mShouldLockMouse; };
virtual WindowId getWindowId();
virtual PlatformWindow * getNextWindow() const
{
return mNextWindow;
}
/// Provide a simple GDI-based render for when the game is not rendering.
virtual void defaultRender();
/// Return the class name for the windows we create with this class.
static const UTF16 *getWindowClassName();
/// Return the class name for the curtain window class.
static const UTF16 *getCurtainWindowClassName();
/// Return the platform specific object needed to create or attach an
/// accelerated graohics drawing context on or to the window
virtual void* getPlatformDrawable() const { return mWindowHandle; }
};
#endif

View file

@ -0,0 +1,453 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platformWin32/platformWin32.h"
#include "windowManager/win32/win32WindowMgr.h"
#include "gfx/gfxDevice.h"
#include "windowManager/win32/winDispatch.h"
#include "core/util/journal/process.h"
#include "core/strings/unicode.h"
// ------------------------------------------------------------------------
void CloseSplashWindow(HINSTANCE hinst);
PlatformWindowManager * CreatePlatformWindowManager()
{
return new Win32WindowManager();
}
// ------------------------------------------------------------------------
Win32WindowManager::Win32WindowManager()
{
// Register in the process list.
Process::notify(this, &Win32WindowManager::_process, PROCESS_INPUT_ORDER);
// Init our list of allocated windows.
mWindowListHead = NULL;
// By default, we have no parent window.
mParentWindow = NULL;
mCurtainWindow = NULL;
mOffscreenRender = false;
}
Win32WindowManager::~Win32WindowManager()
{
// Get ourselves off the process list.
Process::remove(this, &Win32WindowManager::_process);
// Kill all our windows first.
while(mWindowListHead)
// The destructors update the list, so this works just fine.
delete mWindowListHead;
}
RectI Win32WindowManager::getPrimaryDesktopArea()
{
RECT primaryWorkRect;
SystemParametersInfo(SPI_GETWORKAREA, 0, &primaryWorkRect, 0);
RectI res;
res.point.x = primaryWorkRect.left;
res.point.y = primaryWorkRect.top;
res.extent.x = primaryWorkRect.right - primaryWorkRect.left;
res.extent.y = primaryWorkRect.bottom - primaryWorkRect.top;
return res;
}
Point2I Win32WindowManager::getDesktopResolution()
{
DEVMODE devMode;
dMemset( &devMode, 0, sizeof( devMode ) );
devMode.dmSize = sizeof( devMode );
if (!::EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
return Point2I(-1,-1);
// Return Resolution
return Point2I(devMode.dmPelsWidth, devMode.dmPelsHeight);
}
S32 Win32WindowManager::getDesktopBitDepth()
{
DEVMODE devMode;
dMemset( &devMode, 0, sizeof( devMode ) );
devMode.dmSize = sizeof( devMode );
if (!::EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
return -1;
// Return Bits per Pixel
return (S32)devMode.dmBitsPerPel;
}
BOOL Win32WindowManager::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData )
{
Vector<RectI> * regions = (Vector<RectI>*)dwData;
regions->increment();
regions->last().point.x = lprcMonitor->left;
regions->last().point.y = lprcMonitor->top;
regions->last().extent.x = lprcMonitor->right - lprcMonitor->left;
regions->last().extent.y = lprcMonitor->bottom - lprcMonitor->top;
return true;
}
void Win32WindowManager::getMonitorRegions(Vector<RectI> &regions)
{
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)&regions);
}
void Win32WindowManager::getWindows(VectorPtr<PlatformWindow*> &windows)
{
Win32Window *win = mWindowListHead;
while(win)
{
windows.push_back(win);
win = win->mNextWindow;
}
}
PlatformWindow *Win32WindowManager::createWindow(GFXDevice *device, const GFXVideoMode &mode)
{
// Do the allocation.
Win32Window *w32w = new Win32Window();
w32w->setOffscreenRender(mOffscreenRender);
w32w->mWindowId = getNextId();
w32w->mOwningManager = this;
// Link into our list of windows.
linkWindow(w32w);
DWORD dwExStyle;
DWORD dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
dwStyle |= WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_CAPTION;
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
// If we're parented, we want a different set of window styles.
if(mParentWindow)
dwStyle = WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILDWINDOW;
if (mOffscreenRender)
{
dwStyle = WS_OVERLAPPEDWINDOW;
dwExStyle = 0;
}
// Create the window handle
w32w->mWindowHandle = CreateWindowEx(
dwExStyle,
Win32Window::getWindowClassName(), //class name
String( getEngineProductString() ).utf16(), //window title
dwStyle, //style - need clip siblings/children for opengl
0,
0,
0,
0,
mParentWindow, //parent window
NULL, //menu? No.
NULL, //the hInstance
NULL ); //no funky params
// Note the style we created with so we can switch back to it when we're
// done with full-screen mode.
w32w->mWindowedWindowStyle = dwStyle;
// Set the video mode on the window
w32w->setVideoMode(mode);
// Associate our window struct with the HWND.
SetWindowLongPtrW(w32w->mWindowHandle, GWLP_USERDATA, (LONG)w32w);
// Do some error checking.
AssertFatal(w32w->mWindowHandle != NULL, "Win32WindowManager::createWindow - Could not create window!");
if(w32w->mWindowHandle == NULL)
{
Con::errorf("Win32WindowManager::createWindow - Could not create window!");
delete w32w;
return NULL;
}
// If we're not rendering offscreen, make sure our window is shown and drawn to.
if (!mOffscreenRender)
ShowWindow( w32w->mWindowHandle, SW_SHOWDEFAULT );
// Close any splash screen we created
CloseSplashWindow(winState.appInstance);
// Bind the window to the specified device.
if(device)
{
w32w->mDevice = device;
w32w->mTarget = device->allocWindowTarget(w32w);
AssertISV(w32w->mTarget,
"Win32WindowManager::createWindow - failed to get a window target back from the device.");
}
else
{
Con::warnf("Win32WindowManager::createWindow - created a window with no device!");
}
// Update it if needed.
UpdateWindow( w32w->mWindowHandle );
return w32w;
}
void Win32WindowManager::setParentWindow(void* newParent)
{
Con::printf( "Setting parent HWND: %d", newParent );
mParentWindow = (HWND)newParent;
if( mWindowListHead && mWindowListHead->mWindowHandle )
::SetParent( mWindowListHead->mWindowHandle, mParentWindow);
}
void* Win32WindowManager::getParentWindow()
{
return (void*)mParentWindow;
}
void Win32WindowManager::_process()
{
MSG msg;
bool _blocking = false;
// CodeReview [tom, 4/30/2007] Maintaining two completely separate message
// handlers that are essentially the same is silly. The first one never
// seems to run as _blocking is hard coded to false above, so is this even
// needed ? If it is, this should be rewritten to use the one loop that
// adjusts as needed based on _blocking and Journal::IsPlaying()
if (_blocking && !Journal::IsPlaying())
{
// In blocking mode, we process one message at a time.
if (GetMessage(&msg, NULL, 0, 0))
{
bool noTranslate = false;
Win32Window *w32w = mWindowListHead;
while(w32w)
{
noTranslate = w32w->translateMessage(msg);
if(noTranslate) break;
w32w = w32w->mNextWindow;
}
if(! noTranslate)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
// This should be WM_QUIT
Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
}
else
{
// Process all queued up messages
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
bool translated = false;
// Win32Window *w32w = mWindowListHead;
// while(w32w)
// {
// noTranslate = w32w->translateMessage(msg);
// if(noTranslate) break;
// w32w = w32w->mNextWindow;
// }
// [tom, 4/30/2007] I think this should work, but leaving the above commented
// out just in case this is actually fubared with multiple windows.
Win32Window* window = (Win32Window*)(GetWindowLong(msg.hwnd, GWL_USERDATA));
if(window)
translated = window->translateMessage(msg);
if(! translated)
{
// Win32Window::translateMessage() will post a WM_COMMAND event for
// translated accelerator events, so dispatching again will cause a
// the input event to be dispatched, which is usually not what we want.
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
{
Dispatch(ImmediateDispatch,0,msg.message,msg.wParam,msg.lParam);
break;
}
}
}
// Dispatch any delayed events
while (DispatchNext());
// Fire off idle events for every window.
Win32Window *w32w = mWindowListHead;
while(w32w)
{
w32w->idleEvent.trigger();
w32w = w32w->mNextWindow;
}
}
PlatformWindow * Win32WindowManager::getWindowById( WindowId id )
{
// Walk the list and find the matching id, if any.
Win32Window *win = mWindowListHead;
while(win)
{
if(win->getWindowId() == id)
return win;
win = win->mNextWindow;
}
return NULL;
}
PlatformWindow * Win32WindowManager::getFirstWindow()
{
return mWindowListHead != NULL ? mWindowListHead : NULL;
}
PlatformWindow* Win32WindowManager::getFocusedWindow()
{
Win32Window* window = mWindowListHead;
while( window )
{
if( window->isFocused() )
return window;
window = window->mNextWindow;
}
return NULL;
}
void Win32WindowManager::linkWindow( Win32Window *w )
{
w->mNextWindow = mWindowListHead;
mWindowListHead = w;
}
void Win32WindowManager::unlinkWindow( Win32Window *w )
{
Win32Window **walk = &mWindowListHead;
while(*walk)
{
if(*walk != w)
{
// Advance to next item in list.
walk = &(*walk)->mNextWindow;
continue;
}
// Got a match - unlink and return.
*walk = (*walk)->mNextWindow;
return;
}
}
void Win32WindowManager::_processCmdLineArgs( const S32 argc, const char **argv )
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
if ( dStrnicmp( argv[i], "-window", 7 ) == 0 )
{
i++;
if ( i >= argc )
{
Con::errorf( "Command line error: -window requires an argument" );
break;
}
S32 hwnd = dAtoi( argv[i] );
if ( hwnd == 0 || hwnd == S32_MAX )
{
Con::errorf( "Command line error: -window requires a number, found [%s]", argv[i] );
break;
}
mParentWindow = (HWND)hwnd;
Con::printf( "HWND from command line: %d", hwnd );
}
if ( dStrnicmp( argv[i], "-offscreen", 10 ) == 0 )
{
mOffscreenRender = true;
}
}
}
}
void Win32WindowManager::lowerCurtain()
{
if(mCurtainWindow)
return;
// For now just grab monitor of the first window... we may need to
// beef this up later on, maybe by passing in the window that's entering
// leaving full-screen to lowerCurtain.
HMONITOR hMon = MonitorFromWindow(mWindowListHead->getHWND(), MONITOR_DEFAULTTOPRIMARY);
// Get the monitor's extents.
MONITORINFO monInfo;
dMemset(&monInfo, 0, sizeof MONITORINFO);
monInfo.cbSize = sizeof MONITORINFO;
GetMonitorInfo(hMon, &monInfo);
mCurtainWindow = CreateWindow(Win32Window::getCurtainWindowClassName(),
dT(""), (WS_POPUP | WS_MAXIMIZE | WS_VISIBLE),
monInfo.rcWork.left, monInfo.rcWork.top,
monInfo.rcWork.right - monInfo.rcWork.left,
monInfo.rcWork.bottom - monInfo.rcWork.top,
NULL, NULL, NULL, NULL);
if (!mOffscreenRender)
SetWindowPos(mCurtainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
void Win32WindowManager::raiseCurtain()
{
if(!mCurtainWindow)
return;
DestroyWindow(mCurtainWindow);
mCurtainWindow = NULL;
}

View file

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _WINDOWMANAGER_WIN32_WIN32WINDOWMANAGER_
#define _WINDOWMANAGER_WIN32_WIN32WINDOWMANAGER_
#include <windows.h>
#include "math/mMath.h"
#include "gfx/gfxStructs.h"
#include "windowManager/win32/win32Window.h"
#include "core/util/tVector.h"
/// Win32 implementation of the window manager interface.
class Win32WindowManager : public PlatformWindowManager
{
friend class Win32Window;
virtual void _processCmdLineArgs(const S32 argc, const char **argv);
/// Link the specified window into the window list.
void linkWindow(Win32Window *w);
/// Remove specified window from the window list.
void unlinkWindow(Win32Window *w);
/// Callback for the process list.
void _process();
/// List of allocated windows.
Win32Window *mWindowListHead;
/// Parent window, used in window setup in web plugin scenarios.
HWND mParentWindow;
/// set via command line -offscreen option, controls whether rendering/input
// is intended for offscreen rendering
bool mOffscreenRender;
/// Callback to receive information about available monitors.
static BOOL CALLBACK MonitorEnumProc(
HMONITOR hMonitor, // handle to display monitor
HDC hdcMonitor, // handle to monitor DC
LPRECT lprcMonitor, // monitor intersection rectangle
LPARAM dwData // data
);
/// If a curtain window is present, then its HWND will be stored here.
HWND mCurtainWindow;
public:
Win32WindowManager();
~Win32WindowManager();
virtual RectI getPrimaryDesktopArea();
virtual S32 getDesktopBitDepth();
virtual Point2I getDesktopResolution();
virtual void getMonitorRegions(Vector<RectI> &regions);
virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode);
virtual void getWindows(VectorPtr<PlatformWindow*> &windows);
virtual void setParentWindow(void* newParent);
virtual void* getParentWindow();
virtual PlatformWindow *getWindowById(WindowId id);
virtual PlatformWindow *getFirstWindow();
virtual PlatformWindow* getFocusedWindow();
virtual void lowerCurtain();
virtual void raiseCurtain();
};
#endif

View file

@ -0,0 +1,594 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#define NO_MINMAX
#define WIN32_LEAN_AND_MEAN
// This is a fix for mouse wheel support on
// older versions of VC++.
#if _MSC_VER < 1500
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include "platform/event.h"
#include "platform/platformInput.h"
#include "windowManager/win32/winDispatch.h"
#include "windowManager/win32/win32Window.h"
#include "windowManager/win32/win32CursorController.h"
#include "platformWin32/winDirectInput.h"
#include "core/util/journal/process.h"
#include "core/util/journal/journaledSignal.h"
static U32 _ModifierKeys=0;
static BYTE keyboardState[256];
static bool initKBState = false;
static bool sgDoubleByteEnabled = false;
// is keyboard input a standard (non-changing) VK keycode
#define dIsStandardVK(c) (((0x08 <= (c)) && ((c) <= 0x12)) || \
((c) == 0x1b) || \
((0x20 <= (c)) && ((c) <= 0x2e)) || \
((0x30 <= (c)) && ((c) <= 0x39)) || \
((0x41 <= (c)) && ((c) <= 0x5a)) || \
((0x70 <= (c)) && ((c) <= 0x7B)))
extern InputObjectInstances DIK_to_Key( U8 dikCode );
extern U8 TranslateOSKeyCode(U8 vcode );
extern InputModifiers convertModifierBits(const U32 in);
static void _keyboardEvent(Win32Window* window,UINT message, WPARAM wParam, WPARAM lParam)
{
if(!initKBState)
{
dMemset(keyboardState, 0, sizeof(keyboardState));
initKBState = true;
}
// Extract windows key info:
// S32 repeatCount = (lParam & 0xffff);
U32 scanCode = (lParam >> 16) & 0xff;
bool extended = lParam & (1 << 24); // Enhanced keyboard key
bool previous = lParam & (1 << 30); // Previously down
bool make = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
// Translate the OS virtual key code to a Torque KEY_XXXX.
S32 nVirtkey = TranslateOSKeyCode( wParam );
S32 keyCode;
if ( wParam == VK_PROCESSKEY && sgDoubleByteEnabled )
keyCode = MapVirtualKey( scanCode, 1 ); // This is the REAL virtual key...
else
keyCode = wParam;
// Convert alt/shift/ctrl to left or right variant if needed.
S32 newVirtKey = nVirtkey;
switch(nVirtkey)
{
case KEY_ALT:
newVirtKey = extended ? KEY_RALT : KEY_LALT;
break;
case KEY_CONTROL:
newVirtKey = extended ? KEY_RCONTROL : KEY_LCONTROL;
break;
case KEY_SHIFT:
newVirtKey = (scanCode == 54) ? KEY_RSHIFT : KEY_LSHIFT;
break;
case KEY_RETURN:
if ( extended )
newVirtKey = KEY_NUMPADENTER;
break;
}
// Track modifier keys
U32 modifier = 0;
switch (newVirtKey)
{
case KEY_LALT: modifier = IM_LALT; break;
case KEY_RALT: modifier = IM_RALT; break;
case KEY_LSHIFT: modifier = IM_LSHIFT; break;
case KEY_RSHIFT: modifier = IM_RSHIFT; break;
case KEY_LCONTROL: modifier = IM_LCTRL; break;
case KEY_RCONTROL: modifier = IM_RCTRL; break;
}
if (make)
{
_ModifierKeys |= modifier;
keyboardState[keyCode] |= 0x80;
}
else
{
_ModifierKeys &= ~modifier;
keyboardState[keyCode] &= 0x7f;
}
U32 torqueMods = convertModifierBits( _ModifierKeys );
Input::setModifierKeys( torqueMods );
// If character event translation is active and this isn't a key
// mapped in the global action map, try converting the event into
// a character event first.
if( make
&& window->getKeyboardTranslation()
&& !window->shouldNotTranslate( torqueMods, newVirtKey ) )
{
U16 chars[ 64 ];
dMemset( chars, 0, sizeof( chars ) );
S32 res = ToUnicode( keyCode, scanCode, keyboardState, chars, sizeof( chars ) / sizeof( chars[ 0 ] ), 0 );
// This should only happen on Window 9x/ME systems
if( res == 0 )
res = ToAscii( keyCode, scanCode, keyboardState, chars, 0 );
if( res >= 1 )
{
// Post chars, but filter them to not be control codes... this is a bit hacky.
bool handledCharEvent = false;
for( S32 i=0; i< res; i ++ )
if( chars[i] >= 32)
{
window->charEvent.trigger(window->getWindowId(),_ModifierKeys,chars[i]);
handledCharEvent = true;
}
if( handledCharEvent )
return;
}
}
// Produce a key event.
U32 action = make ? (previous ? IA_REPEAT : IA_MAKE ) : IA_BREAK;
window->keyEvent.trigger(window->getWindowId(),_ModifierKeys,action,newVirtKey);
}
//-----------------------------------------------------------------------------
static bool _dispatch(HWND hWnd,UINT message,WPARAM wParam,WPARAM lParam)
{
static bool button[3] = {false,false,false};
static S32 mouseNCState = -1; // -1 denotes unchanged,
// 0 denotes changed but was hidden
// 1 denotes changed but was visible
Win32Window* window = hWnd?(Win32Window*)GetWindowLong(hWnd, GWL_USERDATA): 0;
const WindowId devId = window ? window->getWindowId() : 0;
// State tracking for focus/lose focus cursor management
static bool cursorLocked = false;
static bool cursorVisible = true;
switch(message)
{
case WM_MOUSEMOVE:
{
// Skip it if we have no window!
if (!window || !window->getCursorController())
break;
PlatformCursorController *pController = window->getCursorController();
// If we're locked and unfocused, ignore it.
if(window->shouldLockMouse() && !window->isFocused())
break;
// If the mouse was shown to accommodate a NC mouse move
// we need to change it back to what it was
if( mouseNCState != -1 )
{
pController->setCursorVisible( mouseNCState );
mouseNCState = -1; // reset to unchanged
}
// Let the cursor manager update the native cursor.
pController->refreshCursor();
// Grab the mouse pos so we can modify it.
S32 mouseX = S16(LOWORD(lParam));
S32 mouseY = S16(HIWORD(lParam));
// Ensure mouse lock when appropriate
window->setMouseLocked( window->shouldLockMouse() );
// Are we locked?
if(window->isMouseLocked())
{
// Always invisible when locked.
if( window->isCursorVisible() )
window->setCursorVisible( false );
RECT r;
GetWindowRect(window->getHWND(), &r);
// See Win32Window::setMouseLocked for explanation
RECT rCopy = r;
rCopy.top += 32; rCopy.bottom -= 64;
rCopy.left += 32; rCopy.right -= 64;
ClipCursor(&rCopy);
// Recenter the mouse if necessary (don't flood the message pump)
Point2I curPos;
pController->getCursorPosition( curPos );
const S32 centerX = (r.right + r.left) / 2;
const S32 centerY = (r.bottom + r.top) / 2;
if( curPos.x != centerX || curPos.y != centerY )
pController->setCursorPosition(centerX, centerY);
// Convert the incoming client pos into a screen pos, so we can
// accurately convert to relative coordinates.
POINT mousePos;
mousePos.x = mouseX;
mousePos.y = mouseY;
ClientToScreen(window->getHWND(), &mousePos);
// Now we can calculate the position relative to the center we set.
mouseX = mousePos.x - centerX;
mouseY = mousePos.y - centerY;
}
else
{
// Probably don't need to call this all the time but better
// safe than sorry...
ClipCursor(NULL);
}
window->mouseEvent.trigger(devId,_ModifierKeys,mouseX,mouseY,window->isMouseLocked());
break;
}
// We want to show the system cursor whenever we leave
// our window, and it'd be simple, except for one problem:
// showcursor isn't a toggle. so, keep hammering it until
// the cursor is *actually* going to be shown.
case WM_NCMOUSEMOVE:
{
if( window )
{
mouseNCState = ( window->isCursorVisible() ? 1 : 0);
window->setCursorVisible( true );
}
break;
}
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN: {
int index = (message - WM_LBUTTONDOWN) / 3;
button[index] = true;
// Capture the mouse on button down to allow dragging outside
// of the window boundary.
if (GetCapture() != hWnd)
SetCapture(hWnd);
if (window)
window->buttonEvent.trigger(devId,_ModifierKeys,IA_MAKE,index);
break;
}
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP: {
int index = (message - WM_LBUTTONUP) / 3;
button[index] = false;
// Release mouse capture from button down.
if (!button[0] && !button[1] && !button[2])
ReleaseCapture();
if (window)
window->buttonEvent.trigger(devId,_ModifierKeys,IA_BREAK,index);
break;
}
case WM_MOUSEWHEEL: // Vertical wheel.
if (window)
window->wheelEvent.trigger(devId,_ModifierKeys,0,GET_WHEEL_DELTA_WPARAM(wParam));
break;
#ifdef WM_MOUSEHWHEEL // Vista
case WM_MOUSEHWHEEL: // Horizontal wheel.
if( window )
window->wheelEvent.trigger( devId, _ModifierKeys, GET_WHEEL_DELTA_WPARAM( wParam ), 0 );
break;
#endif
case WM_KEYUP:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if (window)
_keyboardEvent(window,message,wParam,lParam);
break;
// NOTE: if wParam is NOT equal to our window handle then we are GAINING focus
case WM_SETFOCUS:
// clear any key states
_ModifierKeys = 0;
dMemset(keyboardState, 0, 256);
Input::setModifierKeys(0);
// We must have a window present; otherwise there's nothing further
// we can do about this event.
if (window && window->getHWND() != (HWND)wParam)
{
if (cursorVisible == false)
window->setCursorVisible(false);
if (cursorLocked == true)
window->setMouseLocked(true);
// Update window state.
window->setBackground(false);
// Fire event.
window->appEvent.trigger(devId, GainFocus);
if (!Input::isActive())
Input::activate();
}
break;
// NOTE: if wParam is NOT equal to our window handle then we are LOSING focus
case WM_KILLFOCUS:
// clear any key states
_ModifierKeys = 0;
dMemset(keyboardState, 0, 256);
Input::setModifierKeys(0);
// We must have a window present; otherwise there's nothing further
// we can do about this event.
if (window && window->getHWND() != (HWND)wParam)
{
HWND hwnd = (HWND)wParam;
UTF16 classBuf[256];
if (hwnd)
GetClassName(hwnd, classBuf, sizeof(classBuf));
// We toggle the mouse lock when we become inactive
// causing the subsequent lock call to defer itself
// until the window becomes active again.
if (window && window->isMouseLocked())
{
window->setMouseLocked( false );
window->setMouseLocked( true );
}
// FIXME [tom, 5/1/2007] Hard coding this is lame since there's a const in win32Window.cpp
// CodeReview - this fails if there is a second jug app in the arena.
if (hwnd == NULL || dStrcmp(classBuf, L"TorqueJuggernaughtWindow") != 0)
{
// We are being made inactive and the window being made active isn't
// a jugg window. Thus, we need to deactivate input.
if (Input::isActive())
Input::deactivate();
}
cursorVisible = window->isCursorVisible();
if (!cursorVisible)
window->setCursorVisible(true);
cursorLocked = window->isMouseLocked();
if (cursorLocked)
window->setMouseLocked(false);
// Update window state.
window->setBackground(true);
// Fire event.
window->appEvent.trigger(devId, LoseFocus);
}
break;
case WM_ACTIVATEAPP:
if (wParam)
{
// Could extract current modifier state from windows.
_ModifierKeys = 0;
Input::setModifierKeys(_ModifierKeys);
}
break;
case WM_CLOSE:
if (window)
window->appEvent.trigger(devId,WindowClose);
// Force a quit if we're in play mode, otherwise there would be
// no way to stop a journal playback.(
if (Journal::IsPlaying())
Process::requestShutdown();
break;
case WM_TIMER: {
if (window)
window->appEvent.trigger(devId,Timer);
break;
}
case WM_DESTROY:{
// Only people who care about this currently are web plugins, because
// everyone else will just handle the WM_CLOSE app event.
if(window)
window->appEvent.trigger(devId,WindowDestroy);
break;
}
case WM_QUIT: {
// Quit indicates that we're not going to receive anymore Win32 messages.
// Therefore, it's appropriate to flag our event loop for exit as well,
// since we won't be getting any more messages.
Process::requestShutdown();
break;
}
// CodeReview - This is not used now and will incur an overhead for rendering
// since the renderThreadBlocked fix requires handling WM_PAINT and
// triggering the displayEvent. May need to revisit this at a later
// time if we want event driven rendering.
//case WM_PAINT: {
// // Checking for isOpen will keep us from generating an event
// // during the window creation process, which can cause problems
// // with the journaling.
// if (window && window->isOpen() && !winState.renderThreadBlocked )
// window->displayEvent.trigger(devId);
//}
case WM_SIZE: {
if (window && wParam != SIZE_MINIMIZED && !Journal::IsPlaying())
{
window->resizeEvent.trigger(window->getWindowId(), LOWORD(lParam),HIWORD(lParam));
// Consume all existing mouse events and those posted to our own dispatch queue
MSG msg;
PeekMessage( &msg, 0,WM_MOUSEFIRST,WM_MOUSELAST , PM_QS_POSTMESSAGE | PM_NOYIELD | PM_REMOVE );
RemoveMessages( NULL, WM_MOUSEMOVE, WM_MOUSEMOVE );
if( window->isMouseLocked())
{
RECT r;
GetWindowRect(window->getHWND(), &r);
S32 centerX = (r.right + r.left) >> 1;
S32 centerY = ((r.bottom + r.top) >> 1);
window->setCursorPosition( centerX, centerY );
// Set the CursorPos
SetCursorPos(centerX, centerY);
}
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Structure used to store Windows events for delayed dispatching
struct WinMessageQueue
{
public:
struct Message {
HWND hWnd;
UINT message;
WPARAM wparam;
WPARAM lparam;
};
WinMessageQueue()
{
VECTOR_SET_ASSOCIATION( _messageList );
}
bool isEmpty() {
return !_messageList.size();
}
void post(HWND hWnd,UINT message,WPARAM wparam,WPARAM lparam) {
Message msg;
msg.hWnd = hWnd;
msg.message = message;
msg.wparam = wparam;
msg.lparam = lparam;
_messageList.push_back(msg);
}
bool next(Message* msg) {
if (!_messageList.size())
return false;
*msg = _messageList.first();
_messageList.pop_front();
return true;
}
void remove(HWND hWnd, UINT msgBegin = -1, UINT msgEnd = -1) {
for (S32 i = 0; i < _messageList.size(); i++)
{
// Match Window
if( hWnd != NULL && _messageList[i].hWnd == hWnd)
_messageList.erase_fast(i--);
else if( msgBegin != -1 && msgEnd != -1 )
{
// CodeReview - Match Message Range [6/30/2007 justind]
//
// Word of caution : Use this only if you know what you're doing.
// I cannot be responsible for you blowing your leg off destroying
// a bunch of messages you didn't intend to if you specify a ridiculous
// range of messages values.
//
// To filter a single message, pass the message as the begin and end.
if( _messageList[i].message >= msgBegin && _messageList[i].message <= msgEnd )
_messageList.erase_fast(i--);
}
}
}
private:
Vector<Message> _messageList;
};
static WinMessageQueue _MessageQueue;
void RemoveMessages(HWND hWnd,UINT msgBegin,WPARAM msgEnd )
{
_MessageQueue.remove( hWnd, msgBegin, msgEnd );
}
// Dispatch the window event, or queue up for later
void Dispatch(DispatchType type,HWND hWnd,UINT message,WPARAM wparam,WPARAM lparam)
{
// If the message queue is not empty, then we'll need to delay
// this dispatch in order to preserve message order.
if (type == DelayedDispatch || !_MessageQueue.isEmpty())
_MessageQueue.post(hWnd,message,wparam,lparam);
else
_dispatch(hWnd,message,wparam,lparam);
}
// Dispatch next even in the queue
bool DispatchNext()
{
WinMessageQueue::Message msg;
if (!_MessageQueue.next(&msg))
return false;
_dispatch(msg.hWnd,msg.message,msg.wparam,msg.lparam);
return true;
}
// Remove events from the queue
void DispatchRemove(HWND hWnd)
{
_MessageQueue.remove(hWnd);
}

View file

@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _WINDOWMANAGER_WIN32_WINDISPATCH_H_
#define _WINDOWMANAGER_WIN32_WINDISPATCH_H_
//
// *** This header requires that Window.h be included before this.
//
/// Some events must be processed immediately, and others can or should be
/// processed later. This enum allows us to distinguish between the two
/// types.
enum DispatchType {
DelayedDispatch,
ImmediateDispatch,
};
/// Dispatch the event into the journaling system.
///
/// Dispatch Win32 events into the journaling system. To avoid problems
/// with journaling, events should normally use the DelayedDispatch type.
///
/// Delayed events are pushed onto a queue for later processing by DispatchNext().
void Dispatch(DispatchType,HWND hWnd,UINT message,WPARAM wparam,WPARAM lparam);
/// Remove messages from the event queue, matching a msg value range or hWnd
///
/// If no filter is specified, either HWND or MessageRange, nothing will be removed
/// You may not match HWND and MsgRange both, currently.
///
/// Message Range is calculated as follows.
/// @li Both Begin and End are specified as message values, ex WM_MOUSEMOVE
/// @li Specifying an identical set of begin/end will remove all messages matching that message value (WM_MOUSEMOVE)
/// @li If you specify a range it will remove from that beginning value through the end value
///
/// @note : The range is useful because on windows messages declared such that you can filter a block of
/// messages just by specifying the beginning value and end.
/// ex. WM_MOUSEFIRST,WM_MOUSELAST range will match all mouse messages.
///
/// @param hWnd The HWND to filter by, this cannot be combined with a msg range filter currently
/// @param msgBegin The beginning msg value to filter from
/// @param msgEnd The ending msg value to filter to
void RemoveMessages(HWND hWnd,UINT msgBegin,UINT msgEnd );
/// Dispatch the next event in the delayed dispatch queue.
/// This function should be called outside of any journaled calls.
/// Returns true if an event was dispatched.
bool DispatchNext();
/// Remove events related to the window from the dispatch queue.
void DispatchRemove(HWND hWnd);
#endif