mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-21 12:25:30 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
|
|
@ -0,0 +1,29 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "windowManager/dedicated/dedicatedWindowStub.h"
|
||||
|
||||
|
||||
PlatformWindowManager *CreatePlatformWindowManager()
|
||||
{
|
||||
return new DedicatedWindowMgr;
|
||||
}
|
||||
109
Engine/source/windowManager/dedicated/dedicatedWindowStub.h
Normal file
109
Engine/source/windowManager/dedicated/dedicatedWindowStub.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef TORQUE_DEDICATED
|
||||
|
||||
#ifndef _DEDICATED_WINDOW_STUB_H_
|
||||
#define _DEDICATED_WINDOW_STUB_H_
|
||||
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
|
||||
/// The DedicatedWindowMgr is for Dedicated servers, which may not
|
||||
/// even have graphics hardware. However, the WindowManager is referenced
|
||||
/// (indirectly) by scripts, and therefore must exist.
|
||||
class DedicatedWindowMgr : public PlatformWindowManager
|
||||
{
|
||||
public:
|
||||
|
||||
DedicatedWindowMgr() {};
|
||||
|
||||
virtual ~DedicatedWindowMgr()
|
||||
{
|
||||
}
|
||||
|
||||
static void processCmdLineArgs(const S32 argc, const char **argv) {}
|
||||
|
||||
/// Return the extents in window coordinates of the primary desktop
|
||||
/// area. On dedicated systems, this returns a token value of 0.
|
||||
virtual RectI getPrimaryDesktopArea() { return RectI(0, 0, 0, 0); }
|
||||
|
||||
/// Retrieve the currently set desktop bit depth.
|
||||
/// @return -1 since there is no desktop
|
||||
virtual S32 getDesktopBitDepth() { return -1; }
|
||||
|
||||
/// Retrieve the currently set desktop resolution
|
||||
/// @return Point2I(-1,-1) since there is no desktop
|
||||
virtual Point2I getDesktopResolution() { return Point2I(-1, -1); }
|
||||
|
||||
/// Populate a vector with the token primary desktop area value
|
||||
virtual void getMonitorRegions(Vector<RectI> ®ions) { regions.push_back(getPrimaryDesktopArea()); }
|
||||
|
||||
/// Create a new window, appropriate for the specified device and mode.
|
||||
///
|
||||
/// @return NULL - there is no graphics hardware available in dedicated mode
|
||||
virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode) { return NULL; }
|
||||
|
||||
/// Produces an empty list since there are no windows in dedicated mode
|
||||
virtual void getWindows(VectorPtr<PlatformWindow*> &windows) { windows.clear(); }
|
||||
|
||||
/// Get the window that currently has the input focus or NULL.
|
||||
virtual PlatformWindow* getFocusedWindow() { return NULL; }
|
||||
|
||||
/// Get a window from a device ID.
|
||||
///
|
||||
/// @return NULL.
|
||||
virtual PlatformWindow *getWindowById(WindowId id) { return NULL; }
|
||||
|
||||
/// Get the first window in the window list
|
||||
///
|
||||
/// @return The first window in the list, or NULL if no windows found
|
||||
virtual PlatformWindow *getFirstWindow() { return NULL; }
|
||||
|
||||
|
||||
/// Set the parent window
|
||||
///
|
||||
/// This does nothing in dedicated builds
|
||||
virtual void setParentWindow(void* newParent) {}
|
||||
|
||||
/// Get the parent window - returns NULL for dedicated servers
|
||||
virtual void* getParentWindow() { return NULL; }
|
||||
|
||||
|
||||
/// This method cues the appearance of that window ("lowering the curtain").
|
||||
virtual void lowerCurtain() {}
|
||||
|
||||
/// @see lowerCurtain
|
||||
///
|
||||
/// This method removes the curtain window.
|
||||
virtual void raiseCurtain() {}
|
||||
|
||||
private:
|
||||
/// Process command line arguments from StandardMainLoop. This is done to
|
||||
/// allow web plugin functionality, where we are passed platform-specific
|
||||
/// information allowing us to set ourselves up in the web browser,
|
||||
/// to occur in a platform-neutral way.
|
||||
virtual void _processCmdLineArgs(const S32 argc, const char **argv) {}
|
||||
};
|
||||
|
||||
#endif // _DEDICATED_WINDOW_STUB_H_
|
||||
|
||||
#endif // TORQUE_DEDICATED
|
||||
50
Engine/source/windowManager/mac/macCursorController.h
Normal file
50
Engine/source/windowManager/mac/macCursorController.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _MACCURSORCONTROLLER_H_
|
||||
#define _MACCURSORCONTROLLER_H_
|
||||
|
||||
#include "windowManager/platformCursorController.h"
|
||||
|
||||
class MacCursorController : public PlatformCursorController
|
||||
{
|
||||
public:
|
||||
MacCursorController(MacWindow* owner)
|
||||
: PlatformCursorController( ( PlatformWindow* ) owner )
|
||||
{
|
||||
pushCursor(PlatformCursorController::curArrow);
|
||||
}
|
||||
|
||||
virtual void setCursorPosition(S32 x, S32 y);
|
||||
virtual void getCursorPosition(Point2I &point);
|
||||
virtual void setCursorVisible(bool visible);
|
||||
virtual bool isCursorVisible();
|
||||
|
||||
virtual void setCursorShape(U32 cursorID);
|
||||
virtual void setCursorShape( const UTF8 *fileName, bool reload );
|
||||
|
||||
virtual U32 getDoubleClickTime();
|
||||
virtual S32 getDoubleClickWidth();
|
||||
virtual S32 getDoubleClickHeight();
|
||||
};
|
||||
|
||||
#endif
|
||||
166
Engine/source/windowManager/mac/macCursorController.mm
Normal file
166
Engine/source/windowManager/mac/macCursorController.mm
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 <Carbon/Carbon.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include "windowManager/mac/macWindow.h"
|
||||
#include "windowManager/mac/macCursorController.h"
|
||||
|
||||
void MacCursorController::setCursorPosition(S32 x, S32 y)
|
||||
{
|
||||
MacWindow* macWindow = dynamic_cast<MacWindow*>(mOwner);
|
||||
if(!macWindow || !macWindow->isVisible())
|
||||
return;
|
||||
|
||||
CGPoint pt = { x, y };
|
||||
CGWarpMouseCursorPosition(pt);
|
||||
|
||||
macWindow->_skipAnotherMouseEvent();
|
||||
}
|
||||
|
||||
void MacCursorController::getCursorPosition( Point2I &point )
|
||||
{
|
||||
NSPoint pos = [NSEvent mouseLocation];
|
||||
point.x = pos.x;
|
||||
point.y = pos.y;
|
||||
|
||||
//what does this do?? comment??
|
||||
|
||||
MacWindow* macWindow = static_cast<MacWindow*>(mOwner);
|
||||
|
||||
CGRect bounds = macWindow->getDisplayBounds();
|
||||
CGRect mainbounds = macWindow->getMainDisplayBounds();
|
||||
F32 offsetY = mainbounds.size.height - (bounds.size.height + bounds.origin.y);
|
||||
point.y = bounds.size.height + offsetY - point.y;
|
||||
}
|
||||
|
||||
void MacCursorController::setCursorVisible(bool visible)
|
||||
{
|
||||
visible ? [NSCursor unhide] : [NSCursor hide];
|
||||
}
|
||||
|
||||
bool MacCursorController::isCursorVisible()
|
||||
{
|
||||
return CGCursorIsVisible();
|
||||
}
|
||||
|
||||
// a repository of custom cursors.
|
||||
@interface TorqueCursors : NSObject { }
|
||||
+(NSCursor*)resizeAll;
|
||||
+(NSCursor*)resizeNWSE;
|
||||
+(NSCursor*)resizeNESW;
|
||||
@end
|
||||
@implementation TorqueCursors
|
||||
+(NSCursor*)resizeAll
|
||||
{
|
||||
static NSCursor* cur = nil;
|
||||
if(!cur)
|
||||
cur = [[NSCursor alloc] initWithImage:[NSImage imageNamed:@"resizeAll"] hotSpot:NSMakePoint(8, 8)];
|
||||
return cur;
|
||||
}
|
||||
+(NSCursor*)resizeNWSE
|
||||
{
|
||||
static NSCursor* cur = nil;
|
||||
if(!cur)
|
||||
cur = [[NSCursor alloc] initWithImage:[NSImage imageNamed:@"resizeNWSE"] hotSpot:NSMakePoint(8, 8)];
|
||||
return cur;
|
||||
}
|
||||
+(NSCursor*)resizeNESW
|
||||
{
|
||||
static NSCursor* cur = nil;
|
||||
if(!cur)
|
||||
cur = [[NSCursor alloc] initWithImage:[NSImage imageNamed:@"resizeNESW"] hotSpot:NSMakePoint(8, 8)];
|
||||
return cur;
|
||||
}
|
||||
@end
|
||||
|
||||
void MacCursorController::setCursorShape(U32 cursorID)
|
||||
{
|
||||
NSCursor *cur;
|
||||
switch(cursorID)
|
||||
{
|
||||
case PlatformCursorController::curArrow:
|
||||
[[NSCursor arrowCursor] set];
|
||||
break;
|
||||
case PlatformCursorController::curWait:
|
||||
// hack: black-sheep carbon call
|
||||
SetThemeCursor(kThemeWatchCursor);
|
||||
break;
|
||||
case PlatformCursorController::curPlus:
|
||||
[[NSCursor crosshairCursor] set];
|
||||
break;
|
||||
case PlatformCursorController::curResizeVert:
|
||||
[[NSCursor resizeLeftRightCursor] set];
|
||||
break;
|
||||
case PlatformCursorController::curIBeam:
|
||||
[[NSCursor IBeamCursor] set];
|
||||
break;
|
||||
case PlatformCursorController::curResizeAll:
|
||||
cur = [TorqueCursors resizeAll];
|
||||
[cur set];
|
||||
break;
|
||||
case PlatformCursorController::curResizeNESW:
|
||||
[[TorqueCursors resizeNESW] set];
|
||||
break;
|
||||
case PlatformCursorController::curResizeNWSE:
|
||||
[[TorqueCursors resizeNWSE] set];
|
||||
break;
|
||||
case PlatformCursorController::curResizeHorz:
|
||||
[[NSCursor resizeUpDownCursor] set];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacCursorController::setCursorShape( const UTF8 *fileName, bool reload )
|
||||
{
|
||||
//TODO: this is untested code
|
||||
|
||||
NSString* strFileName = [ NSString stringWithUTF8String: fileName ];
|
||||
|
||||
// Load image file.
|
||||
|
||||
NSImage* image = [ NSImage alloc ];
|
||||
if( [ image initWithContentsOfFile: strFileName ] == nil )
|
||||
return;
|
||||
|
||||
// Allocate cursor.
|
||||
|
||||
NSCursor* cursor = [ NSCursor alloc ];
|
||||
[ cursor initWithImage: image hotSpot: NSMakePoint( 0.5, 0.5 ) ];
|
||||
}
|
||||
|
||||
U32 MacCursorController::getDoubleClickTime()
|
||||
{
|
||||
return GetDblTime() / 60.0f * 1000.0f;
|
||||
}
|
||||
|
||||
S32 MacCursorController::getDoubleClickWidth()
|
||||
{
|
||||
// This is an arbitrary value.
|
||||
return 10;
|
||||
}
|
||||
|
||||
S32 MacCursorController::getDoubleClickHeight()
|
||||
{
|
||||
return getDoubleClickWidth();
|
||||
}
|
||||
|
||||
75
Engine/source/windowManager/mac/macView.h
Normal file
75
Engine/source/windowManager/mac/macView.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _MACVIEW_H_
|
||||
#define _MACVIEW_H_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "windowManager/mac/macWindow.h"
|
||||
|
||||
/// GGMacView handles displaying content and responding to user input.
|
||||
@interface GGMacView : NSOpenGLView
|
||||
{
|
||||
MacWindow* mTorqueWindow;
|
||||
U32 mLastMods;
|
||||
bool mHandledAsCharEvent;
|
||||
}
|
||||
- (void)setTorqueWindow:(MacWindow*)theWindow;
|
||||
- (MacWindow*)torqueWindow;
|
||||
|
||||
/// @name Inherited Mouse Input methods
|
||||
/// @{
|
||||
- (void)mouseDown:(NSEvent *)theEvent;
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent;
|
||||
- (void)mouseDragged:(NSEvent *)theEvent;
|
||||
- (void)rightMouseDragged:(NSEvent *)theEvent;
|
||||
- (void)mouseUp:(NSEvent *)theEvent;
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent;
|
||||
- (void)mouseMoved:(NSEvent *)theEvent;
|
||||
- (void)scrollWheel:(NSEvent *)theEvent;
|
||||
/// @}
|
||||
|
||||
/// @name Inherited Keyboard Input methods
|
||||
/// @{
|
||||
- (void)keyDown:(NSEvent *)theEvent;
|
||||
- (void)keyUp:(NSEvent *)theEvent;
|
||||
/// @}
|
||||
|
||||
/// @name Keyboard Input Common Code
|
||||
/// @{
|
||||
- (void)rawKeyUpDown:(NSEvent *)theEvent keyDown:(BOOL)isKeyDown;
|
||||
/// @}
|
||||
|
||||
/// @name Mouse Input Common Code
|
||||
/// @{
|
||||
- (void)mouseUpDown:(NSEvent *)theEvent mouseDown:(BOOL)isMouseDown;
|
||||
- (void)mouseMotion:(NSEvent *)theEvent;
|
||||
/// @}
|
||||
|
||||
- (BOOL)acceptsFirstResponder;
|
||||
- (BOOL)becomeFirstResponder;
|
||||
- (BOOL)resignFirstResponder;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
401
Engine/source/windowManager/mac/macView.mm
Normal file
401
Engine/source/windowManager/mac/macView.mm
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "windowManager/mac/macView.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/platformInput.h"
|
||||
#include "console/console.h"
|
||||
#include "sim/actionMap.h"
|
||||
#include "app/mainLoop.h"
|
||||
|
||||
// For left/right side definitions.
|
||||
#include <IOKit/hidsystem/IOLLEvent.h>
|
||||
|
||||
|
||||
#define WHEEL_DELTA ( 120 * 0.1 )
|
||||
|
||||
static bool smApplicationInactive = false;
|
||||
|
||||
|
||||
extern InputModifiers convertModifierBits( const U32 in );
|
||||
|
||||
|
||||
inline U32 NSModifiersToTorqueModifiers( NSUInteger mods )
|
||||
{
|
||||
U32 torqueMods = 0;
|
||||
|
||||
if( mods & NX_DEVICELSHIFTKEYMASK )
|
||||
torqueMods |= IM_LSHIFT;
|
||||
if( mods & NX_DEVICERSHIFTKEYMASK )
|
||||
torqueMods |= IM_RSHIFT;
|
||||
if( mods & NX_DEVICELALTKEYMASK )
|
||||
torqueMods |= IM_LOPT;
|
||||
if( mods & NX_DEVICERALTKEYMASK )
|
||||
torqueMods |= IM_ROPT;
|
||||
if( mods & NX_DEVICELCTLKEYMASK )
|
||||
torqueMods |= IM_LCTRL;
|
||||
if( mods & NX_DEVICERCTLKEYMASK )
|
||||
torqueMods |= IM_RCTRL;
|
||||
if( mods & NX_DEVICELCMDKEYMASK )
|
||||
torqueMods |= IM_LALT;
|
||||
if( mods & NX_DEVICERCMDKEYMASK )
|
||||
torqueMods |= IM_RALT;
|
||||
|
||||
Input::setModifierKeys( convertModifierBits( torqueMods ) );
|
||||
|
||||
return torqueMods;
|
||||
}
|
||||
|
||||
|
||||
@implementation GGMacView
|
||||
- (void)setTorqueWindow:(MacWindow*)theWindow
|
||||
{
|
||||
mTorqueWindow = theWindow;
|
||||
mLastMods = 0;
|
||||
}
|
||||
|
||||
- (MacWindow*)torqueWindow
|
||||
{
|
||||
return mTorqueWindow;
|
||||
}
|
||||
|
||||
-(void)trackModState:(U32)torqueKey withMacMods:(U32)macMods event:(NSEvent*)theEvent
|
||||
{
|
||||
// track state:
|
||||
// translate the torque key code to the torque flag that changed
|
||||
// xor with existing mods for new mod state
|
||||
// clear anything that the mac says both siblings are not down ( to help stay in sync, a little bit )
|
||||
|
||||
// ?set left sibling of anything that the mac says some sibling is down, but that we don't see as down?
|
||||
|
||||
U32 torqueMod = 0;
|
||||
switch(torqueKey)
|
||||
{
|
||||
case KEY_LSHIFT: torqueMod = IM_LSHIFT; break;
|
||||
case KEY_RSHIFT: torqueMod = IM_RSHIFT; break;
|
||||
case KEY_LCONTROL: torqueMod = IM_LCTRL; break;
|
||||
case KEY_RCONTROL: torqueMod = IM_RCTRL; break;
|
||||
case KEY_MAC_LOPT: torqueMod = IM_LOPT; break;
|
||||
case KEY_MAC_ROPT: torqueMod = IM_ROPT; break;
|
||||
case KEY_LALT: torqueMod = IM_LALT; break;
|
||||
case KEY_RALT: torqueMod = IM_RALT; break;
|
||||
};
|
||||
|
||||
// flip the mod that we got an event for
|
||||
U32 newMods = mLastMods ^ torqueMod;
|
||||
|
||||
// clear left and right if mac thinks both are up.
|
||||
if( !(macMods & NSShiftKeyMask)) newMods &= ~IM_LSHIFT, newMods &= ~IM_RSHIFT;
|
||||
if( !(macMods & NSControlKeyMask)) newMods &= ~IM_LCTRL, newMods &= ~IM_RCTRL;
|
||||
if( !(macMods & NSAlternateKeyMask)) newMods &= ~IM_LOPT, newMods &= ~IM_ROPT;
|
||||
if( !(macMods & NSCommandKeyMask)) newMods &= ~IM_LALT, newMods &= ~IM_RALT;
|
||||
|
||||
// Generate keyUp/Down event (allows us to use modifier keys for actions)
|
||||
mLastMods = 0;
|
||||
[self rawKeyUpDown:theEvent keyDown:(newMods & torqueMod)];
|
||||
|
||||
mLastMods = newMods;
|
||||
|
||||
Input::setModifierKeys( convertModifierBits( mLastMods ) );
|
||||
}
|
||||
|
||||
- (Point2I)viewCoordsToTorqueCoords:(NSPoint)mousePoint
|
||||
{
|
||||
if(mTorqueWindow->isFullscreen())
|
||||
{
|
||||
CGRect bounds = mTorqueWindow->getDisplayBounds();
|
||||
CGRect mainbounds = mTorqueWindow->getMainDisplayBounds();
|
||||
F32 offsetY = mainbounds.size.height - (bounds.size.height + bounds.origin.y);
|
||||
Point2I pt(mousePoint.x - bounds.origin.x, bounds.size.height + offsetY - mousePoint.y);
|
||||
return pt;
|
||||
}
|
||||
return Point2I(mousePoint.x, mTorqueWindow->getClientExtent().y - mousePoint.y);
|
||||
}
|
||||
|
||||
- (void)signalGainFocus
|
||||
{
|
||||
if(smApplicationInactive)
|
||||
smApplicationInactive = false;
|
||||
|
||||
bool gainFocus = static_cast<MacWindowManager*>(WindowManager)->canWindowGainFocus(mTorqueWindow);
|
||||
if(gainFocus)
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), GainFocus);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Mouse Input
|
||||
// We're funnelling all the standard cocoa event handlers to -mouseUpDown and -mouseMotion.
|
||||
- (void)mouseDown:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:YES]; }
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:YES]; }
|
||||
- (void)otherMouseDown:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:YES]; }
|
||||
- (void)mouseUp:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:NO]; }
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:NO]; }
|
||||
- (void)otherMouseUp:(NSEvent *)theEvent { [self mouseUpDown:theEvent mouseDown:NO]; }
|
||||
- (void)mouseDragged:(NSEvent *)theEvent { [self mouseMotion:theEvent]; }
|
||||
- (void)rightMouseDragged:(NSEvent *)theEvent { [self mouseMotion:theEvent]; }
|
||||
- (void)otherMouseDragged:(NSEvent *)theEvent { [self mouseMotion:theEvent]; }
|
||||
- (void)mouseMoved:(NSEvent *)theEvent { [self mouseMotion:theEvent]; }
|
||||
|
||||
- (void)mouseUpDown:(NSEvent *)theEvent mouseDown:(BOOL)isMouseDown
|
||||
{
|
||||
Point2I eventLocation = [self viewCoordsToTorqueCoords: [theEvent locationInWindow]];
|
||||
U16 buttonNumber = [theEvent buttonNumber];
|
||||
U32 action = isMouseDown ? SI_MAKE : SI_BREAK;
|
||||
|
||||
// If the event location is negative then it occurred in the structure region (e.g. title bar, resize corner), and we don't want
|
||||
// to lock the mouse/drop into fullscreen for that.
|
||||
if(WindowManager->getFocusedWindow() != mTorqueWindow && eventLocation.x > 0 && eventLocation.y > 0)
|
||||
[self signalGainFocus];
|
||||
|
||||
mLastMods = NSModifiersToTorqueModifiers( [ theEvent modifierFlags ] );
|
||||
|
||||
mTorqueWindow->buttonEvent.trigger(mTorqueWindow->getWindowId(), mLastMods, action, buttonNumber);
|
||||
}
|
||||
|
||||
- (void)mouseMotion:(NSEvent *)theEvent
|
||||
{
|
||||
mTorqueWindow->_doMouseLockNow();
|
||||
|
||||
// when moving the mouse to the center of the window for mouse locking, we need
|
||||
// to skip the next mouse delta event
|
||||
if(mTorqueWindow->isMouseLocked() && mTorqueWindow->_skipNextMouseEvent())
|
||||
{
|
||||
mTorqueWindow->_skippedMouseEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
Point2I eventLocation;
|
||||
if(mTorqueWindow->isMouseLocked())
|
||||
{
|
||||
eventLocation.x = [theEvent deltaX];
|
||||
eventLocation.y = [theEvent deltaY];
|
||||
}
|
||||
else
|
||||
{
|
||||
eventLocation = [self viewCoordsToTorqueCoords:[theEvent locationInWindow]];
|
||||
}
|
||||
|
||||
mLastMods = NSModifiersToTorqueModifiers( [ theEvent modifierFlags ] );
|
||||
|
||||
mTorqueWindow->mouseEvent.trigger(mTorqueWindow->getWindowId(), mLastMods, eventLocation.x, eventLocation.y, mTorqueWindow->isMouseLocked());
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)theEvent
|
||||
{
|
||||
float deltaX = [ theEvent deltaX ];
|
||||
float deltaY = [ theEvent deltaY ];
|
||||
|
||||
if( mIsZero( deltaX ) && mIsZero( deltaY ) )
|
||||
return;
|
||||
|
||||
mLastMods = NSModifiersToTorqueModifiers( [ theEvent modifierFlags ] );
|
||||
|
||||
mTorqueWindow->wheelEvent.trigger( mTorqueWindow->getWindowId(), mLastMods, S32( deltaX * WHEEL_DELTA ), S32( deltaY * WHEEL_DELTA ) );
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Keyboard Input
|
||||
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
|
||||
{
|
||||
// Pass it off to the main menu. If the main menu handled it, we're done.
|
||||
if([[NSApp mainMenu] performKeyEquivalent:theEvent])
|
||||
return YES;
|
||||
|
||||
// cmd-q will quit. End of story.
|
||||
if(([theEvent modifierFlags] & NSCommandKeyMask && !([theEvent modifierFlags] & NSAlternateKeyMask) && !([theEvent modifierFlags] & NSControlKeyMask)) && [theEvent keyCode] == 0x0C)
|
||||
{
|
||||
StandardMainLoop::shutdown();
|
||||
[NSApp terminate:self];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// In fullscreen we grab ALL keyboard events, including ones which would normally be handled by the system,
|
||||
// like cmd-tab. Thus, we need to specifically check for cmd-tab and bail out of fullscreen and hide the app
|
||||
// to switch to the next application.
|
||||
// 0x30 is tab, so this grabs command-tab and command-shift-tab
|
||||
if([theEvent keyCode] == 0x30 && mTorqueWindow->isFullscreen())
|
||||
{
|
||||
// Bail!
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), LoseFocus);
|
||||
[NSApp hide:nil];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// All other events are uninteresting to us and can be handled by Torque.
|
||||
if([theEvent type] == NSKeyDown)
|
||||
[self keyDown:theEvent];
|
||||
else if([theEvent type] == NSKeyUp)
|
||||
[self keyUp:theEvent];
|
||||
|
||||
// Don't let the default handler continue processing these events, it does things we don't like.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)theEvent
|
||||
{
|
||||
U32 torqueKeyCode = TranslateOSKeyCode([theEvent keyCode]);
|
||||
U32 macMods = [theEvent modifierFlags];
|
||||
[self trackModState:torqueKeyCode withMacMods:macMods event:theEvent];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
// If keyboard translation is on and the key isn't bound in the
|
||||
// global action map, first try turning this into one or more
|
||||
// character events.
|
||||
|
||||
if( mTorqueWindow->getKeyboardTranslation()
|
||||
&& !mTorqueWindow->shouldNotTranslate(
|
||||
convertModifierBits( NSModifiersToTorqueModifiers( [ theEvent modifierFlags ] ) ),
|
||||
( InputObjectInstances ) TranslateOSKeyCode( [ theEvent keyCode ] ) ) )
|
||||
{
|
||||
mHandledAsCharEvent = false;
|
||||
[ self interpretKeyEvents: [ NSArray arrayWithObject: theEvent ] ];
|
||||
|
||||
if( mHandledAsCharEvent )
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire as raw keyboard event.
|
||||
|
||||
[ self rawKeyUpDown: theEvent keyDown: YES ];
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)theEvent
|
||||
{
|
||||
[self rawKeyUpDown:theEvent keyDown:NO];
|
||||
}
|
||||
|
||||
- (void)rawKeyUpDown:(NSEvent *)theEvent keyDown:(BOOL)isKeyDown
|
||||
{
|
||||
U32 action;
|
||||
if([theEvent type] != NSFlagsChanged)
|
||||
action = isKeyDown ? ([theEvent isARepeat] ? SI_REPEAT : SI_MAKE) : SI_BREAK;
|
||||
else
|
||||
action = isKeyDown ? SI_MAKE : SI_BREAK;
|
||||
|
||||
U32 torqueKeyCode = TranslateOSKeyCode([theEvent keyCode]);
|
||||
mLastMods = NSModifiersToTorqueModifiers( [ theEvent modifierFlags ] );
|
||||
|
||||
mTorqueWindow->keyEvent.trigger(mTorqueWindow->getWindowId(), mLastMods, action, torqueKeyCode);
|
||||
}
|
||||
|
||||
- (void)insertText:(id)_inString
|
||||
{
|
||||
// input string may be an NSString or an NSAttributedString
|
||||
NSString *text = [_inString isKindOfClass:[NSAttributedString class]] ? [_inString string] : _inString;
|
||||
for(int i = 0; i < [text length]; i++)
|
||||
{
|
||||
mTorqueWindow->charEvent.trigger(mTorqueWindow->getWindowId(), mLastMods, [text characterAtIndex:i]);
|
||||
mHandledAsCharEvent = true;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Application Delegate
|
||||
- (void)applicationDidResignActive:(NSNotification *)aNotification
|
||||
{
|
||||
smApplicationInactive = true;
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), LoseFocus);
|
||||
[NSApp setDelegate:nil];
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)aNotification
|
||||
{
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), LoseFocus);
|
||||
}
|
||||
|
||||
- (void)applicationDidUnhide:(NSNotification *)aNotification
|
||||
{
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), GainFocus);
|
||||
}
|
||||
|
||||
#ifndef TORQUE_SHARED
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
|
||||
{
|
||||
Platform::postQuitMessage(0);
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Window Delegate
|
||||
- (BOOL)windowShouldClose:(NSWindow *)sender
|
||||
{
|
||||
// We close the window ourselves
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), WindowDestroy);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *) notification
|
||||
{
|
||||
mTorqueWindow->_disassociateCocoaWindow();
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
// when our window is the key window, we become the app delegate.
|
||||
PlatformWindow* focusWindow = WindowManager->getFocusedWindow();
|
||||
if(focusWindow && focusWindow != mTorqueWindow)
|
||||
focusWindow->appEvent.trigger(mTorqueWindow->getWindowId(), LoseFocus);
|
||||
[NSApp setDelegate:self];
|
||||
[self signalGainFocus];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification*)notification
|
||||
{
|
||||
mTorqueWindow->appEvent.trigger(mTorqueWindow->getWindowId(), LoseScreen);
|
||||
mTorqueWindow->_associateMouse();
|
||||
mTorqueWindow->setCursorVisible(true);
|
||||
[NSApp setDelegate:nil];
|
||||
}
|
||||
|
||||
- (void)windowDidChangeScreen:(NSNotification*)notification
|
||||
{
|
||||
NSWindow* wnd = [notification object];
|
||||
// TODO: Add a category to NSScreen to deal with this
|
||||
CGDirectDisplayID disp = (CGDirectDisplayID)[[[[wnd screen] deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue];
|
||||
mTorqueWindow->setDisplay(disp);
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification
|
||||
{
|
||||
Point2I clientExtent = mTorqueWindow->getClientExtent();
|
||||
mTorqueWindow->resizeEvent.trigger(mTorqueWindow->getWindowId(), clientExtent.x, clientExtent.y);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark responder status
|
||||
- (BOOL)acceptsFirstResponder { return YES; }
|
||||
- (BOOL)becomeFirstResponder { return YES; }
|
||||
- (BOOL)resignFirstResponder { return YES; }
|
||||
|
||||
// Basic implementation because NSResponder's default implementation can cause infinite loops when our keyDown: method calls interpretKeyEvents:
|
||||
- (void)doCommandBySelector:(SEL)aSelector
|
||||
{
|
||||
if([self respondsToSelector:aSelector])
|
||||
[self performSelector:aSelector withObject:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
191
Engine/source/windowManager/mac/macWindow.h
Normal file
191
Engine/source/windowManager/mac/macWindow.h
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _TORQUE_MACWINDOW_H_
|
||||
#define _TORQUE_MACWINDOW_H_
|
||||
|
||||
#include "windowManager/platformWindow.h"
|
||||
#include "windowManager/mac/macWindowManager.h"
|
||||
#include "windowManager/mac/macCursorController.h"
|
||||
|
||||
#ifndef _GFXTARGET_H_
|
||||
#include "gfx/gfxTarget.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GFXSTRUCTS_H_
|
||||
#include "gfx/gfxStructs.h"
|
||||
#endif
|
||||
|
||||
class MacWindow : public PlatformWindow
|
||||
{
|
||||
public:
|
||||
virtual ~MacWindow();
|
||||
|
||||
virtual GFXDevice *getGFXDevice() { return mDevice; }
|
||||
virtual GFXWindowTarget *getGFXTarget() { return mTarget; }
|
||||
virtual void setVideoMode(const GFXVideoMode &mode);
|
||||
virtual const GFXVideoMode &getVideoMode() { return mCurrentMode; }
|
||||
|
||||
virtual WindowId getWindowId() { return mWindowId; }
|
||||
|
||||
void setDisplay(CGDirectDisplayID display);
|
||||
CGDirectDisplayID getDisplay() { return mDisplay; }
|
||||
CGRect getMainDisplayBounds() { return mMainDisplayBounds; }
|
||||
CGRect getDisplayBounds() { return mDisplayBounds; }
|
||||
|
||||
virtual bool clearFullscreen()
|
||||
{
|
||||
// TODO: properly drop out of full screen
|
||||
return true;
|
||||
}
|
||||
virtual bool isFullscreen() { return mFullscreen; }
|
||||
|
||||
virtual PlatformWindow * getNextWindow() const;
|
||||
|
||||
virtual void setMouseLocked( bool enable )
|
||||
{
|
||||
mShouldMouseLock = enable;
|
||||
if(isFocused())
|
||||
_doMouseLockNow();
|
||||
}
|
||||
virtual bool isMouseLocked() const { return mMouseLocked; }
|
||||
virtual bool shouldLockMouse() const { return mShouldMouseLock; }
|
||||
|
||||
virtual bool setSize(const Point2I &newSize);
|
||||
|
||||
virtual void setClientExtent( const Point2I newExtent );
|
||||
virtual const Point2I getClientExtent();
|
||||
|
||||
virtual void setBounds( const RectI &newBounds );
|
||||
virtual const RectI getBounds() const;
|
||||
|
||||
virtual void setPosition( const Point2I newPosition );
|
||||
virtual const Point2I getPosition();
|
||||
|
||||
virtual void centerWindow();
|
||||
|
||||
virtual Point2I clientToScreen( const Point2I& pos );
|
||||
virtual Point2I screenToClient( const Point2I& pos );
|
||||
|
||||
virtual bool setCaption(const char *windowText);
|
||||
virtual const char *getCaption() { return mTitle; }
|
||||
|
||||
virtual bool setType( S32 windowType ) { return true; }
|
||||
|
||||
virtual void minimize();
|
||||
virtual void maximize();
|
||||
virtual void restore();
|
||||
virtual bool isMinimized();
|
||||
virtual bool isMaximized();
|
||||
virtual void show();
|
||||
virtual void close();
|
||||
virtual void hide();
|
||||
virtual bool isOpen();
|
||||
virtual bool isVisible();
|
||||
|
||||
virtual bool isFocused();
|
||||
virtual void setFocus();
|
||||
virtual void clearFocus();
|
||||
|
||||
virtual void* getPlatformDrawable() const;
|
||||
|
||||
// TODO: These should be private, but GGMacView (an Obj-C class) needs access to these and we can't friend Obj-C classes
|
||||
bool _skipNextMouseEvent() { return mSkipMouseEvents != 0; }
|
||||
void _skipAnotherMouseEvent() { mSkipMouseEvents++; }
|
||||
void _skippedMouseEvent() { mSkipMouseEvents--; }
|
||||
|
||||
/// Does the work of actually locking or unlocking the mouse, based on the
|
||||
/// value of shouldLockMouse().
|
||||
///
|
||||
/// Disassociates the cursor movement from the mouse input and hides the mouse
|
||||
/// when locking. Re-associates cursor movement with mouse input and shows the
|
||||
/// mouse when unlocking.
|
||||
///
|
||||
/// Returns true if we locked or unlocked the mouse. Returns false if the mouse
|
||||
/// was already in the correct state.
|
||||
void _doMouseLockNow();
|
||||
|
||||
// Helper methods for doMouseLockNow
|
||||
void _associateMouse();
|
||||
void _dissociateMouse();
|
||||
void _centerMouse();
|
||||
|
||||
// For GGMacView
|
||||
void _disassociateCocoaWindow();
|
||||
|
||||
// Safari support methods
|
||||
static void setSafariWindow(NSWindow *window, S32 x = 0, S32 y = 0, S32 width = 0, S32 height = 0);
|
||||
static void hideBrowserWindow(bool hide);
|
||||
|
||||
protected:
|
||||
virtual void _setFullscreen(bool fullScreen);
|
||||
|
||||
private:
|
||||
friend class MacWindowManager;
|
||||
friend class MacCursorController;
|
||||
|
||||
struct SafariWindowInfo
|
||||
{
|
||||
NSWindow* safariWindow; /* The Safari Browser Window */
|
||||
S32 x; /* Position of top left corner relative */
|
||||
S32 y; /* to a safari page. */
|
||||
U32 width; /* Maximum window size */
|
||||
U32 height;
|
||||
};
|
||||
|
||||
MacWindow(U32 windowId, const char* windowText, Point2I clientExtent);
|
||||
|
||||
void _initCocoaWindow(const char* windowText, Point2I clientExtent);
|
||||
void setWindowId(U32 newid) { mWindowId = newid;}
|
||||
void signalGainFocus();
|
||||
|
||||
static SafariWindowInfo* sSafariWindowInfo;
|
||||
static MacWindow* sInstance;
|
||||
|
||||
NSWindow* mCocoaWindow;
|
||||
GFXDevice *mDevice;
|
||||
GFXWindowTargetRef mTarget;
|
||||
GFXVideoMode mCurrentMode;
|
||||
|
||||
MacWindow *mNextWindow;
|
||||
|
||||
bool mMouseLocked;
|
||||
bool mShouldMouseLock;
|
||||
|
||||
const char* mTitle;
|
||||
bool mMouseCaptured;
|
||||
|
||||
MacWindowManager* mOwningWindowManager;
|
||||
U32 mSkipMouseEvents;
|
||||
|
||||
bool mFullscreen;
|
||||
bool mShouldFullscreen;
|
||||
NSDictionary* mDefaultDisplayMode;
|
||||
|
||||
void _onAppEvent(WindowId,S32);
|
||||
|
||||
CGDirectDisplayID mDisplay;
|
||||
CGRect mDisplayBounds;
|
||||
CGRect mMainDisplayBounds;
|
||||
};
|
||||
|
||||
#endif
|
||||
594
Engine/source/windowManager/mac/macWindow.mm
Normal file
594
Engine/source/windowManager/mac/macWindow.mm
Normal 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include "windowManager/mac/macWindow.h"
|
||||
#include "windowManager/mac/macView.h"
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
MacWindow::SafariWindowInfo* MacWindow::sSafariWindowInfo = NULL;
|
||||
MacWindow* MacWindow::sInstance = NULL;
|
||||
|
||||
@interface SafariBrowserWindow : NSWindow
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation SafariBrowserWindow
|
||||
|
||||
// Windows created with NSBorderlessWindowMask normally can't be key, but we want ours to be
|
||||
- (BOOL) canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
MacWindow::MacWindow(U32 windowId, const char* windowText, Point2I clientExtent)
|
||||
{
|
||||
mMouseLocked = false;
|
||||
mShouldMouseLock = false;
|
||||
mTitle = NULL;
|
||||
mMouseCaptured = false;
|
||||
|
||||
mCocoaWindow = NULL;
|
||||
mCursorController = new MacCursorController( this );
|
||||
mOwningWindowManager = NULL;
|
||||
|
||||
mFullscreen = false;
|
||||
mShouldFullscreen = false;
|
||||
mDefaultDisplayMode = NULL;
|
||||
|
||||
mSkipMouseEvents = 0;
|
||||
|
||||
mDisplay = kCGDirectMainDisplay;
|
||||
mMainDisplayBounds = mDisplayBounds = CGDisplayBounds(mDisplay);
|
||||
|
||||
mWindowId = windowId;
|
||||
_initCocoaWindow(windowText, clientExtent);
|
||||
|
||||
appEvent.notify(this, &MacWindow::_onAppEvent);
|
||||
|
||||
sInstance = this;
|
||||
}
|
||||
|
||||
MacWindow::~MacWindow()
|
||||
{
|
||||
if(mFullscreen)
|
||||
_setFullscreen(false);
|
||||
|
||||
appEvent.remove(this, &MacWindow::_onAppEvent);
|
||||
|
||||
//ensure our view isn't the delegate
|
||||
[NSApp setDelegate:nil];
|
||||
|
||||
if( mCocoaWindow )
|
||||
{
|
||||
NSWindow* window = mCocoaWindow;
|
||||
_disassociateCocoaWindow();
|
||||
|
||||
[ window close ];
|
||||
}
|
||||
|
||||
appEvent.trigger(mWindowId, LoseFocus);
|
||||
appEvent.trigger(mWindowId, WindowDestroy);
|
||||
|
||||
mOwningWindowManager->_removeWindow(this);
|
||||
|
||||
setSafariWindow(NULL);
|
||||
|
||||
sInstance = NULL;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void torque_setsafariwindow( NSWindow *window, S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
MacWindow::setSafariWindow(window, x, y, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MacWindow::hideBrowserWindow(bool hide)
|
||||
{
|
||||
if (sSafariWindowInfo && sInstance && sInstance->mCocoaWindow)
|
||||
{
|
||||
if (hide)
|
||||
{
|
||||
if (sSafariWindowInfo && sSafariWindowInfo->safariWindow)
|
||||
[sSafariWindowInfo->safariWindow removeChildWindow: sInstance->mCocoaWindow];
|
||||
|
||||
sInstance->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (sSafariWindowInfo && sSafariWindowInfo->safariWindow)
|
||||
[sSafariWindowInfo->safariWindow addChildWindow: sInstance->mCocoaWindow ordered:NSWindowAbove];
|
||||
|
||||
sInstance->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::setSafariWindow(NSWindow *window, S32 x, S32 y, S32 width, S32 height )
|
||||
{
|
||||
if (!window)
|
||||
{
|
||||
hideBrowserWindow(true);
|
||||
|
||||
if (sSafariWindowInfo)
|
||||
delete sSafariWindowInfo;
|
||||
|
||||
sSafariWindowInfo = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sSafariWindowInfo)
|
||||
{
|
||||
sSafariWindowInfo = new SafariWindowInfo;
|
||||
sSafariWindowInfo->safariWindow = window;
|
||||
sSafariWindowInfo->width = width;
|
||||
sSafariWindowInfo->height = height;
|
||||
sSafariWindowInfo->x = x;
|
||||
sSafariWindowInfo->y = y;
|
||||
if (sInstance && sInstance->mCocoaWindow)
|
||||
{
|
||||
[window addChildWindow: sInstance->mCocoaWindow ordered:NSWindowAbove];
|
||||
hideBrowserWindow(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sSafariWindowInfo->width = width;
|
||||
sSafariWindowInfo->height = height;
|
||||
sSafariWindowInfo->x = x;
|
||||
sSafariWindowInfo->y = y;
|
||||
}
|
||||
|
||||
if (sInstance && sInstance->mCocoaWindow)
|
||||
{
|
||||
//update position
|
||||
|
||||
NSRect frame = [sSafariWindowInfo->safariWindow frame];
|
||||
|
||||
NSPoint o = { (float)sSafariWindowInfo->x, frame.size.height - sSafariWindowInfo->y };
|
||||
NSPoint p = [sSafariWindowInfo->safariWindow convertBaseToScreen: o];
|
||||
|
||||
NSRect contentRect = NSMakeRect(p.x, p.y - sSafariWindowInfo->height, sSafariWindowInfo->width,sSafariWindowInfo->height);
|
||||
|
||||
// we have to set display to NO when resizing otherwise get hangs, perhaps add delegate to SafariBrowserWindow class?
|
||||
[sInstance->mCocoaWindow setFrame:contentRect display:NO];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MacWindow::_initCocoaWindow(const char* windowText, Point2I clientExtent)
|
||||
{
|
||||
// TODO: cascade windows on screen?
|
||||
|
||||
// create the window
|
||||
NSRect contentRect;
|
||||
U32 style;
|
||||
|
||||
if (sSafariWindowInfo)
|
||||
{
|
||||
|
||||
NSRect frame = [sSafariWindowInfo->safariWindow frame];
|
||||
|
||||
NSPoint o = { (float)sSafariWindowInfo->x, frame.size.height - sSafariWindowInfo->y };
|
||||
|
||||
NSPoint p = [sSafariWindowInfo->safariWindow convertBaseToScreen: o];
|
||||
|
||||
contentRect = NSMakeRect(0, 0, sSafariWindowInfo->width,sSafariWindowInfo->height);
|
||||
|
||||
style = NSBorderlessWindowMask;
|
||||
|
||||
mCocoaWindow = [[SafariBrowserWindow alloc] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:nil];
|
||||
|
||||
[mCocoaWindow setFrameTopLeftPoint: p];
|
||||
|
||||
[sSafariWindowInfo->safariWindow addChildWindow: mCocoaWindow ordered:NSWindowAbove];
|
||||
|
||||
// necessary to accept mouseMoved events
|
||||
[mCocoaWindow setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
contentRect = NSMakeRect(0,0,clientExtent.x, clientExtent.y);
|
||||
|
||||
style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
|
||||
|
||||
mCocoaWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:nil];
|
||||
if(windowText)
|
||||
[mCocoaWindow setTitle: [NSString stringWithUTF8String: windowText]];
|
||||
|
||||
// necessary to accept mouseMoved events
|
||||
[mCocoaWindow setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
// correctly position the window on screen
|
||||
[mCocoaWindow center];
|
||||
|
||||
}
|
||||
|
||||
// create the opengl view. we don't care about its pixel format, because we
|
||||
// will be replacing its context with another one.
|
||||
GGMacView* view = [[GGMacView alloc] initWithFrame:contentRect pixelFormat:[NSOpenGLView defaultPixelFormat]];
|
||||
[view setTorqueWindow:this];
|
||||
[mCocoaWindow setContentView:view];
|
||||
[mCocoaWindow setDelegate:view];
|
||||
|
||||
}
|
||||
|
||||
void MacWindow::_disassociateCocoaWindow()
|
||||
{
|
||||
if( !mCocoaWindow )
|
||||
return;
|
||||
|
||||
[mCocoaWindow setContentView:nil];
|
||||
[mCocoaWindow setDelegate:nil];
|
||||
|
||||
if (sSafariWindowInfo)
|
||||
[sSafariWindowInfo->safariWindow removeChildWindow: mCocoaWindow];
|
||||
|
||||
mCocoaWindow = NULL;
|
||||
}
|
||||
|
||||
void MacWindow::setVideoMode(const GFXVideoMode &mode)
|
||||
{
|
||||
mCurrentMode = mode;
|
||||
setSize(mCurrentMode.resolution);
|
||||
|
||||
if(mTarget.isValid())
|
||||
mTarget->resetMode();
|
||||
|
||||
_setFullscreen(mCurrentMode.fullScreen);
|
||||
}
|
||||
|
||||
void MacWindow::_onAppEvent(WindowId, S32 evt)
|
||||
{
|
||||
if(evt == LoseFocus && isFullscreen())
|
||||
{
|
||||
mShouldFullscreen = true;
|
||||
GFXVideoMode mode = mCurrentMode;
|
||||
mode.fullScreen = false;
|
||||
setVideoMode(mode);
|
||||
}
|
||||
|
||||
if(evt == GainFocus && !isFullscreen() && mShouldFullscreen)
|
||||
{
|
||||
mShouldFullscreen = false;
|
||||
GFXVideoMode mode = mCurrentMode;
|
||||
mode.fullScreen = true;
|
||||
setVideoMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::_setFullscreen(bool fullScreen)
|
||||
{
|
||||
if(mFullscreen == fullScreen)
|
||||
return;
|
||||
|
||||
mFullscreen = fullScreen;
|
||||
|
||||
if(mFullscreen)
|
||||
{
|
||||
Con::printf("Capturing display %x", mDisplay);
|
||||
CGDisplayCapture(mDisplay);
|
||||
[mCocoaWindow setAlphaValue:0.0f];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mDefaultDisplayMode)
|
||||
{
|
||||
Con::printf("Restoring default display mode... width: %i height: %i bpp: %i", [[mDefaultDisplayMode valueForKey:@"Width"] intValue],
|
||||
[[mDefaultDisplayMode valueForKey:@"Height"] intValue], [[mDefaultDisplayMode valueForKey:@"BitsPerPixel"] intValue]);
|
||||
CGDisplaySwitchToMode(mDisplay, (CFDictionaryRef)mDefaultDisplayMode);
|
||||
mDisplayBounds = CGDisplayBounds(mDisplay);
|
||||
if(mDisplay == kCGDirectMainDisplay)
|
||||
mMainDisplayBounds = mDisplayBounds;
|
||||
}
|
||||
|
||||
Con::printf("Releasing display %x", mDisplay);
|
||||
CGDisplayRelease(mDisplay);
|
||||
[mCocoaWindow setAlphaValue:1.0f];
|
||||
mDefaultDisplayMode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* MacWindow::getPlatformDrawable() const
|
||||
{
|
||||
return [mCocoaWindow contentView];
|
||||
}
|
||||
|
||||
void MacWindow::show()
|
||||
{
|
||||
[mCocoaWindow makeKeyAndOrderFront:nil];
|
||||
[mCocoaWindow makeFirstResponder:[mCocoaWindow contentView]];
|
||||
appEvent.trigger(getWindowId(), WindowShown);
|
||||
appEvent.trigger(getWindowId(), GainFocus);
|
||||
}
|
||||
|
||||
void MacWindow::close()
|
||||
{
|
||||
[mCocoaWindow close];
|
||||
appEvent.trigger(mWindowId, LoseFocus);
|
||||
appEvent.trigger(mWindowId, WindowDestroy);
|
||||
|
||||
mOwningWindowManager->_removeWindow(this);
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void MacWindow::hide()
|
||||
{
|
||||
[mCocoaWindow orderOut:nil];
|
||||
appEvent.trigger(getWindowId(), WindowHidden);
|
||||
}
|
||||
|
||||
void MacWindow::setDisplay(CGDirectDisplayID display)
|
||||
{
|
||||
mDisplay = display;
|
||||
mDisplayBounds = CGDisplayBounds(mDisplay);
|
||||
}
|
||||
|
||||
PlatformWindow* MacWindow::getNextWindow() const
|
||||
{
|
||||
return mNextWindow;
|
||||
}
|
||||
|
||||
bool MacWindow::setSize(const Point2I &newSize)
|
||||
{
|
||||
if (sSafariWindowInfo)
|
||||
return true;
|
||||
|
||||
NSSize newExtent = {newSize.x, newSize.y};
|
||||
[mCocoaWindow setContentSize:newExtent];
|
||||
[mCocoaWindow center];
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacWindow::setClientExtent( const Point2I newExtent )
|
||||
{
|
||||
if(!mFullscreen)
|
||||
{
|
||||
// Set the Client Area Extent (Resolution) of this window
|
||||
NSSize newSize = {newExtent.x, newExtent.y};
|
||||
[mCocoaWindow setContentSize:newSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
// In fullscreen we have to resize the monitor (it'll be good to change it back too...)
|
||||
if(!mDefaultDisplayMode)
|
||||
mDefaultDisplayMode = (NSDictionary*)CGDisplayCurrentMode(mDisplay);
|
||||
|
||||
NSDictionary* newMode = (NSDictionary*)CGDisplayBestModeForParameters(mDisplay, 32, newExtent.x, newExtent.y, NULL);
|
||||
Con::printf("Switching to new display mode... width: %i height: %i bpp: %i",
|
||||
[[newMode valueForKey:@"Width"] intValue], [[newMode valueForKey:@"Height"] intValue], [[newMode valueForKey:@"BitsPerPixel"] intValue]);
|
||||
CGDisplaySwitchToMode(mDisplay, (CFDictionaryRef)newMode);
|
||||
mDisplayBounds = CGDisplayBounds(mDisplay);
|
||||
if(mDisplay == kCGDirectMainDisplay)
|
||||
mMainDisplayBounds = mDisplayBounds;
|
||||
}
|
||||
}
|
||||
|
||||
const Point2I MacWindow::getClientExtent()
|
||||
{
|
||||
if(!mFullscreen)
|
||||
{
|
||||
// Get the Client Area Extent (Resolution) of this window
|
||||
NSSize size = [[mCocoaWindow contentView] frame].size;
|
||||
return Point2I(size.width, size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Point2I(mDisplayBounds.size.width, mDisplayBounds.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::setBounds( const RectI &newBounds )
|
||||
{
|
||||
NSRect newFrame = NSMakeRect(newBounds.point.x, newBounds.point.y, newBounds.extent.x, newBounds.extent.y);
|
||||
[mCocoaWindow setFrame:newFrame display:YES];
|
||||
}
|
||||
|
||||
const RectI MacWindow::getBounds() const
|
||||
{
|
||||
if(!mFullscreen)
|
||||
{
|
||||
// Get the position and size (fullscreen windows are always at (0,0)).
|
||||
NSRect frame = [mCocoaWindow frame];
|
||||
return RectI(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RectI(0, 0, mDisplayBounds.size.width, mDisplayBounds.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::setPosition( const Point2I newPosition )
|
||||
{
|
||||
NSScreen *screen = [mCocoaWindow screen];
|
||||
NSRect screenFrame = [screen frame];
|
||||
|
||||
NSPoint pos = {newPosition.x, newPosition.y + screenFrame.size.height};
|
||||
[mCocoaWindow setFrameTopLeftPoint: pos];
|
||||
}
|
||||
|
||||
const Point2I MacWindow::getPosition()
|
||||
{
|
||||
NSScreen *screen = [mCocoaWindow screen];
|
||||
NSRect screenFrame = [screen frame];
|
||||
NSRect frame = [mCocoaWindow frame];
|
||||
|
||||
return Point2I(frame.origin.x, screenFrame.size.height - (frame.origin.y + frame.size.height));
|
||||
}
|
||||
|
||||
void MacWindow::centerWindow()
|
||||
{
|
||||
[mCocoaWindow center];
|
||||
}
|
||||
|
||||
Point2I MacWindow::clientToScreen( const Point2I& pos )
|
||||
{
|
||||
NSPoint p = { pos.x, pos.y };
|
||||
|
||||
p = [ mCocoaWindow convertBaseToScreen: p ];
|
||||
return Point2I( p.x, p.y );
|
||||
}
|
||||
|
||||
Point2I MacWindow::screenToClient( const Point2I& pos )
|
||||
{
|
||||
NSPoint p = { pos.x, pos.y };
|
||||
|
||||
p = [ mCocoaWindow convertScreenToBase: p ];
|
||||
return Point2I( p.x, p.y );
|
||||
}
|
||||
|
||||
bool MacWindow::isFocused()
|
||||
{
|
||||
return [mCocoaWindow isKeyWindow];
|
||||
}
|
||||
|
||||
bool MacWindow::isOpen()
|
||||
{
|
||||
// Maybe check if _window != NULL ?
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacWindow::isVisible()
|
||||
{
|
||||
return !isMinimized() && ([mCocoaWindow isVisible] == YES);
|
||||
}
|
||||
|
||||
void MacWindow::setFocus()
|
||||
{
|
||||
[mCocoaWindow makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
void MacWindow::signalGainFocus()
|
||||
{
|
||||
if(isFocused())
|
||||
[[mCocoaWindow delegate] performSelector:@selector(signalGainFocus)];
|
||||
}
|
||||
|
||||
void MacWindow::minimize()
|
||||
{
|
||||
if(!isVisible())
|
||||
return;
|
||||
|
||||
[mCocoaWindow miniaturize:nil];
|
||||
appEvent.trigger(getWindowId(), WindowHidden);
|
||||
}
|
||||
|
||||
void MacWindow::maximize()
|
||||
{
|
||||
if(!isVisible())
|
||||
return;
|
||||
|
||||
// GFX2_RENDER_MERGE
|
||||
//[mCocoaWindow miniaturize:nil];
|
||||
//appEvent.trigger(getWindowId(), WindowHidden);
|
||||
}
|
||||
|
||||
void MacWindow::restore()
|
||||
{
|
||||
if(!isMinimized())
|
||||
return;
|
||||
|
||||
[mCocoaWindow deminiaturize:nil];
|
||||
appEvent.trigger(getWindowId(), WindowShown);
|
||||
}
|
||||
|
||||
bool MacWindow::isMinimized()
|
||||
{
|
||||
return [mCocoaWindow isMiniaturized] == YES;
|
||||
}
|
||||
|
||||
bool MacWindow::isMaximized()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacWindow::clearFocus()
|
||||
{
|
||||
// Clear the focus state for this Window.
|
||||
// If the Window does not have focus, nothing happens.
|
||||
// If the Window has focus, it relinquishes it's focus to the Operating System
|
||||
|
||||
// TODO: find out if we can do anything correct here. We are instructed *not* to call [NSWindow resignKeyWindow], and we don't necessarily have another window to assign as key.
|
||||
}
|
||||
|
||||
bool MacWindow::setCaption(const char* windowText)
|
||||
{
|
||||
mTitle = windowText;
|
||||
[mCocoaWindow setTitle:[NSString stringWithUTF8String:mTitle]];
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacWindow::_doMouseLockNow()
|
||||
{
|
||||
if(!isVisible())
|
||||
return;
|
||||
|
||||
if(mShouldMouseLock == mMouseLocked && mMouseLocked != isCursorVisible())
|
||||
return;
|
||||
|
||||
if(mShouldMouseLock)
|
||||
_dissociateMouse();
|
||||
else
|
||||
_associateMouse();
|
||||
|
||||
// hide the cursor if we're locking, show it if we're unlocking
|
||||
setCursorVisible(!shouldLockMouse());
|
||||
|
||||
mMouseLocked = mShouldMouseLock;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void MacWindow::_associateMouse()
|
||||
{
|
||||
CGAssociateMouseAndMouseCursorPosition(true);
|
||||
}
|
||||
|
||||
void MacWindow::_dissociateMouse()
|
||||
{
|
||||
_centerMouse();
|
||||
CGAssociateMouseAndMouseCursorPosition(false);
|
||||
}
|
||||
|
||||
void MacWindow::_centerMouse()
|
||||
{
|
||||
NSRect frame = [mCocoaWindow frame];
|
||||
|
||||
// Deal with the y flip (really fun when more than one monitor is involved)
|
||||
F32 offsetY = mMainDisplayBounds.size.height - mDisplayBounds.size.height;
|
||||
frame.origin.y = (mDisplayBounds.size.height + offsetY) - (S32)frame.origin.y - (S32)frame.size.height;
|
||||
mCursorController->setCursorPosition(frame.origin.x + frame.size.width / 2, frame.origin.y + frame.size.height / 2);
|
||||
}
|
||||
129
Engine/source/windowManager/mac/macWindowManager.h
Normal file
129
Engine/source/windowManager/mac/macWindowManager.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _MACWINDOWMANAGER_H_
|
||||
#define _MACWINDOWMANAGER_H_
|
||||
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
#include "core/util/tVector.h"
|
||||
|
||||
class MacWindow;
|
||||
|
||||
class MacWindowManager : public PlatformWindowManager
|
||||
{
|
||||
private:
|
||||
typedef VectorPtr<MacWindow*> WindowList;
|
||||
WindowList mWindowList;
|
||||
U32 mFadeToken;
|
||||
Delegate<bool(void)> mNotifyShutdownDelegate;
|
||||
|
||||
public:
|
||||
MacWindowManager();
|
||||
~MacWindowManager();
|
||||
|
||||
virtual void setParentWindow(void* newParent) {
|
||||
}
|
||||
|
||||
/// Get the parent window
|
||||
virtual void* getParentWindow()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode);
|
||||
|
||||
/// @name Desktop Queries
|
||||
/// @{
|
||||
|
||||
/// Return the extents in window coordinates of the primary desktop
|
||||
/// area. On a single monitor system this is just the display extents.
|
||||
/// On a multi-monitor system this is the primary monitor (which Torque should
|
||||
/// launch on).
|
||||
virtual RectI getPrimaryDesktopArea();
|
||||
|
||||
/// Populate a vector with all monitors and their extents in window space.
|
||||
virtual void getMonitorRegions(Vector<RectI> ®ions);
|
||||
|
||||
/// Retrieve the currently set desktop bit depth
|
||||
/// @return The current desktop bit depth, or -1 if an error occurred
|
||||
virtual S32 getDesktopBitDepth();
|
||||
|
||||
/// Retrieve the currently set desktop resolution
|
||||
/// @return The current desktop bit depth, or Point2I(-1,-1) if an error occurred
|
||||
virtual Point2I getDesktopResolution();
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Window Lookup
|
||||
/// @{
|
||||
|
||||
/// Get the number of Window's in this system
|
||||
virtual S32 getWindowCount();
|
||||
|
||||
/// Populate a list with references to all the windows created from this manager.
|
||||
virtual void getWindows(VectorPtr<PlatformWindow*> &windows);
|
||||
|
||||
/// Get a window from a device ID.
|
||||
///
|
||||
/// @return The window associated with the specified ID, or NULL if no
|
||||
/// match was found.
|
||||
virtual PlatformWindow *getWindowById(WindowId id);
|
||||
|
||||
virtual PlatformWindow *getFirstWindow();
|
||||
virtual PlatformWindow* getFocusedWindow();
|
||||
|
||||
/// During full-screen toggles we want to suppress ugly transition states,
|
||||
/// which we do (on Win32) by showing and hiding a full-monitor black window.
|
||||
///
|
||||
/// This method cues the appearance of that window ("lowering the curtain").
|
||||
virtual void lowerCurtain();
|
||||
|
||||
/// @see lowerCurtain
|
||||
///
|
||||
/// This method removes the curtain window.
|
||||
virtual void raiseCurtain();
|
||||
|
||||
/// @}
|
||||
/// @name Command Line Usage
|
||||
/// @{
|
||||
|
||||
/// Process command line arguments sent to this window manager
|
||||
/// to manipulate it's windows.
|
||||
virtual void _processCmdLineArgs(const S32 argc, const char **argv);
|
||||
|
||||
/// @}
|
||||
|
||||
// static MacWindowManager* get() { return (MacWindowManager*)PlatformWindowManager::get(); }
|
||||
void _addWindow(MacWindow* window);
|
||||
void _removeWindow(MacWindow* window);
|
||||
|
||||
void _onAppSignal(WindowId wnd, S32 event);
|
||||
|
||||
bool onShutdown();
|
||||
bool canWindowGainFocus(MacWindow* window);
|
||||
|
||||
|
||||
private:
|
||||
bool mIsShuttingDown;
|
||||
};
|
||||
|
||||
#endif
|
||||
245
Engine/source/windowManager/mac/macWindowManager.mm
Normal file
245
Engine/source/windowManager/mac/macWindowManager.mm
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 <Cocoa/Cocoa.h>
|
||||
#include "windowManager/mac/macWindowManager.h"
|
||||
#include "windowManager/mac/macWindow.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "console/console.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
|
||||
PlatformWindowManager* CreatePlatformWindowManager()
|
||||
{
|
||||
return new MacWindowManager();
|
||||
}
|
||||
|
||||
static inline RectI convertCGRectToRectI(NSRect r)
|
||||
{
|
||||
return RectI(r.origin.x, r.origin.y, r.size.width, r.size.height);
|
||||
}
|
||||
|
||||
MacWindowManager::MacWindowManager() : mNotifyShutdownDelegate(this, &MacWindowManager::onShutdown), mIsShuttingDown(false)
|
||||
{
|
||||
mWindowList.clear();
|
||||
Process::notifyShutdown(mNotifyShutdownDelegate);
|
||||
}
|
||||
|
||||
MacWindowManager::~MacWindowManager()
|
||||
{
|
||||
for(U32 i = 0; i < mWindowList.size(); i++)
|
||||
delete mWindowList[i];
|
||||
mWindowList.clear();
|
||||
|
||||
CGReleaseDisplayFadeReservation(mFadeToken);
|
||||
}
|
||||
|
||||
RectI MacWindowManager::getPrimaryDesktopArea()
|
||||
{
|
||||
// Get the area of the main desktop that isn't taken by the dock or menu bar.
|
||||
return convertCGRectToRectI([[NSScreen mainScreen] visibleFrame]);
|
||||
}
|
||||
|
||||
void MacWindowManager::getMonitorRegions(Vector<RectI> ®ions)
|
||||
{
|
||||
// Populate a vector with all monitors and their extents in window space.
|
||||
NSArray *screenList = [NSScreen screens];
|
||||
for(U32 i = 0; i < [screenList count]; i++)
|
||||
{
|
||||
NSRect screenBounds = [[screenList objectAtIndex: i] frame];
|
||||
regions.push_back(convertCGRectToRectI(screenBounds));
|
||||
}
|
||||
}
|
||||
|
||||
S32 MacWindowManager::getDesktopBitDepth()
|
||||
{
|
||||
// get the current desktop bit depth
|
||||
// TODO: return -1 if an error occurred
|
||||
return NSBitsPerPixelFromDepth([[NSScreen mainScreen] depth]);
|
||||
}
|
||||
|
||||
Point2I MacWindowManager::getDesktopResolution()
|
||||
{
|
||||
// get the current desktop width/height
|
||||
// TODO: return Point2I(-1,-1) if an error occurred
|
||||
NSRect desktopBounds = [[NSScreen mainScreen] frame];
|
||||
return Point2I((U32)desktopBounds.size.width, (U32)desktopBounds.size.height);
|
||||
}
|
||||
|
||||
S32 MacWindowManager::getWindowCount()
|
||||
{
|
||||
// Get the number of PlatformWindow's in this manager
|
||||
return mWindowList.size();
|
||||
}
|
||||
|
||||
void MacWindowManager::getWindows(VectorPtr<PlatformWindow*> &windows)
|
||||
{
|
||||
// Populate a list with references to all the windows created from this manager.
|
||||
windows.merge(mWindowList);
|
||||
}
|
||||
|
||||
PlatformWindow * MacWindowManager::getFirstWindow()
|
||||
{
|
||||
if (mWindowList.size() > 0)
|
||||
return mWindowList[0];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PlatformWindow* MacWindowManager::getFocusedWindow()
|
||||
{
|
||||
for (U32 i = 0; i < mWindowList.size(); i++)
|
||||
{
|
||||
if( mWindowList[i]->isFocused() )
|
||||
return mWindowList[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PlatformWindow* MacWindowManager::getWindowById(WindowId zid)
|
||||
{
|
||||
// Find the window by its arbirary WindowId.
|
||||
for(U32 i = 0; i < mWindowList.size(); i++)
|
||||
{
|
||||
PlatformWindow* w = mWindowList[i];
|
||||
if( w->getWindowId() == zid)
|
||||
return w;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MacWindowManager::lowerCurtain()
|
||||
{
|
||||
// fade all displays.
|
||||
CGError err;
|
||||
err = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &mFadeToken);
|
||||
AssertWarn(!err, "MacWindowManager::lowerCurtain() could not get a token");
|
||||
if(err) return;
|
||||
|
||||
err = CGDisplayFade(mFadeToken, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, true);
|
||||
AssertWarn(!err, "MacWindowManager::lowerCurtain() failed the fade");
|
||||
if(err) return;
|
||||
|
||||
// we do not release the token, because that will un-fade the screen!
|
||||
// the token will last for 15 sec, and then the screen will un-fade regardless.
|
||||
//CGReleaseDisplayFadeReservation(mFadeToken);
|
||||
}
|
||||
|
||||
void MacWindowManager::raiseCurtain()
|
||||
{
|
||||
// release the fade on all displays
|
||||
CGError err;
|
||||
err = CGDisplayFade(mFadeToken, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, false);
|
||||
AssertWarn(!err, "MacWindowManager::raiseCurtain() failed the fade");
|
||||
|
||||
err = CGReleaseDisplayFadeReservation(mFadeToken);
|
||||
AssertWarn(!err, "MacWindowManager::raiseCurtain() failed releasing the token");
|
||||
}
|
||||
|
||||
|
||||
void MacWindowManager::_processCmdLineArgs(const S32 argc, const char **argv)
|
||||
{
|
||||
// TODO: accept command line args if necessary.
|
||||
}
|
||||
|
||||
PlatformWindow *MacWindowManager::createWindow(GFXDevice *device, const GFXVideoMode &mode)
|
||||
{
|
||||
MacWindow* window = new MacWindow(getNextId(), getEngineProductString(), mode.resolution);
|
||||
_addWindow(window);
|
||||
|
||||
// Set the video mode on the window
|
||||
window->setVideoMode(mode);
|
||||
|
||||
// Make sure our window is shown and drawn to.
|
||||
window->show();
|
||||
|
||||
// Bind the window to the specified device.
|
||||
if(device)
|
||||
{
|
||||
window->mDevice = device;
|
||||
window->mTarget = device->allocWindowTarget(window);
|
||||
AssertISV(window->mTarget,
|
||||
"MacWindowManager::createWindow - failed to get a window target back from the device.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::warnf("MacWindowManager::createWindow - created a window with no device!");
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
void MacWindowManager::_addWindow(MacWindow* window)
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
// Make sure we aren't adding the window twice
|
||||
for(U32 i = 0; i < mWindowList.size(); i++)
|
||||
AssertFatal(window != mWindowList[i], "MacWindowManager::_addWindow - Should not add a window more than once");
|
||||
#endif
|
||||
if (mWindowList.size() > 0)
|
||||
window->mNextWindow = mWindowList.last();
|
||||
else
|
||||
window->mNextWindow = NULL;
|
||||
|
||||
mWindowList.push_back(window);
|
||||
window->mOwningWindowManager = this;
|
||||
window->appEvent.notify(this, &MacWindowManager::_onAppSignal);
|
||||
}
|
||||
|
||||
void MacWindowManager::_removeWindow(MacWindow* window)
|
||||
{
|
||||
for(WindowList::iterator i = mWindowList.begin(); i != mWindowList.end(); i++)
|
||||
{
|
||||
if(*i == window)
|
||||
{
|
||||
mWindowList.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
AssertFatal(false, avar("MacWindowManager::_removeWindow - Failed to remove window %x, perhaps it was already removed?", window));
|
||||
}
|
||||
|
||||
void MacWindowManager::_onAppSignal(WindowId wnd, S32 event)
|
||||
{
|
||||
if(event != WindowHidden)
|
||||
return;
|
||||
|
||||
for(U32 i = 0; i < mWindowList.size(); i++)
|
||||
{
|
||||
if(mWindowList[i]->getWindowId() == wnd)
|
||||
continue;
|
||||
|
||||
mWindowList[i]->signalGainFocus();
|
||||
}
|
||||
}
|
||||
|
||||
bool MacWindowManager::onShutdown()
|
||||
{
|
||||
mIsShuttingDown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacWindowManager::canWindowGainFocus(MacWindow* window)
|
||||
{
|
||||
return !mIsShuttingDown;
|
||||
}
|
||||
94
Engine/source/windowManager/platformCursorController.cpp
Normal file
94
Engine/source/windowManager/platformCursorController.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "windowManager/platformCursorController.h"
|
||||
|
||||
void PlatformCursorController::pushCursor( S32 cursorID )
|
||||
{
|
||||
// Place the new cursor shape onto the stack
|
||||
mCursors.increment();
|
||||
|
||||
CursorShape &shape = mCursors.last();
|
||||
shape.mCursorType = CursorShape::TYPE_RESOURCE;
|
||||
shape.mCursorID = cursorID;
|
||||
|
||||
// Now Change the Cursor Shape.
|
||||
setCursorShape( shape.mCursorID );
|
||||
}
|
||||
|
||||
void PlatformCursorController::pushCursor( const UTF8 *fileName )
|
||||
{
|
||||
// Place the new cursor shape onto the stack
|
||||
mCursors.increment();
|
||||
|
||||
// Store the Details.
|
||||
CursorShape &shape = mCursors.last();
|
||||
shape.mCursorType = CursorShape::TYPE_FILE;
|
||||
shape.mCursorFile = String::ToString( "%s", fileName );
|
||||
|
||||
// Now Change the Cursor Shape.
|
||||
setCursorShape( shape.mCursorFile.c_str(), true );
|
||||
}
|
||||
|
||||
void PlatformCursorController::popCursor()
|
||||
{
|
||||
// Before poping the stack, make sure we're not trying to remove the last cursor shape
|
||||
if ( mCursors.size() <= 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the Last Cursor.
|
||||
mCursors.pop_back();
|
||||
|
||||
// Now Change the Cursor Shape.
|
||||
setCursorShape( mCursors.last(), true );
|
||||
}
|
||||
|
||||
void PlatformCursorController::refreshCursor()
|
||||
{
|
||||
// Refresh the Cursor Shape.
|
||||
setCursorShape( mCursors.last(), false );
|
||||
}
|
||||
|
||||
void PlatformCursorController::setCursorShape( const CursorShape &shape, bool reload )
|
||||
{
|
||||
switch( shape.mCursorType )
|
||||
{
|
||||
case CursorShape::TYPE_RESOURCE :
|
||||
{
|
||||
|
||||
// Set Resource.
|
||||
setCursorShape( shape.mCursorID );
|
||||
|
||||
} break;
|
||||
|
||||
case CursorShape::TYPE_FILE :
|
||||
{
|
||||
|
||||
// Set File.
|
||||
setCursorShape( shape.mCursorFile.c_str(), reload );
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
102
Engine/source/windowManager/platformCursorController.h
Normal file
102
Engine/source/windowManager/platformCursorController.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PLATFORMCURSORCONTROLLER_H_
|
||||
#define _PLATFORMCURSORCONTROLLER_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class PlatformWindow;
|
||||
|
||||
class PlatformCursorController
|
||||
{
|
||||
protected:
|
||||
|
||||
struct CursorShape
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
TYPE_RESOURCE,
|
||||
TYPE_FILE,
|
||||
};
|
||||
|
||||
Type mCursorType;
|
||||
S32 mCursorID; // Points to a platform specific cursor ID
|
||||
String mCursorFile; // Points to a custom cursor file
|
||||
};
|
||||
|
||||
Vector<CursorShape> mCursors;
|
||||
|
||||
/// The PlatformWindow that owns this Cursor Controller
|
||||
PlatformWindow *mOwner;
|
||||
|
||||
public:
|
||||
|
||||
PlatformCursorController( PlatformWindow *owner ) :
|
||||
mOwner( owner )
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mCursors );
|
||||
};
|
||||
|
||||
virtual ~PlatformCursorController()
|
||||
{
|
||||
mOwner = NULL;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
curArrow = 0,
|
||||
curWait,
|
||||
curPlus,
|
||||
curResizeVert,
|
||||
curResizeHorz,
|
||||
curResizeAll,
|
||||
curIBeam,
|
||||
curResizeNESW,
|
||||
curResizeNWSE,
|
||||
curHand,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
virtual void setCursorPosition(S32 x, S32 y) = 0;
|
||||
virtual void getCursorPosition( Point2I &point ) = 0;
|
||||
virtual void setCursorVisible( bool visible ) = 0;
|
||||
virtual bool isCursorVisible() = 0;
|
||||
|
||||
virtual void setCursorShape( const CursorShape &shape, bool reload );
|
||||
virtual void setCursorShape( U32 cursorID ) = 0;
|
||||
virtual void setCursorShape( const UTF8 *filename, bool reload ) = 0;
|
||||
|
||||
virtual void pushCursor( S32 cursorID );
|
||||
virtual void pushCursor( const UTF8 *fileName );
|
||||
virtual void popCursor();
|
||||
virtual void refreshCursor();
|
||||
|
||||
virtual U32 getDoubleClickTime() = 0;
|
||||
virtual S32 getDoubleClickWidth() = 0;
|
||||
virtual S32 getDoubleClickHeight() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
143
Engine/source/windowManager/platformInterface.cpp
Normal file
143
Engine/source/windowManager/platformInterface.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "platform/event.h"
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
#include "gfx/gfxInit.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "core/util/autoPtr.h"
|
||||
|
||||
// This file converts from the windowmanager system to the old platform and
|
||||
// event interfaces. So it's a bit hackish but hopefully will not be necessary
|
||||
// for very long. Because of the heavy use of globals in the old platform
|
||||
// layer, this layer also has a fair number of globals.
|
||||
|
||||
|
||||
// WindowManager
|
||||
//
|
||||
// PlatformWindowManager::get() wrapped in Macro WindowManager
|
||||
static AutoPtr< PlatformWindowManager > smWindowManager;
|
||||
PlatformWindowManager *PlatformWindowManager::get()
|
||||
{
|
||||
if( smWindowManager.isNull() )
|
||||
smWindowManager = CreatePlatformWindowManager();
|
||||
return smWindowManager.ptr();
|
||||
}
|
||||
|
||||
void PlatformWindowManager::processCmdLineArgs( const S32 argc, const char **argv )
|
||||
{
|
||||
// Only call the get() routine if we have arguments on the command line
|
||||
if(argc > 0)
|
||||
{
|
||||
PlatformWindowManager::get()->_processCmdLineArgs(argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GFXDevice *gDevice = NULL;
|
||||
PlatformWindow *gWindow = NULL;
|
||||
|
||||
// Conversion from window manager input conventions to Torque standard.
|
||||
static struct ModifierBitMap {
|
||||
U32 grendelMask,torqueMask;
|
||||
} _ModifierBitMap[] = {
|
||||
{ IM_LSHIFT, SI_LSHIFT },
|
||||
{ IM_RSHIFT, SI_RSHIFT },
|
||||
{ IM_LALT, SI_LALT },
|
||||
{ IM_RALT, SI_RALT },
|
||||
{ IM_LCTRL, SI_LCTRL },
|
||||
{ IM_RCTRL, SI_RCTRL },
|
||||
{ IM_LOPT, SI_MAC_LOPT },
|
||||
{ IM_ROPT, SI_MAC_ROPT },
|
||||
};
|
||||
static int _ModifierBitMapCount = sizeof(_ModifierBitMap) / sizeof(ModifierBitMap);
|
||||
|
||||
InputModifiers convertModifierBits(const U32 in)
|
||||
{
|
||||
U32 out=0;
|
||||
|
||||
for(S32 i=0; i<_ModifierBitMapCount; i++)
|
||||
if(in & _ModifierBitMap[i].grendelMask)
|
||||
out |= _ModifierBitMap[i].torqueMask;
|
||||
|
||||
return (InputModifiers)out;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Platform::setWindowSize(U32 newWidth, U32 newHeight, bool fullScreen )
|
||||
{
|
||||
AssertISV(gWindow, "Platform::setWindowSize - no window present!");
|
||||
|
||||
// Grab the curent video settings and diddle them with the new values.
|
||||
GFXVideoMode vm = gWindow->getVideoMode();
|
||||
vm.resolution.set(newWidth, newHeight);
|
||||
vm.fullScreen = fullScreen;
|
||||
gWindow->setVideoMode(vm);
|
||||
}
|
||||
|
||||
void Platform::setWindowLocked(bool locked)
|
||||
{
|
||||
PlatformWindow* window = WindowManager->getFirstWindow();
|
||||
if( window )
|
||||
window->setMouseLocked( locked );
|
||||
}
|
||||
|
||||
void Platform::minimizeWindow()
|
||||
{
|
||||
// requires PlatformWindow API extension...
|
||||
if(gWindow)
|
||||
gWindow->minimize();
|
||||
}
|
||||
|
||||
void Platform::closeWindow()
|
||||
{
|
||||
// Shutdown all our stuff.
|
||||
//SAFE_DELETE(gDevice); // <-- device is already cleaned up elsewhere by now...
|
||||
SAFE_DELETE(gWindow);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#ifdef TORQUE_OS_WIN32
|
||||
// Hack so we can get the HWND of the global window more easily - replacement
|
||||
// for the HWND that was in the platstate.
|
||||
#include "windowManager/win32/win32Window.h"
|
||||
|
||||
HWND getWin32WindowHandle()
|
||||
{
|
||||
PlatformWindow* window = WindowManager->getFocusedWindow();
|
||||
if( !window )
|
||||
{
|
||||
window = WindowManager->getFirstWindow();
|
||||
if( !window )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ( ( Win32Window* ) window )->getHWND();
|
||||
}
|
||||
|
||||
#endif
|
||||
50
Engine/source/windowManager/platformWindow.cpp
Normal file
50
Engine/source/windowManager/platformWindow.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "windowManager/platformWindow.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PlatformWindow::setFullscreen( const bool fullscreen )
|
||||
{
|
||||
// Notify listeners that we will acquire the screen
|
||||
if(fullscreen && !Journal::IsDispatching())
|
||||
appEvent.trigger(getWindowId(),GainScreen);
|
||||
|
||||
// Do platform specific fullscreen code
|
||||
_setFullscreen(fullscreen);
|
||||
|
||||
// Notify listeners that we released the screen
|
||||
if(!fullscreen && !Journal::IsDispatching())
|
||||
appEvent.trigger(getWindowId(),LoseScreen);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool PlatformWindow::shouldNotTranslate( U32 modifiers, U32 keyCode ) const
|
||||
{
|
||||
if( mWindowInputGenerator )
|
||||
return mWindowInputGenerator->wantAsKeyboardEvent( modifiers, keyCode );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
494
Engine/source/windowManager/platformWindow.h
Normal file
494
Engine/source/windowManager/platformWindow.h
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PLATFORMWINDOW_H_
|
||||
#define _WINDOWMANAGER_PLATFORMWINDOW_H_
|
||||
|
||||
#include "math/mRect.h"
|
||||
#include "core/util/journal/journaledSignal.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "windowManager/platformCursorController.h"
|
||||
#include "windowManager/windowInputGenerator.h"
|
||||
|
||||
//forward decl's
|
||||
class PlatformWindowManager;
|
||||
class GFXDevice;
|
||||
struct GFXVideoMode;
|
||||
class GFXWindowTarget;
|
||||
class IProcessInput;
|
||||
|
||||
/// Abstract representation of a native OS window.
|
||||
///
|
||||
/// Every windowing system has its own representations and conventions as
|
||||
/// regards the windows on-screen. In order to provide Torque with means for
|
||||
/// interfacing with multiple windows, tracking their state, etc. we provide
|
||||
/// this interface.
|
||||
///
|
||||
/// This interface also allows the app to access the render target for the
|
||||
/// window it represents, as well as control mode switches, get mode info,
|
||||
/// and so on.
|
||||
///
|
||||
/// @see PlatformWindowManager
|
||||
class PlatformWindow
|
||||
{
|
||||
friend class PlatformWindowManager;
|
||||
protected:
|
||||
|
||||
/// Are we enabling IME or other keyboard input translation services,
|
||||
/// or concerned about raw input?
|
||||
bool mEnableKeyboardTranslation;
|
||||
|
||||
/// When Torque GuiText input controls have focus they need to
|
||||
/// disable native OS keyboard accelerator translation.
|
||||
bool mEnableAccelerators;
|
||||
|
||||
/// Minimum allowed size for this window. When possible, we will communicate
|
||||
/// this to the OS.
|
||||
Point2I mMinimumSize;
|
||||
|
||||
/// When the resize is locked, this will be used as both minimum and maximum window size
|
||||
Point2I mLockedSize;
|
||||
|
||||
/// When this is true, resizing is locked
|
||||
bool mResizeLocked;
|
||||
|
||||
/// Is Idle?
|
||||
bool mIsBackground;
|
||||
|
||||
/// Cursor Controller for this Window
|
||||
PlatformCursorController *mCursorController;
|
||||
|
||||
/// An opaque ID used to resolve references to this Window
|
||||
WindowId mWindowId;
|
||||
|
||||
/// Window Mouse/Key input Controller for this Window
|
||||
WindowInputGenerator *mWindowInputGenerator;
|
||||
|
||||
/// Suppress device resets
|
||||
bool mSuppressReset;
|
||||
|
||||
/// Offscreen Render
|
||||
bool mOffscreenRender;
|
||||
|
||||
/// Protected constructor so that the win
|
||||
PlatformWindow()
|
||||
{
|
||||
mIsBackground = false; // This could be toggled to true to prefer performance.
|
||||
mMinimumSize.set(0,0);
|
||||
mLockedSize.set(0,0);
|
||||
mResizeLocked = false;
|
||||
mEnableKeyboardTranslation = false;
|
||||
mEnableAccelerators = true;
|
||||
mCursorController = NULL;
|
||||
// This controller maps window input (Mouse/Keyboard) to a generic input consumer
|
||||
mWindowInputGenerator = new WindowInputGenerator( this );
|
||||
mSuppressReset = false;
|
||||
|
||||
mOffscreenRender = false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// To get rid of a window, just delete it. Make sure the GFXDevice is
|
||||
/// done with it first!
|
||||
virtual ~PlatformWindow()
|
||||
{
|
||||
SAFE_DELETE( mCursorController );
|
||||
SAFE_DELETE( mWindowInputGenerator );
|
||||
}
|
||||
|
||||
/// Get the WindowController associated with this window
|
||||
virtual void setInputController( IProcessInput *controller ) { if( mWindowInputGenerator ) mWindowInputGenerator->setInputController( controller ); };
|
||||
|
||||
/// Get the ID that uniquely identifies this window in the context of its
|
||||
/// window manager.
|
||||
virtual WindowId getWindowId() { return 0; };
|
||||
|
||||
/// Set the flag that determines whether to suppress a GFXDevice reset
|
||||
inline void setSuppressReset(bool suppress) { mSuppressReset = suppress; };
|
||||
|
||||
/// @name GFX State Management
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Return a pointer to the GFX device this window is bound to. A GFX
|
||||
/// device may use many windows, but a window can only be used by a
|
||||
/// single GFX device.
|
||||
virtual GFXDevice *getGFXDevice()=0;
|
||||
|
||||
/// Return a pointer to this window's render target.
|
||||
///
|
||||
/// By setting window targets from different windows, we can effect
|
||||
/// rendering to multiple windows from a single device.
|
||||
virtual GFXWindowTarget *getGFXTarget()=0;
|
||||
|
||||
/// Set the video mode for this window.
|
||||
virtual void setVideoMode(const GFXVideoMode &mode)=0;
|
||||
|
||||
/// Get our current video mode - if the window has been resized, it will
|
||||
/// reflect this.
|
||||
virtual const GFXVideoMode &getVideoMode()=0;
|
||||
|
||||
/// If we're fullscreen, this function returns us to desktop mode.
|
||||
///
|
||||
/// This will be either the last mode that we had that was not
|
||||
/// fullscreen, or the equivalent mode, windowed.
|
||||
virtual bool clearFullscreen()=0;
|
||||
|
||||
/// @return true if this window is fullscreen, false otherwise.
|
||||
virtual bool isFullscreen()=0;
|
||||
|
||||
/// Acquire the entire screen
|
||||
void setFullscreen(const bool fullscreen);
|
||||
|
||||
/// Set Idle State (Background)
|
||||
///
|
||||
/// This is called to put a window into idle state, which causes it's
|
||||
/// rendering priority to be toned down to prefer performance
|
||||
virtual void setBackground( bool val ) { mIsBackground = val; };
|
||||
|
||||
/// Get Idle State (Background)
|
||||
///
|
||||
/// This is called to poll the window as to it's idle state.
|
||||
virtual bool getBackground() { return mIsBackground; };
|
||||
|
||||
/// Set whether this window is intended for offscreen rendering
|
||||
/// An offscreen window will never be shown or lose focus
|
||||
virtual void setOffscreenRender(bool val ) { mOffscreenRender = val; };
|
||||
|
||||
/// Set whether this window is intended for offscreen rendering
|
||||
///
|
||||
/// This is called to poll the window as to it's idle state.
|
||||
virtual bool getOffscreenRender() { return mOffscreenRender; };
|
||||
|
||||
|
||||
/// Set Focused State (Foreground)
|
||||
///
|
||||
/// Claim OS input focus for this window
|
||||
virtual void setFocus() { }
|
||||
/// @}
|
||||
|
||||
/// @name Caption
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Set the window's caption.
|
||||
virtual bool setCaption(const char *cap)=0;
|
||||
|
||||
/// Get the window's caption.
|
||||
virtual const char *getCaption()=0;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Visibility
|
||||
///
|
||||
/// Control how the window is displayed
|
||||
/// @{
|
||||
|
||||
/// Minimize the window on screen
|
||||
virtual void minimize()=0;
|
||||
|
||||
/// Maximize the window on screen
|
||||
virtual void maximize()=0;
|
||||
|
||||
/// Hide the window on screen
|
||||
virtual void hide()=0;
|
||||
|
||||
/// Show the window on screen
|
||||
virtual void show()=0;
|
||||
|
||||
/// Destroy the window on screen
|
||||
virtual void close()=0;
|
||||
|
||||
/// Restore the window from a Maximized or Minimized state
|
||||
virtual void restore()=0;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Window Bounds
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// The Client Rectangle or "Render Area" of a window is the area that
|
||||
/// is occupied by a given client that is rendering to that window.
|
||||
/// This does not include the area occupied by a title-bar, menu,
|
||||
/// borders or other non-client elements.
|
||||
/// @{
|
||||
|
||||
/// Set the Client Area Extent (Resolution) of this window
|
||||
virtual void setClientExtent( const Point2I newExtent ) = 0;
|
||||
|
||||
/// Get the Client Area Extent (Resolution) of this window
|
||||
virtual const Point2I getClientExtent() = 0;
|
||||
|
||||
/// @}
|
||||
/// The bounds of a Window are defined as the entire area occupied by
|
||||
/// that Window. This includes the area needed for a title-bar, menu,
|
||||
/// borders, and other non-client elements.
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Resize the window to have some new bounds.
|
||||
virtual void setBounds( const RectI &newBounds ) = 0;
|
||||
|
||||
/// Get the position and size (fullscreen windows are always at (0,0)).
|
||||
virtual const RectI getBounds() const = 0;
|
||||
|
||||
/// @}
|
||||
/// The Position of a window is always in relation to the very upper left
|
||||
/// of the window. This means that saying setPosition at 0,0 will put the
|
||||
/// position of the window title-bar (if one exists) at 0,0 and the Client
|
||||
/// area will be offset from that point by the space needed for the Non-Client
|
||||
/// area.
|
||||
/// @{
|
||||
|
||||
/// Set the position of this window
|
||||
virtual void setPosition( const Point2I newPosition ) = 0;
|
||||
|
||||
/// Get the position of this window
|
||||
virtual const Point2I getPosition() = 0;
|
||||
|
||||
virtual void centerWindow() {};
|
||||
|
||||
/// Resize the window to have a new size (but be in the same position).
|
||||
virtual bool setSize(const Point2I &newSize)=0;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Coordinate Space Conversion
|
||||
/// @{
|
||||
|
||||
/// Convert the coordinate given in this window space to screen coordinates.
|
||||
virtual Point2I clientToScreen( const Point2I& point ) = 0;
|
||||
|
||||
/// Convert the given screen coordinates to coordinates in this window space.
|
||||
virtual Point2I screenToClient( const Point2I& point ) = 0;
|
||||
|
||||
/// @}
|
||||
|
||||
/// @name Windowed state
|
||||
///
|
||||
/// This is only really meaningful if the window is not fullscreen.
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Returns true if the window is instantiated in the OS.
|
||||
virtual bool isOpen() = 0;
|
||||
|
||||
/// Returns true if the window is visible.
|
||||
virtual bool isVisible() = 0;
|
||||
|
||||
/// Returns true if the window has input focus
|
||||
virtual bool isFocused() = 0;
|
||||
|
||||
/// Returns true if the window is minimized
|
||||
virtual bool isMinimized() = 0;
|
||||
|
||||
/// Returns true if the window is maximized
|
||||
virtual bool isMaximized() = 0;
|
||||
|
||||
/// @name Keyboard Translation
|
||||
///
|
||||
/// When keyboard translation is on, keypress events that correspond to character input
|
||||
/// should be send as character input events rather than as raw key events *except* if
|
||||
/// shouldNotTranslate() returns true for a specific keypress event. This enables the
|
||||
/// platform layer to perform platform-specific character input mapping.
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Set if relevant keypress events should be translated into character input events.
|
||||
virtual void setKeyboardTranslation(const bool enabled)
|
||||
{
|
||||
mEnableKeyboardTranslation = enabled;
|
||||
}
|
||||
|
||||
/// Returns true if keyboard translation is enabled.
|
||||
virtual bool getKeyboardTranslation() const
|
||||
{
|
||||
return mEnableKeyboardTranslation;
|
||||
}
|
||||
|
||||
/// Returns true if the given keypress event should not be translated.
|
||||
virtual bool shouldNotTranslate( U32 modifiers, U32 keyCode ) const;
|
||||
|
||||
/// @}
|
||||
|
||||
/// Used to disable native OS keyboard accelerators.
|
||||
virtual void setAcceleratorsEnabled(const bool enabled)
|
||||
{
|
||||
mEnableAccelerators = enabled;
|
||||
}
|
||||
|
||||
/// Returns true if native OS keyboard accelerators are enabled.
|
||||
virtual bool getAcceleratorsEnabled() const
|
||||
{
|
||||
return mEnableAccelerators;
|
||||
}
|
||||
|
||||
/// Sets a minimum window size. We'll work with the OS to prevent user
|
||||
/// from sizing the window to less than this. Setting to (0,0) means
|
||||
/// user has complete freedom of resize.
|
||||
virtual void setMinimumWindowSize(Point2I minSize)
|
||||
{
|
||||
mMinimumSize = minSize;
|
||||
}
|
||||
|
||||
/// Returns the current minimum window size for this window.
|
||||
virtual Point2I getMinimumWindowSize()
|
||||
{
|
||||
return mMinimumSize;
|
||||
}
|
||||
|
||||
/// Locks/unlocks window resizing
|
||||
virtual void lockSize(bool locked)
|
||||
{
|
||||
mResizeLocked = locked;
|
||||
if (mResizeLocked)
|
||||
mLockedSize = getBounds().extent;
|
||||
}
|
||||
|
||||
/// Returns true if the window size is locked
|
||||
virtual bool isSizeLocked()
|
||||
{
|
||||
return mResizeLocked;
|
||||
}
|
||||
|
||||
/// Returns the locked window size
|
||||
virtual Point2I getLockedSize()
|
||||
{
|
||||
return mLockedSize;
|
||||
}
|
||||
/// @}
|
||||
|
||||
|
||||
/// @name Window Cursor
|
||||
///
|
||||
/// Accessors to control a windows cursor shape and visibility
|
||||
///
|
||||
/// @{
|
||||
/// Get the CursorController that this window owns.
|
||||
virtual PlatformCursorController *getCursorController() { return mCursorController; };
|
||||
|
||||
/// Set the cursor position based on logical coordinates from the upper-right corner
|
||||
///
|
||||
/// @param x The X position of the cursor
|
||||
/// @param y The Y position of the cursor
|
||||
virtual void setCursorPosition(S32 x, S32 y)
|
||||
{
|
||||
if( mCursorController != NULL )
|
||||
mCursorController->setCursorPosition(x,y);
|
||||
}
|
||||
|
||||
/// Get the cursor position based on logical coordinates from the upper-right corner
|
||||
///
|
||||
/// @param point A reference to a Point2I to store the coordinates
|
||||
virtual void getCursorPosition( Point2I &point )
|
||||
{
|
||||
if( mCursorController != NULL )
|
||||
mCursorController->getCursorPosition(point);
|
||||
}
|
||||
|
||||
/// Set the cursor visibility on this window
|
||||
///
|
||||
/// @param visible Whether the cursor should be visible or not
|
||||
virtual void setCursorVisible(bool visible)
|
||||
{
|
||||
if( mCursorController != NULL )
|
||||
mCursorController->setCursorVisible(visible);
|
||||
}
|
||||
|
||||
/// Get the cursor visibility on this window
|
||||
///
|
||||
/// @return true if the cursor is visible or false if it's hidden
|
||||
virtual bool isCursorVisible()
|
||||
{
|
||||
if( mCursorController != NULL )
|
||||
return mCursorController->isCursorVisible();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lock the mouse to this window.
|
||||
///
|
||||
/// When this is set, the mouse will always be returned to the center
|
||||
/// of the client area after every mouse event. The mouse will also be
|
||||
/// hidden while it is locked.
|
||||
///
|
||||
/// The mouse cannot be moved out of the bounds of the window, but the
|
||||
/// window may lose focus (for instance by an alt-tab or other event).
|
||||
/// While the window lacks focus, no mouse events will be reported.
|
||||
virtual void setMouseLocked( bool enable )=0;
|
||||
|
||||
/// Is the mouse locked ?
|
||||
virtual bool isMouseLocked() const = 0;
|
||||
|
||||
/// Should the mouse be locked at the next opportunity ?
|
||||
///
|
||||
/// This flag is set to the current state of the mouse lock
|
||||
/// on a window, to specify the preferred lock status of the
|
||||
/// mouse in a platform window.
|
||||
///
|
||||
/// This is important for situations where a call is made
|
||||
/// to setMouseLocked, and the window is not in a state that
|
||||
/// it can be cleanly locked. Take for example if it was called
|
||||
/// while the window is in the background, then it is not appropriate
|
||||
/// to lock the window, but rather the window should query this
|
||||
/// state at it's next opportunity and lock the mouse if requested.
|
||||
virtual bool shouldLockMouse() const = 0;
|
||||
|
||||
/// @}
|
||||
|
||||
virtual PlatformWindow * getNextWindow() const = 0;
|
||||
|
||||
/// @name Event Handlers
|
||||
///
|
||||
/// Various events that this window receives. These are all subclasses of
|
||||
/// JournaledSignal, so you can subscribe to them and receive notifications
|
||||
/// per the documentation for that class.
|
||||
///
|
||||
/// @{
|
||||
|
||||
///
|
||||
AppEvent appEvent;
|
||||
MouseEvent mouseEvent;
|
||||
MouseWheelEvent wheelEvent;
|
||||
ButtonEvent buttonEvent;
|
||||
LinearEvent linearEvent;
|
||||
KeyEvent keyEvent;
|
||||
CharEvent charEvent;
|
||||
DisplayEvent displayEvent;
|
||||
ResizeEvent resizeEvent;
|
||||
IdleEvent idleEvent;
|
||||
|
||||
/// @}
|
||||
|
||||
/// Get the platform specific object needed to create or attach an accelerated
|
||||
/// graohics drawing context on or to the window
|
||||
/// Win32 D3D and OpenGL typically needs an HWND
|
||||
/// Mac Cocoa OpenGL typically needs an NSOpenGLView
|
||||
/// Mac Carbon OpenGL typically needs a WindowRef
|
||||
///
|
||||
virtual void* getPlatformDrawable() const = 0;
|
||||
protected:
|
||||
virtual void _setFullscreen(const bool fullScreen) {};
|
||||
};
|
||||
|
||||
#endif
|
||||
133
Engine/source/windowManager/platformWindowMgr.h
Normal file
133
Engine/source/windowManager/platformWindowMgr.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PLATFORM_PLATFORMWINDOWMGR_H_
|
||||
#define _PLATFORM_PLATFORMWINDOWMGR_H_
|
||||
|
||||
#include "math/mRect.h"
|
||||
#include "core/util/journal/journaledSignal.h"
|
||||
#include "windowManager/platformWindow.h"
|
||||
|
||||
|
||||
// Global macro
|
||||
#define WindowManager PlatformWindowManager::get()
|
||||
|
||||
/// Abstract representation of a manager for native OS windows.
|
||||
///
|
||||
/// The PlatformWindowManager interface provides a variety of methods for querying
|
||||
/// the current desktop configuration, as well as allocating and retrieving
|
||||
/// existing windows. It may also manage application-level event handling.
|
||||
class PlatformWindowManager
|
||||
{
|
||||
// Generator for window IDs.
|
||||
S32 mIdSource;
|
||||
|
||||
protected:
|
||||
/// Get the next available window Id
|
||||
inline S32 getNextId() { return mIdSource++; }
|
||||
public:
|
||||
|
||||
/// Get Global Singleton
|
||||
static PlatformWindowManager *get();
|
||||
|
||||
PlatformWindowManager() : mIdSource(0) {};
|
||||
|
||||
virtual ~PlatformWindowManager()
|
||||
{
|
||||
}
|
||||
|
||||
static void processCmdLineArgs(const S32 argc, const char **argv);
|
||||
|
||||
/// Return the extents in window coordinates of the primary desktop
|
||||
/// area. On a single monitor system this is just the display extents.
|
||||
/// On a multimon system this is the primary monitor (which Torque should
|
||||
/// launch on).
|
||||
virtual RectI getPrimaryDesktopArea() = 0;
|
||||
|
||||
/// Retrieve the currently set desktop bit depth
|
||||
/// @return The current desktop bit depth, or -1 if an error occurred
|
||||
virtual S32 getDesktopBitDepth() = 0;
|
||||
|
||||
/// Retrieve the currently set desktop resolution
|
||||
/// @return The current desktop bit depth, or Point2I(-1,-1) if an error occurred
|
||||
virtual Point2I getDesktopResolution() = 0;
|
||||
|
||||
/// Populate a vector with all monitors and their extents in window space.
|
||||
virtual void getMonitorRegions(Vector<RectI> ®ions) = 0;
|
||||
|
||||
/// Create a new window, appropriate for the specified device and mode.
|
||||
///
|
||||
/// @return Pointer to the new window.
|
||||
virtual PlatformWindow *createWindow(GFXDevice *device, const GFXVideoMode &mode) = 0;
|
||||
|
||||
/// Populate a list with references to all the windows created from this manager.
|
||||
virtual void getWindows(VectorPtr<PlatformWindow*> &windows) = 0;
|
||||
|
||||
/// Get the window that currently has the input focus or NULL.
|
||||
virtual PlatformWindow* getFocusedWindow() = 0;
|
||||
|
||||
/// Get a window from a device ID.
|
||||
///
|
||||
/// @return The window associated with the specified ID, or NULL if no
|
||||
/// match was found.
|
||||
virtual PlatformWindow *getWindowById(WindowId id)=0;
|
||||
|
||||
/// Get the first window in the window list
|
||||
///
|
||||
/// @return The first window in the list, or NULL if no windows found
|
||||
virtual PlatformWindow *getFirstWindow()=0;
|
||||
|
||||
|
||||
/// Set the parent window
|
||||
///
|
||||
/// This can be used to render in a child window.
|
||||
virtual void setParentWindow(void* newParent) = 0;
|
||||
|
||||
/// Get the parent window
|
||||
virtual void* getParentWindow() = 0;
|
||||
|
||||
|
||||
/// This method cues the appearance of that window ("lowering the curtain").
|
||||
virtual void lowerCurtain()=0;
|
||||
|
||||
/// @see lowerCurtain
|
||||
///
|
||||
/// This method removes the curtain window.
|
||||
virtual void raiseCurtain()=0;
|
||||
|
||||
private:
|
||||
/// Process command line arguments from StandardMainLoop. This is done to
|
||||
/// allow web plugin functionality, where we are passed platform-specific
|
||||
/// information allowing us to set ourselves up in the web browser,
|
||||
/// to occur in a platform-neutral way.
|
||||
virtual void _processCmdLineArgs(const S32 argc, const char **argv)=0;
|
||||
};
|
||||
|
||||
/// Global function to allocate a new platform window manager.
|
||||
///
|
||||
/// This returns an instance of the appropriate window manager for the current OS.
|
||||
///
|
||||
/// Depending on situation (for instance, if we are a web plugin) we may
|
||||
/// need to get the window manager from somewhere else.
|
||||
PlatformWindowManager *CreatePlatformWindowManager();
|
||||
|
||||
#endif
|
||||
538
Engine/source/windowManager/test/testWinMgr.cpp
Normal file
538
Engine/source/windowManager/test/testWinMgr.cpp
Normal file
|
|
@ -0,0 +1,538 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "console/console.h"
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "gfx/gfxStructs.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "gfx/gfxInit.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(TestWinMgrQueries, "WindowManager/BasicQueries")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
// Check out the primary desktop area...
|
||||
RectI primary = pwm->getPrimaryDesktopArea();
|
||||
|
||||
Con::printf("Primary desktop area is (%d,%d) (%d,%d)",
|
||||
primary.point.x, primary.point.y, primary.extent.x, primary.extent.y);
|
||||
|
||||
test(primary.isValidRect(), "Got some sort of invalid rect from the window manager!");
|
||||
|
||||
// Now try to get info about all the monitors.
|
||||
Vector<RectI> monitorRects;
|
||||
pwm->getMonitorRegions(monitorRects);
|
||||
|
||||
test(monitorRects.size() > 0, "Should get at least one monitor rect back from getMonitorRegions!");
|
||||
|
||||
// This test is here just to detect overflow/runaway situations. -- BJG
|
||||
test(monitorRects.size() < 64, "Either something's wrong, or you have a lot of monitors...");
|
||||
|
||||
for(S32 i=0; i<monitorRects.size(); i++)
|
||||
{
|
||||
Con::printf(" Monitor #%d region is (%d,%d) (%d,%d)", i,
|
||||
monitorRects[i].point.x, monitorRects[i].point.y, monitorRects[i].extent.x, monitorRects[i].extent.y);
|
||||
|
||||
test(monitorRects[i].isValidRect(), "Got an invalid rect for this monitor - no good.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrCreate, "WindowManager/CreateAWindow")
|
||||
{
|
||||
void handleMouseEvent(WindowId,U32,S32 x,S32 y, bool isRelative)
|
||||
{
|
||||
Con::printf("Mouse at %d, %d %s", x, y, isRelative ? "(relative)" : "(absolute)");
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 800;
|
||||
vm.resolution.y = 600;
|
||||
|
||||
PlatformWindow *pw = pwm->createWindow(NULL, vm);
|
||||
|
||||
test(pw, "Didn't get a window back from the window manager, no good.");
|
||||
if(!pw)
|
||||
return;
|
||||
|
||||
// Setup our events.
|
||||
pw->mouseEvent.notify(this, &TestWinMgrCreate::handleMouseEvent);
|
||||
pw->appEvent.notify(this, &TestWinMgrCreate::handleAppEvent);
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
SAFE_DELETE(pw);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrGFXInit, "WindowManager/SimpleGFX")
|
||||
{
|
||||
PlatformWindow *mWindow;
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(mWindow->getGFXTarget());
|
||||
mDevice->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, ColorI( 255, 255, 0 ), 1.0f, 0 );
|
||||
mDevice->endScene();
|
||||
mWindow->getGFXTarget()->present();
|
||||
}
|
||||
|
||||
void forceDraw()
|
||||
{
|
||||
handleDrawEvent(0);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the window...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
mWindow = pwm->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindow, "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindow)
|
||||
return;
|
||||
|
||||
// Setup our events.
|
||||
mWindow->displayEvent.notify(this, &TestWinMgrGFXInit::handleDrawEvent);
|
||||
mWindow->idleEvent.notify(this, &TestWinMgrGFXInit::forceDraw);
|
||||
mWindow->appEvent.notify(this, &TestWinMgrGFXInit::handleAppEvent);
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
mWindow->displayEvent.remove(this, &TestWinMgrGFXInit::handleDrawEvent);
|
||||
mWindow->idleEvent.remove(this, &TestWinMgrGFXInit::forceDraw);
|
||||
mWindow->appEvent.remove(this, &TestWinMgrGFXInit::handleAppEvent);
|
||||
|
||||
// Clean up!
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindow);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrGFXInitMultiWindow, "WindowManager/GFXMultiWindow")
|
||||
{
|
||||
enum {
|
||||
NumWindows = 4,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(w->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
mDevice->clear( GFXClearTarget,
|
||||
ColorI( 255 - (id * 50), 255, id * 100 ), 1.0f, 0 );
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
((GFXWindowTarget*)w->getGFXTarget())->present();
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
handleDrawEvent(mWindows[i]->getWindowId());
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->displayEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleDrawEvent);
|
||||
mWindows[i]->appEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleAppEvent);
|
||||
mWindows[i]->idleEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
SAFE_DELETE(mWindowManager);
|
||||
SAFE_DELETE(mDevice);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestJournaledMultiWindowGFX, "WindowManager/GFXJournaledMultiWindow")
|
||||
{
|
||||
enum {
|
||||
NumWindows = 2,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
S32 mNumDraws;
|
||||
S32 mNumResize;
|
||||
|
||||
void drawToWindow(PlatformWindow *win)
|
||||
{
|
||||
// Do some simple checks to make sure we draw the same number of times
|
||||
// on both runs.
|
||||
if(Journal::IsPlaying())
|
||||
mNumDraws--;
|
||||
else
|
||||
mNumDraws++;
|
||||
|
||||
// Render!
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(win->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
static S32 timeVariance = 0;
|
||||
|
||||
mDevice->clear( GFXClearTarget,
|
||||
ColorI( 0xFF - (++timeVariance * 5), 0xFF, win->getWindowId() * 0x0F ), 1.0f, 0 );
|
||||
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
win->getGFXTarget()->present();
|
||||
|
||||
}
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
drawToWindow(mWindows[i]);
|
||||
}
|
||||
|
||||
void handleResizeEvent(WindowId id, S32 width, S32 height)
|
||||
{
|
||||
// Do some simple checks to make sure we resize the same number of times
|
||||
// on both runs.
|
||||
|
||||
if(Journal::IsPlaying())
|
||||
{
|
||||
// If we're playing back, APPLY the resize event...
|
||||
mWindowManager->getWindowById(id)->setSize(Point2I(width, height));
|
||||
|
||||
mNumResize--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're not playing back, do nothing except note it.
|
||||
mNumResize++;
|
||||
}
|
||||
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
/// The mainloop of our app - we'll run this twice, once to create
|
||||
/// a journal and again to play it back.
|
||||
void mainLoop()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create ogl device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->displayEvent.notify(this, &TestJournaledMultiWindowGFX::handleDrawEvent);
|
||||
mWindows[i]->appEvent.notify(this, &TestJournaledMultiWindowGFX::handleAppEvent);
|
||||
mWindows[i]->resizeEvent.notify(this, &TestJournaledMultiWindowGFX::handleResizeEvent);
|
||||
|
||||
// Only subscribe to the first idle event.
|
||||
if(i==0)
|
||||
mWindows[i]->idleEvent.notify(this, &TestJournaledMultiWindowGFX::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
// Finally, clean up.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
SAFE_DELETE(mWindows[i]);
|
||||
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindowManager);
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
return;
|
||||
|
||||
// CodeReview: this should be deleted or enabled.
|
||||
#if 0
|
||||
mNumDraws = 0;
|
||||
mNumResize = 0;
|
||||
|
||||
// Record a run of the main loop.
|
||||
Journal::Record("multiwindow.jrn");
|
||||
mainLoop();
|
||||
Journal::Stop();
|
||||
|
||||
test(mNumDraws > 0, "No draws occurred!");
|
||||
test(mNumResize > 0, "No resizes occurred!");
|
||||
|
||||
// And play it back.
|
||||
Journal::Play("multiwindow.jrn");
|
||||
mainLoop();
|
||||
Journal::Stop();
|
||||
|
||||
test(mNumDraws == 0, "Failed to play journal back with same number of draws.");
|
||||
test(mNumResize == 0, "Failed to play journal back with same number of resizes.");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(GFXTestFullscreenToggle, "GFX/TestFullscreenToggle")
|
||||
{
|
||||
enum Constants
|
||||
{
|
||||
NumWindows = 1,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void drawToWindow(PlatformWindow *win)
|
||||
{
|
||||
// Render!
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(win->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
static S32 timeVariance = 0;
|
||||
|
||||
mDevice->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget,
|
||||
ColorI( 0xFF - (++timeVariance * 5), 0xFF, win->getWindowId() * 0x40 ), 1.0f, 0 );
|
||||
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
win->getGFXTarget()->present();
|
||||
}
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
// Redraw everything.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
drawToWindow(mWindows[i]);
|
||||
|
||||
// Don't monopolize the CPU.
|
||||
Platform::sleep(10);
|
||||
}
|
||||
|
||||
void handleButtonEvent(WindowId did,U32 modifier,U32 action,U16 button)
|
||||
{
|
||||
// Only respond to button down
|
||||
if(action != IA_MAKE)
|
||||
return;
|
||||
|
||||
// Get the window...
|
||||
PlatformWindow *win = mWindowManager->getWindowById(did);
|
||||
GFXVideoMode winVm = win->getVideoMode();
|
||||
|
||||
// If the window is not full screen, make it full screen 800x600x32
|
||||
if(winVm.fullScreen == false)
|
||||
{
|
||||
winVm.fullScreen = true;
|
||||
winVm.resolution.set(800,600);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the window is full screen, then bump it to 400x400x32
|
||||
winVm.fullScreen = false;
|
||||
winVm.resolution.set(400,400);
|
||||
}
|
||||
|
||||
win->setVideoMode(winVm);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->appEvent.notify(this, &GFXTestFullscreenToggle::handleAppEvent);
|
||||
mWindows[i]->buttonEvent.notify(this, &GFXTestFullscreenToggle::handleButtonEvent);
|
||||
mWindows[i]->displayEvent.notify(this, &GFXTestFullscreenToggle::handleDrawEvent);
|
||||
|
||||
// Only subscribe to the first idle event.
|
||||
if(i==0)
|
||||
mWindows[i]->idleEvent.notify(this, &GFXTestFullscreenToggle::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
// Finally, clean up.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
SAFE_DELETE(mWindows[i]);
|
||||
|
||||
mDevice->preDestroy();
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindowManager);
|
||||
}
|
||||
};
|
||||
202
Engine/source/windowManager/win32/win32CursorController.cpp
Normal file
202
Engine/source/windowManager/win32/win32CursorController.cpp
Normal 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();
|
||||
// }
|
||||
//}
|
||||
52
Engine/source/windowManager/win32/win32CursorController.h
Normal file
52
Engine/source/windowManager/win32/win32CursorController.h
Normal 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
|
||||
142
Engine/source/windowManager/win32/win32SplashScreen.cpp
Normal file
142
Engine/source/windowManager/win32/win32SplashScreen.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
1162
Engine/source/windowManager/win32/win32Window.cpp
Normal file
1162
Engine/source/windowManager/win32/win32Window.cpp
Normal file
File diff suppressed because it is too large
Load diff
231
Engine/source/windowManager/win32/win32Window.h
Normal file
231
Engine/source/windowManager/win32/win32Window.h
Normal 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
|
||||
453
Engine/source/windowManager/win32/win32WindowMgr.cpp
Normal file
453
Engine/source/windowManager/win32/win32WindowMgr.cpp
Normal 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> ®ions)
|
||||
{
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (U32)(void*)®ions);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
93
Engine/source/windowManager/win32/win32WindowMgr.h
Normal file
93
Engine/source/windowManager/win32/win32WindowMgr.h
Normal 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> ®ions);
|
||||
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
|
||||
594
Engine/source/windowManager/win32/winDispatch.cpp
Normal file
594
Engine/source/windowManager/win32/winDispatch.cpp
Normal 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);
|
||||
}
|
||||
74
Engine/source/windowManager/win32/winDispatch.h
Normal file
74
Engine/source/windowManager/win32/winDispatch.h
Normal 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
|
||||
370
Engine/source/windowManager/windowInputGenerator.cpp
Normal file
370
Engine/source/windowManager/windowInputGenerator.cpp
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "windowManager/windowInputGenerator.h"
|
||||
#include "windowManager/platformWindow.h"
|
||||
#include "sim/actionMap.h"
|
||||
#include "component/interfaces/IProcessInput.h"
|
||||
|
||||
|
||||
extern InputModifiers convertModifierBits(const U32 in);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor/Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
WindowInputGenerator::WindowInputGenerator( PlatformWindow *window ) :
|
||||
mWindow(window),
|
||||
mInputController(NULL),
|
||||
mLastCursorPos(0,0),
|
||||
mClampToWindow(true),
|
||||
mPixelsPerMickey(1.0f),
|
||||
mNotifyPosition(true),
|
||||
mFocused(false)
|
||||
{
|
||||
AssertFatal(mWindow, "NULL PlatformWindow on WindowInputGenerator creation");
|
||||
|
||||
#ifdef TORQUE_OS_XENON
|
||||
mFocused = true;
|
||||
#endif
|
||||
|
||||
if (mWindow->getOffscreenRender())
|
||||
mFocused = true;
|
||||
|
||||
mWindow->appEvent.notify(this, &WindowInputGenerator::handleAppEvent);
|
||||
mWindow->mouseEvent.notify(this, &WindowInputGenerator::handleMouseMove);
|
||||
mWindow->wheelEvent.notify(this, &WindowInputGenerator::handleMouseWheel);
|
||||
mWindow->buttonEvent.notify(this, &WindowInputGenerator::handleMouseButton);
|
||||
mWindow->keyEvent.notify(this, &WindowInputGenerator::handleKeyboard);
|
||||
mWindow->charEvent.notify(this, &WindowInputGenerator::handleCharInput);
|
||||
|
||||
// We also want to subscribe to input events.
|
||||
Input::smInputEvent.notify(this, &WindowInputGenerator::handleInputEvent);
|
||||
}
|
||||
|
||||
WindowInputGenerator::~WindowInputGenerator()
|
||||
{
|
||||
if( mWindow )
|
||||
{
|
||||
mWindow->mouseEvent.remove(this, &WindowInputGenerator::handleMouseMove);
|
||||
mWindow->buttonEvent.remove(this, &WindowInputGenerator::handleMouseButton);
|
||||
mWindow->wheelEvent.remove(this, &WindowInputGenerator::handleMouseWheel);
|
||||
mWindow->keyEvent.remove(this, &WindowInputGenerator::handleKeyboard);
|
||||
mWindow->charEvent.remove(this, &WindowInputGenerator::handleCharInput);
|
||||
mWindow->appEvent.remove(this, &WindowInputGenerator::handleAppEvent);
|
||||
}
|
||||
|
||||
Input::smInputEvent.remove(this, &WindowInputGenerator::handleInputEvent);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Process an input event and pass it on.
|
||||
// Respect the action map.
|
||||
//-----------------------------------------------------------------------------
|
||||
void WindowInputGenerator::generateInputEvent( InputEventInfo &inputEvent )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
// Give the ActionMap first shot.
|
||||
if (ActionMap::handleEventGlobal(&inputEvent))
|
||||
return;
|
||||
|
||||
if( mInputController->processInputEvent( inputEvent ) )
|
||||
return;
|
||||
|
||||
// If we get here we failed to process it with anything prior... so let
|
||||
// the ActionMap handle it.
|
||||
ActionMap::handleEvent(&inputEvent);
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Mouse Events
|
||||
//-----------------------------------------------------------------------------
|
||||
void WindowInputGenerator::handleMouseMove( WindowId did, U32 modifier, S32 x, S32 y, bool isRelative )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
// jddTODO : Clean this up
|
||||
// CodeReview currently the Torque GuiCanvas deals with mouse input
|
||||
// as relative movement, even when the cursor is visible. Because
|
||||
// of this there is an asinine bit of code in there that manages
|
||||
// updating the cursor position on the class based on relative movement.
|
||||
// Because of this we always have to generate and send off for processing
|
||||
// relative events, even if the mouse is not locked.
|
||||
// I'm considering removing this in the Canvas refactor, thoughts? [7/6/2007 justind]
|
||||
|
||||
// Generate a base Movement along and Axis event
|
||||
InputEventInfo event;
|
||||
event.deviceType = MouseDeviceType;
|
||||
event.deviceInst = 0;
|
||||
event.objType = SI_AXIS;
|
||||
event.modifier = convertModifierBits(modifier);
|
||||
event.ascii = 0;
|
||||
|
||||
// Generate delta movement along each axis
|
||||
Point2F cursDelta;
|
||||
if(isRelative)
|
||||
{
|
||||
cursDelta.x = F32(x) * mPixelsPerMickey;
|
||||
cursDelta.y = F32(y) * mPixelsPerMickey;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursDelta.x = F32(x - mLastCursorPos.x);
|
||||
cursDelta.y = F32(y - mLastCursorPos.y);
|
||||
}
|
||||
|
||||
// If X axis changed, generate a relative event
|
||||
if(mFabs(cursDelta.x) > 0.1)
|
||||
{
|
||||
event.objInst = SI_XAXIS;
|
||||
event.action = SI_MOVE;
|
||||
event.fValue = cursDelta.x;
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
// If Y axis changed, generate a relative event
|
||||
if(mFabs(cursDelta.y) > 0.1)
|
||||
{
|
||||
event.objInst = SI_YAXIS;
|
||||
event.action = SI_MOVE;
|
||||
event.fValue = cursDelta.y;
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
// CodeReview : If we're not relative, pass along a positional update
|
||||
// so that the canvas can update it's internal cursor tracking
|
||||
// point. [7/6/2007 justind]
|
||||
if( !isRelative )
|
||||
{
|
||||
if( mClampToWindow )
|
||||
{
|
||||
Point2I winExtent = mWindow->getClientExtent();
|
||||
x = mClampF(x, 0.0f, F32(winExtent.x - 1));
|
||||
y = mClampF(y, 0.0f, F32(winExtent.y - 1));
|
||||
|
||||
}
|
||||
|
||||
// When the window gains focus, we send a cursor position event
|
||||
if( mNotifyPosition )
|
||||
{
|
||||
mNotifyPosition = false;
|
||||
|
||||
// We use SI_MAKE to signify that the position is being set, not relatively moved.
|
||||
event.action = SI_MAKE;
|
||||
|
||||
// X Axis
|
||||
event.objInst = SI_XAXIS;
|
||||
event.fValue = (F32)x;
|
||||
generateInputEvent(event);
|
||||
|
||||
// Y Axis
|
||||
event.objInst = SI_YAXIS;
|
||||
event.fValue = (F32)y;
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
mLastCursorPos = Point2I(x,y);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mLastCursorPos += Point2I(x,y);
|
||||
mNotifyPosition = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowInputGenerator::handleMouseButton( WindowId did, U32 modifiers, U32 action, U16 button )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
InputEventInfo event;
|
||||
event.deviceType = MouseDeviceType;
|
||||
event.deviceInst = 0;
|
||||
event.objType = SI_BUTTON;
|
||||
event.objInst = (InputObjectInstances)(KEY_BUTTON0 + button);
|
||||
event.modifier = convertModifierBits(modifiers);
|
||||
event.ascii = 0;
|
||||
event.action = (action==IA_MAKE) ? SI_MAKE : SI_BREAK;
|
||||
event.fValue = (action==IA_MAKE) ? 1.0 : 0.0;
|
||||
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
void WindowInputGenerator::handleMouseWheel( WindowId did, U32 modifiers, S32 wheelDeltaX, S32 wheelDeltaY )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
InputEventInfo event;
|
||||
event.deviceType = MouseDeviceType;
|
||||
event.deviceInst = 0;
|
||||
event.objType = SI_AXIS;
|
||||
event.modifier = convertModifierBits(modifiers);
|
||||
event.ascii = 0;
|
||||
event.action = SI_MOVE;
|
||||
|
||||
if( wheelDeltaY ) // Vertical
|
||||
{
|
||||
event.objInst = SI_ZAXIS;
|
||||
event.fValue = (F32)wheelDeltaY;
|
||||
|
||||
generateInputEvent(event);
|
||||
}
|
||||
if( wheelDeltaX ) // Horizontal
|
||||
{
|
||||
event.objInst = SI_RZAXIS;
|
||||
event.fValue = (F32)wheelDeltaX;
|
||||
|
||||
generateInputEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Key/Character Input
|
||||
//-----------------------------------------------------------------------------
|
||||
void WindowInputGenerator::handleCharInput( WindowId did, U32 modifier, U16 key )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
InputEventInfo event;
|
||||
event.deviceType = KeyboardDeviceType;
|
||||
event.deviceInst = 0;
|
||||
event.objType = SI_KEY;
|
||||
event.objInst = KEY_NULL;
|
||||
event.modifier = convertModifierBits(modifier);
|
||||
event.ascii = key;
|
||||
event.action = SI_MAKE;
|
||||
event.fValue = 1.0;
|
||||
generateInputEvent(event);
|
||||
|
||||
event.action = SI_BREAK;
|
||||
event.fValue = 0.f;
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
|
||||
void WindowInputGenerator::handleKeyboard( WindowId did, U32 modifier, U32 action, U16 key )
|
||||
{
|
||||
if( !mInputController || !mFocused )
|
||||
return;
|
||||
|
||||
InputEventInfo event;
|
||||
event.deviceType = KeyboardDeviceType;
|
||||
event.deviceInst = 0;
|
||||
event.objType = SI_KEY;
|
||||
event.objInst = (InputObjectInstances)key;
|
||||
event.modifier = convertModifierBits(modifier);
|
||||
event.ascii = 0;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case IA_MAKE:
|
||||
event.action = SI_MAKE;
|
||||
event.fValue = 1.f;
|
||||
break;
|
||||
|
||||
case IA_REPEAT:
|
||||
event.action = SI_REPEAT;
|
||||
event.fValue = 1.f;
|
||||
break;
|
||||
|
||||
case IA_BREAK:
|
||||
event.action = SI_BREAK;
|
||||
event.fValue = 0.f;
|
||||
break;
|
||||
|
||||
// If we encounter an unknown don't submit the event.
|
||||
default:
|
||||
//Con::warnf("GuiCanvas::handleKeyboard - got an unknown action type %d!", action);
|
||||
return;
|
||||
}
|
||||
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Raw input
|
||||
//-----------------------------------------------------------------------------
|
||||
void WindowInputGenerator::handleInputEvent( U32 deviceInst,F32 fValue, U16 deviceType, U16 objType, U16 ascii, U16 objInst, U8 action, U8 modifier )
|
||||
{
|
||||
// Skip it if we don't have focus.
|
||||
if(!mInputController || !mFocused)
|
||||
return;
|
||||
|
||||
// Convert to an InputEventInfo and pass it around for processing.
|
||||
InputEventInfo event;
|
||||
event.deviceInst = deviceInst;
|
||||
event.fValue = fValue;
|
||||
event.deviceType = (InputDeviceTypes)deviceType;
|
||||
event.objType = (InputEventType)objType;
|
||||
event.ascii = ascii;
|
||||
event.objInst = (InputObjectInstances)objInst;
|
||||
event.action = (InputActionType)action;
|
||||
event.modifier = (InputModifiers)modifier;
|
||||
|
||||
generateInputEvent(event);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Window Events
|
||||
//-----------------------------------------------------------------------------
|
||||
void WindowInputGenerator::handleAppEvent( WindowId did, S32 event )
|
||||
{
|
||||
if(event == LoseFocus)
|
||||
{
|
||||
// Fire all breaks; this will prevent issues with dangling keys.
|
||||
ActionMap::clearAllBreaks();
|
||||
mFocused = false;
|
||||
}
|
||||
else if(event == GainFocus)
|
||||
{
|
||||
// Set an update flag to notify the consumer of the absolute mouse position next move
|
||||
mNotifyPosition = true;
|
||||
mFocused = true;
|
||||
}
|
||||
|
||||
// always focused with offscreen rendering
|
||||
if (mWindow->getOffscreenRender())
|
||||
mFocused = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Character Input Mapping
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool WindowInputGenerator::wantAsKeyboardEvent( U32 modifiers, U32 keyCode )
|
||||
{
|
||||
// Disallow translation on keys that are bound in the global action map.
|
||||
|
||||
return ActionMap::getGlobalMap()->isAction(
|
||||
KeyboardDeviceType,
|
||||
0,
|
||||
modifiers,
|
||||
keyCode
|
||||
);
|
||||
}
|
||||
77
Engine/source/windowManager/windowInputGenerator.h
Normal file
77
Engine/source/windowManager/windowInputGenerator.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _WINDOW_INPUTGENERATOR_H_
|
||||
#define _WINDOW_INPUTGENERATOR_H_
|
||||
|
||||
#ifndef _PLATFORMINPUT_H_
|
||||
#include "platform/platformInput.h"
|
||||
#endif
|
||||
#ifndef _MPOINT2_H_
|
||||
#include "math/mPoint2.h"
|
||||
#endif
|
||||
|
||||
|
||||
class IProcessInput;
|
||||
class PlatformWindow;
|
||||
|
||||
|
||||
class WindowInputGenerator
|
||||
{
|
||||
bool mNotifyPosition;
|
||||
|
||||
protected:
|
||||
|
||||
PlatformWindow *mWindow;
|
||||
IProcessInput *mInputController;
|
||||
Point2I mLastCursorPos;
|
||||
bool mClampToWindow;
|
||||
bool mFocused; ///< We store this off to avoid polling the OS constantly
|
||||
|
||||
/// This is the scale factor which relates mouse movement in pixels
|
||||
/// (one unit of mouse movement is a mickey) to units in the GUI.
|
||||
F32 mPixelsPerMickey;
|
||||
|
||||
// Event Handlers
|
||||
void handleMouseButton(WindowId did, U32 modifier, U32 action, U16 button);
|
||||
void handleMouseWheel (WindowId did, U32 modifier, S32 wheelDeltaX, S32 wheelDeltaY);
|
||||
void handleMouseMove (WindowId did, U32 modifier, S32 x, S32 y, bool isRelative);
|
||||
void handleKeyboard (WindowId did, U32 modifier, U32 action, U16 key);
|
||||
void handleCharInput (WindowId did, U32 modifier, U16 key);
|
||||
void handleAppEvent (WindowId did, S32 event);
|
||||
void handleInputEvent (U32 deviceInst,F32 fValue, U16 deviceType, U16 objType, U16 ascii, U16 objInst, U8 action, U8 modifier);
|
||||
|
||||
void generateInputEvent( InputEventInfo &inputEvent );
|
||||
|
||||
public:
|
||||
|
||||
WindowInputGenerator( PlatformWindow *window );
|
||||
virtual ~WindowInputGenerator();
|
||||
|
||||
void setInputController( IProcessInput *inputController ) { mInputController = inputController; };
|
||||
|
||||
/// Returns true if the given keypress event should be send as a raw keyboard
|
||||
/// event even if it maps to a character input event.
|
||||
bool wantAsKeyboardEvent( U32 modifiers, U32 key );
|
||||
};
|
||||
|
||||
#endif // _WINDOW_INPUTGENERATOR_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue