2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

CWE Directory Reorganization

Rearrange directory structure of CWE to be loosely equivalent to
the H'uru Plasma repository.

Part 1: Movement of directories and files.
This commit is contained in:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAvatarInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef plAvatarInputInterface_inc
#define plAvatarInputInterface_inc
#include "plInputInterface.h"
#include "../pnInputCore/plInputMap.h"
#include "hsTemplates.h"
#include "hsGeometry3.h"
#include "hsUtils.h"
//// Class Definition ////////////////////////////////////////////////////////
class plInputEventMsg;
class plMouseEventMsg;
class plKeyMap;
class plMouseMap;
class plKey;
class hsStream;
class hsResMgr;
class plAvatarInputMap;
class plPipeline;
class plAvatarInputInterface;
//// Little Input Map Helpers ////////////////////////////////////////////////
class plAvatarInputMap
{
protected:
plAvatarInputInterface *fInterface;
public:
plAvatarInputMap();
virtual ~plAvatarInputMap();
virtual char *GetName() = 0;
virtual hsBool IsBasic() { return false; }
plMouseMap *fMouseMap;
UInt32 fButtonState;
};
// Basic avatar mappings, for when the avatar is in "suspended input" mode.
class plSuspendedMovementMap : public plAvatarInputMap
{
public:
plSuspendedMovementMap();
virtual char *GetName() { return "Suspended Movement"; }
};
// The above, plus movement
class plBasicControlMap : public plSuspendedMovementMap
{
public:
plBasicControlMap();
virtual char *GetName() { return "Basic"; }
virtual hsBool IsBasic() { return true; }
};
// The above, plus movement
class plBasicThirdPersonControlMap : public plBasicControlMap
{
public:
plBasicThirdPersonControlMap();
virtual char *GetName() { return "Basic Third Person"; }
};
class plLadderControlMap : public plSuspendedMovementMap
{
public:
plLadderControlMap();
virtual char *GetName() { return "LadderClimb"; }
};
class plLadderMountMap : public plSuspendedMovementMap
{
public:
plLadderMountMap();
virtual char *GetName() { return "Ladder Mount"; }
};
class plLadderDismountMap : public plSuspendedMovementMap
{
public:
plLadderDismountMap();
virtual char *GetName() { return "Ladder Dismount"; }
};
class plBasicFirstPersonControlMap : public plBasicControlMap
{
public:
plBasicFirstPersonControlMap();
virtual char *GetName() { return "Basic First Person"; }
};
// Mouse walk mode
class pl3rdWalkMap : public plAvatarInputMap
{
public:
pl3rdWalkMap();
virtual ~pl3rdWalkMap();
};
class pl3rdWalkForwardMap : public pl3rdWalkMap
{
public:
pl3rdWalkForwardMap();
virtual char *GetName() { return "Walking Forward"; }
};
class pl3rdWalkBackwardMap : public pl3rdWalkMap
{
public:
pl3rdWalkBackwardMap();
virtual char *GetName() { return "Walking Backward"; }
};
class pl3rdWalkBackwardLBMap : public pl3rdWalkMap
{
public:
pl3rdWalkBackwardLBMap();
virtual char *GetName() { return "Walking Backward (LB)"; }
};
///////////////////////////////////////////////////////////////////////////////////
class plAvatarInputInterface : public plInputInterface
{
protected:
UInt32 fCurrentCursor;
hsScalar fCursorOpacity, fCursorTimeout, fCursorFadeDelay;
plAvatarInputMap *fInputMap;
static plAvatarInputInterface *fInstance;
virtual hsBool IHandleCtrlCmd( plCtrlCmd *cmd );
// Gets called once per IUpdate(), just like normal IEval()s
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty );
void IDeactivateCommand(plMouseInfo *info);
void IChangeInputMaps(plAvatarInputMap *newMap);
void ISetSuspendMovementMode();
void ISetBasicMode();
void ISetMouseWalkMode(ControlEventCode code);
void ISetLadderMap();
void ISetPreLadderMap();
void ISetPostLadderMap();
hsBool IHasControlFlag(int f) const { return fControlFlags.IsBitSet(f); }
void IClearControlFlag(int which) { fControlFlags.ClearBit( which ); }
hsBool CursorInBox(plMouseEventMsg* pMsg, hsPoint4 box);
void ClearMouseCursor();
void DisableMouseInput() { fMouseDisabled = true; }
void EnableMouseInput() { fMouseDisabled = false; }
void Reset();
void RequestCursorToWorldPos(hsScalar xPos, hsScalar yPos, int ID);
hsBitVector fControlFlags;
hsBool fMouseDisabled;
plPipeline* fPipe;
int fCursorState;
int fCursorPriority;
hsBool f3rdPerson;
public:
plAvatarInputInterface();
virtual ~plAvatarInputInterface();
void CameraInThirdPerson(hsBool state);
// Always return true, since the cursor should be representing how we control the avatar
virtual hsBool HasInterestingCursorID( void ) const { return true; }
virtual UInt32 GetPriorityLevel( void ) const { return kAvatarInputPriority; }
virtual UInt32 GetCurrentCursorID( void ) const { return fCurrentCursor; }
virtual hsScalar GetCurrentCursorOpacity( void ) const { return fCursorOpacity; }
char* GetInputMapName() { return fInputMap ? fInputMap->GetName() : ""; }
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
virtual void MissedInputEvent( plInputEventMsg *pMsg );
virtual hsBool MsgReceive( plMessage *msg );
virtual void Init( plInputInterfaceMgr *manager );
virtual void Shutdown( void );
virtual void RestoreDefaultKeyMappings( void );
virtual void ClearKeyMap();
// [dis/en]able mouse commands for avatar movement
void SuspendMouseMovement();
void EnableMouseMovement();
void EnableJump(hsBool val);
void EnableForwardMovement(hsBool val);
void EnableControl(hsBool val, ControlEventCode code);
void ClearLadderMode();
void SetLadderMode();
void ForceAlwaysRun(hsBool val);
void SetControlFlag(int f, hsBool val = true) { fControlFlags.SetBit(f, val); }
void SetCursorFadeDelay( hsScalar delay ) { fCursorFadeDelay = delay; }
hsBool IsEnterChatModeBound();
static plAvatarInputInterface *GetInstance( void ) { return fInstance; }
};
#endif plAvatarInputInterface_inc

View File

@ -0,0 +1,293 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// plDInputDevice.cpp
#include "hsConfig.h"
#include "hsWindows.h"
#include "plDInputDevice.h"
#include "plgDispatch.h"
#include "../plMessage/plInputEventMsg.h"
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
//
//
//
// plDInputDevice
//
//
plDInputDevice::plDInputDevice() :
fX(0.5),
fY(0.5)
{
}
plDInputDevice::~plDInputDevice()
{
}
void plDInputDevice::Update(DIDEVICEOBJECTDATA* js)
{
switch(js->uAppData)
{
case A_CONTROL_MOVE:
{
int i = (int)(js->dwData);
if (i <= -1)
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MOVE_FORWARD );
pMsg->SetControlActivated( true );
plgDispatch::MsgSend( pMsg );
}
else
if (i >= 1)
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MOVE_BACKWARD );
pMsg->SetControlActivated( true );
plgDispatch::MsgSend( pMsg );
}
else
if (i == 0)
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MOVE_BACKWARD );
pMsg->SetControlActivated( false );
plgDispatch::MsgSend( pMsg );
plControlEventMsg* pMsg2 = TRACKED_NEW plControlEventMsg;
pMsg2->SetControlCode( B_CONTROL_MOVE_FORWARD );
pMsg2->SetControlActivated( false );
plgDispatch::MsgSend( pMsg2 );
}
}
break;
case A_CONTROL_TURN:
{
int i = (int)(js->dwData);
float f = ((float)i) * 0.001f;
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( A_CONTROL_TURN );
if (f <= 0.02 && f >= -0.02)
pMsg->SetControlActivated( false );
else
pMsg->SetControlActivated( true );
pMsg->SetControlPct(f);
plgDispatch::MsgSend( pMsg );
}
break;
case B_CONTROL_ACTION:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_ACTION );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_MODIFIER_FAST:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MODIFIER_FAST );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_JUMP:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_JUMP );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_STRAFE_LEFT:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_STRAFE_LEFT );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_STRAFE_RIGHT:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_STRAFE_RIGHT);
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_EQUIP:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_EQUIP );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_DROP:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_DROP );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_MOVE_FORWARD:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MOVE_FORWARD );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_MOVE_BACKWARD:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_MOVE_BACKWARD );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_ROTATE_RIGHT:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_ROTATE_RIGHT);
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_ROTATE_LEFT:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_ROTATE_LEFT );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CONTROL_TURN_TO:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CONTROL_TURN_TO );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case B_CAMERA_RECENTER:
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlCode( B_CAMERA_RECENTER );
pMsg->SetControlActivated(js->dwData & 0x80);
plgDispatch::MsgSend(pMsg);
}
break;
case A_CONTROL_MOUSE_X:
{
int i = (int)(js->dwData);
float f = ((float)i) * 0.001f;
if (f <= 0.02 && f >= -0.02)
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlActivated( false );
pMsg->SetControlCode(B_CAMERA_ROTATE_DOWN);
pMsg->SetControlPct(0);
plgDispatch::MsgSend( pMsg );
plControlEventMsg* pMsg2 = TRACKED_NEW plControlEventMsg;
pMsg2->SetControlActivated( false );
pMsg2->SetControlCode(B_CAMERA_ROTATE_UP);
pMsg2->SetControlPct(0);
plgDispatch::MsgSend( pMsg2 );
}
else
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlActivated( true );
if (f < 0)
pMsg->SetControlCode(B_CAMERA_ROTATE_DOWN);
else
pMsg->SetControlCode(B_CAMERA_ROTATE_UP);
pMsg->SetControlPct(f);
plgDispatch::MsgSend( pMsg );
}
}
break;
case A_CONTROL_MOUSE_Y:
{
int i = (int)(js->dwData);
float f = ((float)i) * 0.001f;
if (f <= 0.02 && f >= -0.02)
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlActivated( false );
pMsg->SetControlCode(B_CAMERA_ROTATE_RIGHT);
pMsg->SetControlPct(0);
plgDispatch::MsgSend( pMsg );
plControlEventMsg* pMsg2 = TRACKED_NEW plControlEventMsg;
pMsg2->SetControlActivated( false );
pMsg2->SetControlCode(B_CAMERA_ROTATE_LEFT);
pMsg2->SetControlPct(0);
plgDispatch::MsgSend( pMsg2 );
}
else
{
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
pMsg->SetControlActivated( true );
if (f < 0)
pMsg->SetControlCode(B_CAMERA_ROTATE_RIGHT);
else
pMsg->SetControlCode(B_CAMERA_ROTATE_LEFT);
pMsg->SetControlPct(f);
plgDispatch::MsgSend( pMsg );
}
}
break;
default:
break;
}
}

View File

@ -0,0 +1,66 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// plDInputDevice.h
#ifndef PL_DINPUT_DEVICE_H
#define PL_DINPUT_DEVICE_H
#include "plInputDevice.h"
struct DIDEVICEOBJECTDATA;
class plDInputDevice : public plInputDevice
{
public:
plDInputDevice();
~plDInputDevice();
const char* GetInputName() { return "DInput"; }
virtual void Update(DIDEVICEOBJECTDATA* js);
protected:
hsScalar fX,fY;
};
#endif // PL_INPUT_DEVICE_H

View File

@ -0,0 +1,357 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plDebugInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsConfig.h"
#include "hsWindows.h"
#include "hsTypes.h"
#include "plDebugInputInterface.h"
#include "plInputInterfaceMgr.h"
#include "plInputManager.h"
#include "plInputDevice.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
#include "../plMessage/plInputEventMsg.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnInputCore/plKeyMap.h"
#include "plgDispatch.h"
#include "plPipeline.h"
#include "hsConfig.h"
plDebugInputInterface *plDebugInputInterface::fInstance = nil;
//// Constructor/Destructor //////////////////////////////////////////////////
plDebugInputInterface::plDebugInputInterface()
{
fInstance = this;
// Add our control codes to our control map. Do NOT add the key bindings yet.
// Note: HERE is where you specify the actions for each command, i.e. net propagate and so forth.
// This part basically declares us master of the bindings for these commands.
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
#ifndef PLASMA_EXTERNAL_RELEASE
// fControlMap->AddCode( B_CONTROL_MODIFIER_FAST, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_DRIVE_SPEED_UP, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_DRIVE_SPEED_DOWN, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_MOVE_FORWARD, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_MOVE_BACKWARD, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_MOVE_LEFT, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_MOVE_RIGHT, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_MOVE_UP, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_MOVE_DOWN, kControlFlagNormal | kControlFlagNoRepeat );
// fControlMap->AddCode( B_TOGGLE_DRIVE_MODE, kControlFlagNormal | kControlFlagNoRepeat | kControlFlagShift );
#endif
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
}
plDebugInputInterface::~plDebugInputInterface()
{
fInstance = nil;
}
//// Init/Shutdown ///////////////////////////////////////////////////////////
void plDebugInputInterface::Init( plInputInterfaceMgr *manager )
{
plInputInterface::Init( manager );
}
void plDebugInputInterface::Shutdown( void )
{
}
//// RestoreDefaultKeyMappings ///////////////////////////////////////////////
void plDebugInputInterface::RestoreDefaultKeyMappings( void )
{
if( fControlMap == nil )
return;
fControlMap->UnmapAllBindings();
#ifndef PLASMA_EXTERNAL_RELEASE
// fControlMap->BindKey( KEY_SHIFT, B_CONTROL_MODIFIER_FAST );
fControlMap->BindKey( plShiftKeyCombo( KEY_EQUAL ), B_CAMERA_DRIVE_SPEED_UP );
fControlMap->BindKey( plShiftKeyCombo( KEY_DASH ), B_CAMERA_DRIVE_SPEED_DOWN );
fControlMap->BindKey( KEY_W, B_CAMERA_MOVE_FORWARD );
fControlMap->BindKey( KEY_S, B_CAMERA_MOVE_BACKWARD );
fControlMap->BindKey( KEY_A, B_CAMERA_MOVE_LEFT );
fControlMap->BindKey( KEY_D, B_CAMERA_MOVE_RIGHT );
fControlMap->BindKey( KEY_I, B_CAMERA_MOVE_UP );
fControlMap->BindKey( KEY_K, B_CAMERA_MOVE_DOWN );
// fControlMap->BindKey( KEY_C, B_TOGGLE_DRIVE_MODE );
#endif
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool plDebugInputInterface::IEval( double secs, hsScalar del, UInt32 dirty )
{
return true;
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool plDebugInputInterface::MsgReceive( plMessage *msg )
{
return plInputInterface::MsgReceive(msg);
}
//// cursorinbox /////////////////////////////////////////////////////
hsBool plDebugInputInterface::CursorInBox(plMouseEventMsg* pMsg, hsPoint4 box)
{
return ( pMsg->GetXPos() >= box.fX && pMsg->GetXPos() <= box.fY && pMsg->GetYPos() >= box.fZ && pMsg->GetYPos() <= box.fW );
}
//// InterpretInputEvent /////////////////////////////////////////////////////
hsBool plDebugInputInterface::InterpretInputEvent( plInputEventMsg *pMsg )
{
hsBool handled = false;
plMouseEventMsg* pMouseMsg = plMouseEventMsg::ConvertNoRef(pMsg);
if (pMouseMsg)
{
// check for button presses...
if (fButtonState & kLeftButtonDown)
{
fButtonState |= kLeftButtonRepeat;
}
if (fButtonState & kRightButtonDown)
{
fButtonState |= kRightButtonRepeat;
}
if (pMouseMsg->GetButton() == kLeftButtonDown)
{
fButtonState |= kLeftButtonDown;
}
if (pMouseMsg->GetButton() == kLeftButtonUp)
{
fButtonState &= ~kLeftButtonDown;
fButtonState &= ~kLeftButtonRepeat;
}
if (pMouseMsg->GetButton() == kRightButtonDown)
{
fButtonState |= kRightButtonDown;
}
if (pMouseMsg->GetButton() == kRightButtonUp)
{
fButtonState &= ~kRightButtonDown;
fButtonState &= ~kRightButtonRepeat;
}
for (int i=0; i < fMouseMap.fMap.Count(); i++)
{
// is this control already set?
if (fControlFlags.IsBitSet(fMouseMap.fMap[i]->fCode))
{
// can we disable this control?
hsBool disable = false;
// can we disable this control based on a button?
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButton && !(fButtonState & kLeftButtonDown))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButton && !(fButtonState & kRightButtonDown))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonEx && (fButtonState & kLeftButtonRepeat))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonEx && (fButtonState & kRightButtonRepeat))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonEx && !(fButtonState & kLeftButtonDown))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonEx && !(fButtonState & kRightButtonDown))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonRepeat && !(fButtonState & kLeftButtonDown))
disable = true;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonRepeat && !(fButtonState & kRightButtonDown))
disable = true;
// can we disable this control based on the cursor position?
if (!CursorInBox(pMouseMsg, fMouseMap.fMap[i]->fBox) && fMouseMap.fMap[i]->fControlFlags & kControlFlagBoxDisable)
disable = true;
if (disable)
{
plCtrlCmd* pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fNetPropagateToPlayers = fMouseMap.fMap[i]->fControlFlags & kControlFlagNetPropagate;
pCmd->fControlActivated = false;
pCmd->fControlCode = fMouseMap.fMap[i]->fCode;
fControlFlags.ClearBit(pCmd->fControlCode);
fMessageQueue->Append(pCmd);
handled = true;
continue;
}
// is it a range control? If so we need to re-send the command
if ((fMouseMap.fMap[i]->fControlFlags & kControlFlagRangePos) || (fMouseMap.fMap[i]->fControlFlags & kControlFlagRangeNeg))
{
plCtrlCmd* pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fControlActivated = true;
pCmd->fControlCode = fMouseMap.fMap[i]->fCode;
hsScalar pct = 0.0f;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRangePos)
{
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagXAxisEvent)
pct = hsABS((fMouseMap.fMap[i]->fBox.fX - pMouseMsg->GetXPos()) / (fMouseMap.fMap[i]->fBox.fY - fMouseMap.fMap[i]->fBox.fX));
else
pct = hsABS((fMouseMap.fMap[i]->fBox.fZ - pMouseMsg->GetYPos()) / (fMouseMap.fMap[i]->fBox.fW - fMouseMap.fMap[i]->fBox.fZ));
}
else
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRangeNeg)
{
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagXAxisEvent)
pct = hsABS((fMouseMap.fMap[i]->fBox.fY - pMouseMsg->GetXPos()) / (fMouseMap.fMap[i]->fBox.fY - fMouseMap.fMap[i]->fBox.fX));
else
pct = hsABS((fMouseMap.fMap[i]->fBox.fW - pMouseMsg->GetYPos()) / (fMouseMap.fMap[i]->fBox.fW - fMouseMap.fMap[i]->fBox.fZ));
}
pCmd->fPct = pct;
if (pct == 1.0f || pct == -1.0f)
{
delete pCmd;
break;
}
pCmd->fNetPropagateToPlayers = fMouseMap.fMap[i]->fControlFlags & kControlFlagNetPropagate;
fMessageQueue->Append(pCmd);
}
}
else // if it is an 'always if in box' command see if it's not in the box
if ( (fMouseMap.fMap[i]->fControlFlags & kControlFlagInBox) && (!CursorInBox(pMouseMsg, fMouseMap.fMap[i]->fBox)) )
{
plCtrlCmd* pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fControlActivated = false;
pCmd->fControlCode = fMouseMap.fMap[i]->fCode;
pCmd->fNetPropagateToPlayers = fMouseMap.fMap[i]->fControlFlags & kControlFlagNetPropagate;
fMessageQueue->Append(pCmd);
continue;
}
else // the control is not set, see if we should set it.
{
// is the cursor in the appropriate box?
if (CursorInBox(pMouseMsg, fMouseMap.fMap[i]->fBox))
{
// do we require a button?
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButton && !(fButtonState & kLeftButtonDown))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButton && !(fButtonState & kRightButtonDown))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonEx && (fButtonState & kLeftButtonRepeat))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonEx && (fButtonState & kRightButtonRepeat))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonRepeat && !(fButtonState & kLeftButtonRepeat))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonRepeat && !(fButtonState & kRightButtonRepeat))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonEx && !(fButtonState & kLeftButtonDown))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonEx && !(fButtonState & kLeftButtonDown))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagLeftButtonUp && !(pMouseMsg->GetButton() == kLeftButtonUp))
continue;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRightButtonUp && !(pMouseMsg->GetButton() == kRightButtonUp))
continue;
// okay, we're in the box and either we don't require a button or our button is pressed.
// so set the command as 'enabled'
// UNLESS it has kControlFlagInBox, which means we want it sent every frame it is in the box
if (!(fMouseMap.fMap[i]->fControlFlags & kControlFlagInBox))
fControlFlags.SetBit(fMouseMap.fMap[i]->fCode);
// issue the command
plCtrlCmd* pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fControlActivated = true;
pCmd->fControlCode = fMouseMap.fMap[i]->fCode;
pCmd->fNetPropagateToPlayers = fMouseMap.fMap[i]->fControlFlags & kControlFlagNetPropagate;
// figure out what percent (if any)
hsScalar pct = 0.0f;
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRangePos)
{
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagXAxisEvent)
pct = hsABS((fMouseMap.fMap[i]->fBox.fX - pMouseMsg->GetXPos()) / (fMouseMap.fMap[i]->fBox.fY - fMouseMap.fMap[i]->fBox.fX));
else
pct = hsABS((fMouseMap.fMap[i]->fBox.fZ - pMouseMsg->GetYPos()) / (fMouseMap.fMap[i]->fBox.fW - fMouseMap.fMap[i]->fBox.fZ));
}
else
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagRangeNeg)
{
if (fMouseMap.fMap[i]->fControlFlags & kControlFlagXAxisEvent)
pct = hsABS((fMouseMap.fMap[i]->fBox.fY - pMouseMsg->GetXPos()) / (fMouseMap.fMap[i]->fBox.fY - fMouseMap.fMap[i]->fBox.fX));
else
pct = hsABS((fMouseMap.fMap[i]->fBox.fW - pMouseMsg->GetYPos()) / (fMouseMap.fMap[i]->fBox.fW - fMouseMap.fMap[i]->fBox.fZ));
}
pCmd->fPct = pct;
if (pct == 1.0f || pct == -1.0f)
{
delete pCmd;
break;
}
// and add it to the list
fMessageQueue->Append(pCmd);
handled = true;
continue;
}
}
}
return handled;
}
return false;
}

View File

@ -0,0 +1,94 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plDebugInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plDebugInputInterface_h
#define _plDebugInputInterface_h
#include "plInputInterface.h"
#include "../pnInputCore/plInputMap.h"
//// Class Definition ////////////////////////////////////////////////////////
class plMouseEventMsg;
class plDebugInputInterface : public plInputInterface
{
protected:
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty );
hsBool CursorInBox(plMouseEventMsg* pMsg, hsPoint4 box);
plMouseMap fMouseMap;
UInt32 fButtonState;
hsBitVector fControlFlags;
static plDebugInputInterface *fInstance;
public:
plDebugInputInterface();
virtual ~plDebugInputInterface();
// Always return false,
virtual hsBool HasInterestingCursorID( void ) const { return false; }
virtual UInt32 GetPriorityLevel( void ) const { return kDebugCmdPrioity; }
virtual void RestoreDefaultKeyMappings( void );
virtual UInt32 GetCurrentCursorID( void ) const { return 0; }
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
virtual hsBool MsgReceive( plMessage *msg );
virtual void Init( plInputInterfaceMgr *manager );
virtual void Shutdown( void );
static plDebugInputInterface *GetInstance( void ) { return fInstance; }
};
#endif //_plDebugInputInterface_h

View File

@ -0,0 +1,56 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plInputCoreCreatable_inc
#define plInputCoreCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plInputManager.h"
REGISTER_CREATABLE(plInputManager);
#include "plInputInterfaceMgr.h"
REGISTER_CREATABLE(plInputInterfaceMgr);
#endif // plInputCoreCreatable_inc

View File

@ -0,0 +1,932 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// plInputDevice.cpp
//#include "STRING"
#include "hsConfig.h"
#include "hsWindows.h"
#include "plInputDevice.h"
#include "plInputManager.h"
#include "plAvatarInputInterface.h"
#include "../plMessage/plInputEventMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "hsUtils.h"
#include "plgDispatch.h"
#include "../plPipeline/plPlates.h"
#include "../plPipeline/plDebugText.h"
#include "../plGImage/plMipmap.h"
#include "hsWindows.h"
#include "../NucleusLib/inc/plPipeline.h"
// The resolution that uses the base size of the cursor.
// All other resolutions will scale the cursor size to keep the same physical size.
#define BASE_WIDTH 1024
#define BASE_HEIGHT 768
plKeyboardDevice* plKeyboardDevice::fInstance = nil;
bool plKeyboardDevice::fKeyboardState[256];
hsBool plKeyboardDevice::fIgnoreCapsLock = false;
hsBool plKeyboardDevice::fKeyIsDeadKey = false;
plKeyboardDevice::plKeyboardDevice() :
fShiftKeyDown(false),
fCapsLockKeyDown(false),
fAltKeyDown(false),
fCtrlKeyDown(false),
fCapsLockLock(false),
fPrevNumLockOn(false),
fControlMode(STANDARD_MODE)
{
fInstance = this;
fStartedUpWithNumLockOn = ((GetKeyState(VK_NUMLOCK) & 1) != 0);
InitKeyboardState();
}
plKeyboardDevice::~plKeyboardDevice()
{
if (fStartedUpWithNumLockOn)
ForceNumLock(true);
}
void plKeyboardDevice::InitKeyboardState()
{
static bool initialized = false;
if (!initialized)
{
for (unsigned int i = 0; i < 256; ++i)
plKeyboardDevice::fKeyboardState[i] = false;
initialized = true;
}
}
void plKeyboardDevice::ReleaseAllKeys()
{
// send a key-up message for all "normal" keys
for (unsigned int i = 0; i < 256; ++i)
{
if ((i == KEY_SHIFT) || (i == KEY_CTRL) || (i == KEY_CAPSLOCK))
continue; // these are handled slightly differently
if (fKeyboardState[i])
{
fKeyboardState[i] = false;
// fake a key-up command
plKeyEventMsg* pMsg = TRACKED_NEW plKeyEventMsg;
pMsg->SetKeyCode( (plKeyDef)i );
pMsg->SetKeyDown( false );
pMsg->SetShiftKeyDown( fShiftKeyDown );
pMsg->SetCtrlKeyDown( fCtrlKeyDown );
pMsg->SetCapsLockKeyDown( fCapsLockLock );
pMsg->SetRepeat( false );
plgDispatch::MsgSend( pMsg );
}
}
// send key messages for shift and ctrl if necessary because the keys above need to have
// the proper states of the shift and ctrl keys sent with their messages, and our internal
// flags for these keys need to be cleared. We don't send a key-up message for caps lock
// because it doesn't really operate like every other key on the keyboard
if (fKeyboardState[KEY_SHIFT])
{
fKeyboardState[KEY_SHIFT] = false;
fShiftKeyDown = false;
plKeyEventMsg* pMsg = TRACKED_NEW plKeyEventMsg;
pMsg->SetKeyCode( KEY_SHIFT );
pMsg->SetKeyDown( false );
pMsg->SetShiftKeyDown( false );
pMsg->SetCtrlKeyDown( false );
pMsg->SetCapsLockKeyDown( fCapsLockLock );
pMsg->SetRepeat( false );
plgDispatch::MsgSend( pMsg );
}
if (fKeyboardState[KEY_CTRL])
{
fKeyboardState[KEY_CTRL] = false;
fCtrlKeyDown = false;
plKeyEventMsg* pMsg = TRACKED_NEW plKeyEventMsg;
pMsg->SetKeyCode( KEY_CTRL );
pMsg->SetKeyDown( false );
pMsg->SetShiftKeyDown( false );
pMsg->SetCtrlKeyDown( false );
pMsg->SetCapsLockKeyDown( fCapsLockLock );
pMsg->SetRepeat( false );
plgDispatch::MsgSend( pMsg );
}
}
hsBool plKeyboardDevice::IsCapsLockKeyOn()
{
return fCapsLockLock;
}
void plKeyboardDevice::Shutdown()
{
}
#if HS_BUILD_FOR_WIN32
void plKeyboardDevice::ForceNumLock(hsBool on)
{
if (on != ((GetKeyState(VK_NUMLOCK) & 1) != 0))
{
OSVERSIONINFO info;
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&info);
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
keybd_event( VK_NUMLOCK, 0, KEYEVENTF_EXTENDEDKEY | 0, 0 );
keybd_event( VK_NUMLOCK, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
}
else
{
UInt8 keyState[256];
GetKeyboardState(keyState);
keyState[VK_NUMLOCK] = keyState[VK_NUMLOCK] ^ 1;
SetKeyboardState(keyState);
}
}
}
#endif //HS_BUILD_FOR_WIN32
void plKeyboardDevice::HandleKeyEvent(plOSMsg message, plKeyDef key, bool bKeyDown, hsBool bKeyRepeat)
{
// update the internal keyboard state
unsigned int keyCode = (unsigned int)key;
if ((key >= 0) && (key < 256))
fKeyboardState[key] = bKeyDown;
#if HS_BUILD_FOR_WIN32
if (key == VK_NUMLOCK && bKeyDown)
{
ForceNumLock(false);
}
#endif // HS_BUILD_FOR_WIN32
if (key == KEY_SHIFT)
{
fShiftKeyDown = bKeyDown;
// return;
}
if (key == KEY_CTRL)
{
fCtrlKeyDown = bKeyDown;
// return;
}
if (key == KEY_CAPSLOCK)
{
// Keyboards toggle the light on key-down, so I'm going with that.
if (bKeyDown && !bKeyRepeat)
{
fCapsLockLock = !fCapsLockLock;
plAvatarInputInterface::GetInstance()->ForceAlwaysRun(fCapsLockLock);
}
}
// send a key event...
plKeyEventMsg* pMsg = TRACKED_NEW plKeyEventMsg;
pMsg->SetKeyCode( key );
pMsg->SetKeyDown( bKeyDown );
pMsg->SetShiftKeyDown( fShiftKeyDown );
pMsg->SetCtrlKeyDown( fCtrlKeyDown );
pMsg->SetCapsLockKeyDown( fCapsLockLock );
pMsg->SetRepeat(bKeyRepeat);
plgDispatch::MsgSend( pMsg );
}
void plKeyboardDevice::HandleWindowActivate(bool bActive, HWND hWnd)
{
if (bActive)
{
fCtrlKeyDown = false;
#if HS_BUILD_FOR_WIN32
{
fPrevNumLockOn = ((GetKeyState(VK_NUMLOCK) & 1) != 0);
ForceNumLock(false);
hsBool oldLock = fCapsLockLock;
fCapsLockLock = (GetKeyState(KEY_CAPSLOCK) & 1) != 0;
if (fCapsLockLock != oldLock)
plAvatarInputInterface::GetInstance()->ForceAlwaysRun(fCapsLockLock);
}
#endif
}
else
{
ReleaseAllKeys(); // send key-up events for everything since we're losing focus
#if HS_BUILD_FOR_WIN32
{
if (fPrevNumLockOn)
ForceNumLock(true);
}
#endif
}
}
//// KeyEventToChar //////////////////////////////////////////////////////////
// Translate a Plasma key event to an actual char
char plKeyboardDevice::KeyEventToChar( plKeyEventMsg *msg )
{
short code = msg->GetKeyCode();
char c = 0;
unsigned char *kbState = TRACKED_NEW unsigned char[256];
unsigned char *buffer = TRACKED_NEW unsigned char[256];
UINT scanCode;
int retVal;
buffer[0] = 0;
switch( code )
{
case KEY_A:
case KEY_B:
case KEY_C:
case KEY_D:
case KEY_E:
case KEY_F:
case KEY_G:
case KEY_H:
case KEY_I:
case KEY_J:
case KEY_K:
case KEY_L:
case KEY_M:
case KEY_N:
case KEY_O:
case KEY_P:
case KEY_Q:
case KEY_R:
case KEY_S:
case KEY_T:
case KEY_U:
case KEY_V:
case KEY_W:
case KEY_X:
case KEY_Y:
case KEY_Z:
case KEY_1:
case KEY_2:
case KEY_3:
case KEY_4:
case KEY_5:
case KEY_6:
case KEY_7:
case KEY_8:
case KEY_9:
case KEY_0:
case KEY_TILDE:
case KEY_COMMA:
case KEY_PERIOD:
case KEY_LBRACKET:
case KEY_RBRACKET:
case KEY_BACKSLASH:
case KEY_SLASH:
case KEY_DASH:
case KEY_EQUAL:
case KEY_SEMICOLON:
case KEY_QUOTE:
// let windows translate everything for us!
scanCode = MapVirtualKeyEx(code,0,GetKeyboardLayout(0));
GetKeyboardState(kbState);
if (fIgnoreCapsLock)
kbState[KEY_CAPSLOCK] = 0; // clear the caps lock key
retVal = ToAsciiEx(code,scanCode,kbState,(unsigned short*)buffer,0,GetKeyboardLayout(0));
if (retVal == 2)
{
if ((buffer[0] == buffer[1]) && (!fKeyIsDeadKey))
{
// it's actually a dead key, since the previous key wasn't a dead key
c = (char)buffer[0];
fKeyIsDeadKey = true;
}
else
{
c = (char)buffer[1]; // it was an untranslated dead key, so copy the unconverted key
fKeyIsDeadKey = false;
}
}
else if (retVal == 0)
c = 0; // it's invalid
else
{
c = (char)buffer[0];
if (retVal < 0) // the key was a dead key
fKeyIsDeadKey = true;
else
fKeyIsDeadKey = false;
}
break;
case KEY_ESCAPE: c = 27; break;
case KEY_TAB: c = '\t'; break;
case KEY_BACKSPACE: c = 8; break;
case KEY_ENTER: c = '\n'; break;
case KEY_SPACE: c = ' '; break;
// numlock on numbers
case KEY_NUMPAD0: c = '0'; break;
case KEY_NUMPAD1: c = '1'; break;
case KEY_NUMPAD2: c = '2'; break;
case KEY_NUMPAD3: c = '3'; break;
case KEY_NUMPAD4: c = '4'; break;
case KEY_NUMPAD5: c = '5'; break;
case KEY_NUMPAD6: c = '6'; break;
case KEY_NUMPAD7: c = '7'; break;
case KEY_NUMPAD8: c = '8'; break;
case KEY_NUMPAD9: c = '9'; break;
// everything else
default:
c = 0;
break;
}
delete [] kbState;
delete [] buffer;
return c;
}
//
//
//
// plMouseDevice
//
//
bool plMouseDevice::bMsgAlways = true;
bool plMouseDevice::bCursorHidden = false;
bool plMouseDevice::bCursorOverride = false;
bool plMouseDevice::bInverted = false;
hsScalar plMouseDevice::fWidth = BASE_WIDTH;
hsScalar plMouseDevice::fHeight = BASE_HEIGHT;
plMouseDevice* plMouseDevice::fInstance = 0;
plMouseDevice::plMouseDevice()
{
fXPos = 0;
fYPos = 0;
fCursorID = CURSOR_UP;
fButtonState = 0;
fOpacity = 1.f;
fCursor = nil;
CreateCursor( fCursorID );
plMouseDevice::fInstance = this;
fXMsg = nil;
fYMsg = nil;
fB2Msg = nil;
fLeftBMsg[0] = nil;
fLeftBMsg[1] = nil;
fRightBMsg[0] = nil;
fRightBMsg[1] = nil;
fMiddleBMsg[0] = nil;
fMiddleBMsg[1] = nil;
}
plMouseDevice::~plMouseDevice()
{
plPlateManager::Instance().DestroyPlate( fCursor );
fCursor = nil;
plMouseDevice::fInstance = nil;
}
void plMouseDevice::SetDisplayResolution(hsScalar Width, hsScalar Height)
{
fWidth = Width;
fHeight = Height;
IUpdateCursorSize();
}
void plMouseDevice::CreateCursor( char* cursor )
{
if( fCursor == nil )
{
plPlateManager::Instance().CreatePlate( &fCursor );
fCursor->CreateFromResource(cursor);
}
else
{
fCursor->ReloadFromResource(cursor);
}
fCursor->SetPosition( 0, 0, 0 );
IUpdateCursorSize();
fCursor->SetVisible( true );
fCursor->SetOpacity( fOpacity );
}
void plMouseDevice::IUpdateCursorSize()
{
if(fCursor)
{
// set the size of the cursor based on resolution.
fCursor->SetSize( 2*fCursor->GetMipmap()->GetWidth()/fWidth, 2*fCursor->GetMipmap()->GetHeight()/fHeight );
}
}
void plMouseDevice::AddNameToCursor(const char* name)
{
if (fInstance && name)
{
plDebugText &txt = plDebugText::Instance();
txt.DrawString(fInstance->fWXPos + 12 ,fInstance->fWYPos - 7,name);
}
}
void plMouseDevice::AddCCRToCursor()
{
if (fInstance)
{
plDebugText &txt = plDebugText::Instance();
txt.DrawString(fInstance->fWXPos + 12, fInstance->fWYPos - 17, "CCR");
}
}
void plMouseDevice::AddIDNumToCursor(UInt32 idNum)
{
if (fInstance && idNum)
{
plDebugText &txt = plDebugText::Instance();
char str[256];
sprintf(str, "%d",idNum);
txt.DrawString(fInstance->fWXPos + 12 ,fInstance->fWYPos + 3,str);
}
}
void plMouseDevice::SetCursorX(hsScalar x)
{
/// Set the cursor position
if( fCursor == nil && !plMouseDevice::bCursorHidden)
CreateCursor( fCursorID );
if (fCursor)
fCursor->SetPosition( ( x * 2.0f ) - 1.0f,
( fYPos * 2.0f ) - 1.0f );
// plDebugText &txt = plDebugText::Instance();
// txt.DrawString(fWXPos + 20,fWYPos - 5,"test");
}
void plMouseDevice::SetCursorY(hsScalar y)
{
/// Set the cursor position
if( fCursor == nil && !plMouseDevice::bCursorHidden)
CreateCursor( fCursorID );
if (fCursor)
fCursor->SetPosition( ( fXPos * 2.0f ) - 1.0f,
( y * 2.0f ) - 1.0f );
// plDebugText &txt = plDebugText::Instance();
// txt.DrawString(fWXPos + 20,fWYPos - 10,"test");
}
void plMouseDevice::HideCursor(hsBool override)
{
if( fInstance->fCursor != nil )
fInstance->fCursor->SetVisible( false );
plMouseDevice::bCursorOverride = (override != 0);
plMouseDevice::bCursorHidden = true;
}
void plMouseDevice::ShowCursor(hsBool override)
{
if( !plMouseDevice::bCursorHidden )
return;
if (plMouseDevice::bCursorOverride && !override)
return;
plMouseDevice::bCursorHidden = false;
plMouseDevice::bCursorOverride = false;
if( fInstance->fCursor == nil )
fInstance->CreateCursor( fInstance->fCursorID );
fInstance->fCursor->SetVisible( true );
}
void plMouseDevice::NewCursor(char* cursor)
{
fInstance->fCursorID = cursor;
fInstance->CreateCursor(cursor);
fInstance->SetCursorX(fInstance->GetCursorX());
fInstance->SetCursorY(fInstance->GetCursorY());
if (!plMouseDevice::bCursorHidden)
fInstance->fCursor->SetVisible( true );
}
void plMouseDevice::SetCursorOpacity( hsScalar opacity )
{
fInstance->fOpacity = opacity;
if( fInstance->fCursor != nil )
fInstance->fCursor->SetOpacity( opacity );
}
hsBool plMouseDevice::MsgReceive(plMessage* msg)
{
plEvalMsg* pEMsg = plEvalMsg::ConvertNoRef(msg);
if (pEMsg)
{
if (fXMsg)
{
plgDispatch::MsgSend(fXMsg);
fXMsg = nil;
}
else
{
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
pMsg->SetXPos( fXPos );
pMsg->SetYPos( fYPos );
pMsg->SetDX(0);
pMsg->SetDY(0);
plgDispatch::MsgSend(pMsg);
}
if (fYMsg)
{
plgDispatch::MsgSend(fYMsg);
fYMsg = nil;
}
else
{
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
pMsg->SetXPos( fXPos );
pMsg->SetYPos( fYPos );
pMsg->SetDX(0);
pMsg->SetDY(0);
plgDispatch::MsgSend(pMsg);
}
if( fB2Msg )
{
fB2Msg->Send();
fB2Msg = nil;
}
// look for mouse button events in the queues to be sent now
// ...Left mouse button
if ( fLeftBMsg[0] != nil)
{
fLeftBMsg[0]->Send();
// slide queue elements over... get 'em on the next eval
fLeftBMsg[0] = fLeftBMsg[1];
fLeftBMsg[1] = nil;
}
// ...Right mouse button
if ( fRightBMsg[0] != nil)
{
fRightBMsg[0]->Send();
// slide queue elements over... get 'em on the next eval
fRightBMsg[0] = fRightBMsg[1];
fRightBMsg[1] = nil;
}
// ...middle mouse button
if ( fMiddleBMsg[0] != nil)
{
fMiddleBMsg[0]->Send();
// slide queue elements over... get 'em on the next eval
fMiddleBMsg[0] = fMiddleBMsg[1];
fMiddleBMsg[1] = nil;
}
}
plIMouseXEventMsg* pXMsg = plIMouseXEventMsg::ConvertNoRef(msg);
if (pXMsg)
{
// send a mouse event
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
if (pXMsg->fX == 999)
pMsg->SetXPos( fXPos + 0.001f );
else
if (pXMsg->fX == -999)
pMsg->SetXPos( fXPos - 0.001f );
else
pMsg->SetXPos(pXMsg->fX);
pMsg->SetYPos( fYPos );
pMsg->SetDX( ( fXPos - pMsg->GetXPos()) );
pMsg->SetDY(0);
if (pMsg->GetDX() == 0.0f && !plMouseDevice::bMsgAlways)
{
delete pMsg;
return true;
}
if (fXMsg)
delete fXMsg;
fXMsg = pMsg;
if (pXMsg->fX == 999)
fXPos += 0.01;
else
if (pXMsg->fX == -999)
fXPos -= 0.01;
else
fXPos = pXMsg->fX;
SetCursorX(fXPos);
fWXPos = pXMsg->fWx;
return true;
}
plIMouseYEventMsg* pYMsg = plIMouseYEventMsg::ConvertNoRef(msg);
if (pYMsg)
{
// send a mouse event
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
pMsg->SetXPos( fXPos );
if (pYMsg->fY == 999)
pMsg->SetYPos( fYPos + 0.01f );
else
if (pYMsg->fY == -999)
pMsg->SetYPos( fYPos - 0.01f );
else
pMsg->SetYPos(pYMsg->fY);
pMsg->SetDX(0);
pMsg->SetDY(fYPos - pMsg->GetYPos());
if (pMsg->GetDY() == 0.0f && !plMouseDevice::bMsgAlways)
{
delete pMsg;
return true;
}
if (fYMsg)
delete fYMsg;
fYMsg = pMsg;
if (pYMsg->fY == 999)
fYPos += 0.01;
else
if (pYMsg->fY == -999)
fYPos -= 0.01;
else
fYPos = pYMsg->fY;
fWYPos = pYMsg->fWy;
SetCursorY(fYPos);
return true;
}
plIMouseBEventMsg* pBMsg = plIMouseBEventMsg::ConvertNoRef(msg);
if (pBMsg)
{
// send a mouse event
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
pMsg->SetXPos( fXPos );
pMsg->SetYPos( fYPos );
pMsg->SetDX(0);
pMsg->SetDY(0);
bool deleteMe = true;
// which button is different?
if (pBMsg->fButton & kLeftButtonDown && !(fButtonState & kLeftButtonDown))
{
// left button now down
fButtonState |= kLeftButtonDown;
pMsg->SetButton( kLeftButtonDown );
deleteMe = false;
}
else
if (pBMsg->fButton & kLeftButtonUp && fButtonState & kLeftButtonDown)
{
// left button now up
fButtonState &= ~kLeftButtonDown;
pMsg->SetButton( kLeftButtonUp );
deleteMe = false;
}
else
if (pBMsg->fButton & kRightButtonDown && !(fButtonState & kRightButtonDown))
{
// right button now down
fButtonState |= kRightButtonDown;
pMsg->SetButton( kRightButtonDown );
deleteMe = false;
}
else
if (pBMsg->fButton & kRightButtonUp && fButtonState & kRightButtonDown)
{
// right button now up
fButtonState &= ~kRightButtonDown;
pMsg->SetButton( kRightButtonUp );
deleteMe = false;
}
else
if (pBMsg->fButton & kMiddleButtonDown && !(fButtonState & kMiddleButtonDown))
{
// mouse wheel button now down
fButtonState |= kMiddleButtonDown;
pMsg->SetButton( kMiddleButtonDown );
deleteMe = false;
}
else
if (pBMsg->fButton & kMiddleButtonUp && fButtonState & kMiddleButtonDown)
{
// right button now up
fButtonState &= ~kMiddleButtonDown;
pMsg->SetButton( kMiddleButtonUp );
deleteMe = false;
}
if (pBMsg->fButton & kRightButtonDblClk)
{
// right button dbl clicked, send TWO messages
plMouseEventMsg* pMsg2 = TRACKED_NEW plMouseEventMsg;
pMsg2->SetXPos( fXPos );
pMsg2->SetYPos( fYPos );
pMsg2->SetDX(0);
pMsg2->SetDY(0);
pMsg2->SetButton( kRightButtonDblClk );
if( fB2Msg != nil )
delete fB2Msg;
fB2Msg = pMsg2;
pMsg->SetButton( kRightButtonDown );
deleteMe = false;
}
else
if (pBMsg->fButton & kLeftButtonDblClk)
{
// left button dbl clicked, send TWO messages
plMouseEventMsg* pMsg2 = TRACKED_NEW plMouseEventMsg;
pMsg2->SetXPos( fXPos );
pMsg2->SetYPos( fYPos );
pMsg2->SetDX(0);
pMsg2->SetDY(0);
pMsg2->SetButton( kLeftButtonDblClk );
if( fB2Msg != nil )
delete fB2Msg;
fB2Msg = pMsg2;
pMsg->SetButton( kLeftButtonDown );
deleteMe = false;
}
if( deleteMe )
{
// mouse button state not changed
delete pMsg;
return true;
}
// we are going to save up to two button mouse events per button (left and right)
// that will be dispatched on the next eval
// which button is this for?
if ( pMsg->GetButton() == kLeftButtonDown || pMsg->GetButton() == kLeftButtonUp )
{
// see if the queue is just empty
if ( fLeftBMsg[0] == nil)
{
// nothing to think about... goes in first slot
fLeftBMsg[0] = pMsg;
}
else if (fLeftBMsg[1] == nil)
{
// nothing to think about... goes in second slot
fLeftBMsg[1] = pMsg;
}
else
{
// else queue if full... need to make some decisions
plMouseEventMsg* lastMsg = plMouseEventMsg::ConvertNoRef(pMsg);
// ...if this is an up event and [1] is a down then we need to remove both
// ...because we can't lose the up event and the down will have no match
if ( pMsg->GetButton() == kLeftButtonUp && lastMsg && lastMsg->GetButton() == kLeftButtonDown)
{
delete pMsg;
delete fLeftBMsg[1];
fLeftBMsg[1] = nil;
}
// ... otherwise ignore this event
else
{
delete pMsg;
}
}
}
else if ( pMsg->GetButton() == kRightButtonDown || pMsg->GetButton() == kRightButtonUp )
{
// see if the queue is just empty
if ( fRightBMsg[0] == nil)
{
// nothing to think about... goes in first slot
fRightBMsg[0] = pMsg;
}
else if (fRightBMsg[1] == nil)
{
// nothing to think about... goes in second slot
fRightBMsg[1] = pMsg;
}
else
{
// else queue if full... need to make some decisions
plMouseEventMsg* lastMsg = plMouseEventMsg::ConvertNoRef(pMsg);
// ...if this is an up event and [1] is a down then we need to remove both
// ...because we can't lose the up event and the down will have no match
if ( pMsg->GetButton() == kRightButtonUp && lastMsg && lastMsg->GetButton() == kRightButtonDown)
{
delete pMsg;
delete fRightBMsg[1];
fRightBMsg[1] = nil;
}
// ... otherwise ignore this event
else
{
delete pMsg;
}
}
}
else if ( pMsg->GetButton() == kMiddleButtonDown || pMsg->GetButton() == kMiddleButtonUp )
{
// see if the queue is just empty
if ( fMiddleBMsg[0] == nil)
{
// nothing to think about... goes in first slot
fMiddleBMsg[0] = pMsg;
}
else if (fMiddleBMsg[1] == nil)
{
// nothing to think about... goes in second slot
fMiddleBMsg[1] = pMsg;
}
else
{
// else queue if full... need to make some decisions
plMouseEventMsg* lastMsg = plMouseEventMsg::ConvertNoRef(pMsg);
// ...if this is an up event and [1] is a down then we need to remove both
// ...because we can't lose the up event and the down will have no match
if ( pMsg->GetButton() == kMiddleButtonUp && lastMsg && lastMsg->GetButton() == kMiddleButtonDown)
{
delete pMsg;
delete fMiddleBMsg[1];
fMiddleBMsg[1] = nil;
}
// ... otherwise ignore this event
else
{
delete pMsg;
}
}
}
// we are going to dispatch the mouse button events right away
// and not wait for the next eval, because we shouldn't miss one of these
return true;
}
return false;
}

View File

@ -0,0 +1,241 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// plInputDevice.h
#ifndef PL_INPUT_DEVICE_H
#define PL_INPUT_DEVICE_H
#include "HeadSpin.h"
#include "hsWindows.h"
//#include "../pnInputCore/plControlDefinition.h"
#include "../pnInputCore/plOSMsg.h"
#include "hsBitVector.h"
#include "hsTemplates.h"
class plMessage;
enum plKeyDef;
struct plMouseInfo;
class plPipeline;
class plInputDevice
{
public:
enum Flags
{
kDisabled = 0x1
};
protected:
UInt32 fFlags;
public:
plInputDevice() {;}
virtual ~plInputDevice() {;}
virtual const char* GetInputName() = 0;
UInt32 GetFlags() { return fFlags; }
void SetFlags(UInt32 f) { fFlags = f; }
virtual void HandleKeyEvent(plOSMsg message, plKeyDef key, bool bKeyDown, hsBool bKeyRepeat) {;}
virtual void HandleMouseEvent(plOSMsg message, plMouseState state) {;}
virtual void HandleWindowActivate(bool bActive, HWND hWnd) {;}
virtual hsBool MsgReceive(plMessage* msg) {return false;}
virtual void Shutdown() {;}
};
class plKeyEventMsg;
class plKeyboardDevice : public plInputDevice
{
hsBool fAltKeyDown;
hsBool fShiftKeyDown;
hsBool fCtrlKeyDown;
hsBool fCapsLockKeyDown;
int fControlMode;
hsBool fCapsLockLock;
static bool fKeyboardState[256]; // virtual key code is the index, bool is whether it is down or not
static hsBool fIgnoreCapsLock; // set if we want it to ignore this key when translating characters (i.e. for chatting)
static hsBool fKeyIsDeadKey; // the key we just got was a dead key, store the value if you're a text input object
static plKeyboardDevice* fInstance;
void InitKeyboardMaps();
void InitKeyboardState();
void ReleaseAllKeys();
public:
enum
{
CONSOLE_MODE = 0,
CONSOLE_FULL,
STANDARD_MODE,
};
plKeyboardDevice();
~plKeyboardDevice();
void SetControlMode(int i) { fControlMode = i; }
const char* GetInputName() { return "keyboard"; }
void HandleKeyEvent(plOSMsg message, plKeyDef key, bool bKeyDown, hsBool bKeyRepeat);
virtual void HandleWindowActivate(bool bActive, HWND hWnd);
virtual hsBool IsCapsLockKeyOn();
virtual void Shutdown();
#if HS_BUILD_FOR_WIN32
void ForceNumLock(hsBool on);
#endif
static hsBool IgnoreCapsLock() { return fIgnoreCapsLock; }
static void IgnoreCapsLock(hsBool ignore) { fIgnoreCapsLock = ignore; }
static hsBool KeyIsDeadKey() { return fKeyIsDeadKey; }
static plKeyboardDevice* GetInstance() { return fInstance; }
static char KeyEventToChar( plKeyEventMsg *msg );
protected:
hsBool fStartedUpWithNumLockOn; // maintaining a separate flag since apparently the other one can get confused
hsBool fPrevNumLockOn;
};
class plPlate;
#define CURSOR_UP "cursor_up.png"
#define CURSOR_UPWARD "cursor_upward.png"
#define CURSOR_DOWN "cursor_down.png"
#define CURSOR_RIGHT "cursor_right.png"
#define CURSOR_LEFT "cursor_left.png"
#define CURSOR_OPEN "cursor_open.png"
#define CURSOR_GRAB "cursor_grab.png"
#define CURSOR_CLICKED "cursor_clicked.png"
#define CURSOR_POISED "cursor_poised.png"
#define CURSOR_4WAY_OPEN "cursor_4way_open.png"
#define CURSOR_4WAY_CLOSED "cursor_4way_closed.png"
#define CURSOR_UPDOWN_OPEN "cursor_updown_open.png"
#define CURSOR_UPDOWN_CLOSED "cursor_updown_closed.png"
#define CURSOR_LEFTRIGHT_OPEN "cursor_leftright_open.png"
#define CURSOR_LEFTRIGHT_CLOSED "cursor_leftright_closed.png"
#define CURSOR_OFFER_BOOK "cursor_book.png"
#define CURSOR_OFFER_BOOK_HI "cursor_book_poised.png"
#define CURSOR_OFFER_BOOK_CLICKED "cursor_book_clicked.png"
#define CURSOR_CLICK_DISABLED "cursor_disabled.png"
#define CURSOR_HAND "cursor_up.png"
#define CURSOR_ARROW "cursor_up.png"
class plInputEventMsg;
class plMouseDevice : public plInputDevice
{
public:
plMouseDevice();
~plMouseDevice();
const char* GetInputName() { return "mouse"; }
hsBool HasControlFlag(int f) const { return fControlFlags.IsBitSet(f); }
void SetControlFlag(int f)
{
fControlFlags.SetBit(f);
}
void ClearControlFlag(int which) { fControlFlags.ClearBit( which ); }
void SetCursorX(hsScalar x);
void SetCursorY(hsScalar y);
hsScalar GetCursorX() { return fXPos; }
hsScalar GetCursorY() { return fYPos; }
UInt32 GetButtonState() { return fButtonState; }
hsScalar GetCursorOpacity() { return fOpacity; }
void SetDisplayResolution(hsScalar Width, hsScalar Height);
virtual hsBool MsgReceive(plMessage* msg);
static plMouseDevice* Instance() { return plMouseDevice::fInstance; }
static void SetMsgAlways(bool b) { plMouseDevice::bMsgAlways = b; }
static void ShowCursor(hsBool override = false);
static void NewCursor(char* cursor);
static void HideCursor(hsBool override = false);
static bool GetHideCursor() { return plMouseDevice::bCursorHidden; }
static void SetCursorOpacity( hsScalar opacity = 1.f );
static bool GetInverted() { return plMouseDevice::bInverted; }
static void SetInverted(bool inverted) { plMouseDevice::bInverted = inverted; }
static void AddNameToCursor(const char* name);
static void AddIDNumToCursor(UInt32 idNum);
static void AddCCRToCursor();
protected:
plInputEventMsg* fXMsg;
plInputEventMsg* fYMsg;
plInputEventMsg* fB2Msg;
// mouse button event queues (only hold 2)
plInputEventMsg* fLeftBMsg[2];
plInputEventMsg* fRightBMsg[2];
plInputEventMsg* fMiddleBMsg[2];
hsScalar fXPos;
hsScalar fYPos;
int fWXPos; // the windows coordinates of the cursor
int fWYPos;
UInt32 fButtonState;
hsScalar fOpacity;
hsBitVector fControlFlags;
plPlate *fCursor;
char* fCursorID;
static plMouseDevice* fInstance;
static plMouseInfo fDefaultMouseControlMap[];
void CreateCursor( char* cursor );
void IUpdateCursorSize();
static bool bMsgAlways;
static bool bCursorHidden;
static bool bCursorOverride;
static bool bInverted;
static hsScalar fWidth, fHeight;
};
#endif // PL_INPUT_DEVICE_H

View File

@ -0,0 +1,305 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInputInterface.cpp - A single layer on the input interface stack //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 2.20.02 mcn - Created. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsConfig.h"
#include "hsWindows.h"
#include "hsTypes.h"
#include "plInputInterface.h"
#include "plInputInterfaceMgr.h"
#include "../pnInputCore/plKeyMap.h"
#include "../plMessage/plInputEventMsg.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
//// Constructor/Destructor //////////////////////////////////////////////////
plInputInterface::plInputInterface()
{
fEnabled = false;
fControlMap = TRACKED_NEW plKeyMap;
}
plInputInterface::~plInputInterface()
{
delete fControlMap;
}
void plInputInterface::ClearKeyMap()
{
if( fControlMap != nil )
fControlMap->ClearAll();
}
//// Read/Write //////////////////////////////////////////////////////////////
void plInputInterface::Read( hsStream* s, hsResMgr* mgr )
{
}
void plInputInterface::Write( hsStream* s, hsResMgr* mgr )
{
}
//// Helper Functions ////////////////////////////////////////////////////////
hsBool plInputInterface::IOwnsControlCode( ControlEventCode code )
{
if( fControlMap->FindBinding( code ) != nil )
return true;
return false;
}
//// IVerifyShiftKey /////////////////////////////////////////////////////////
// special logic so the shift key can make everyone totally happy...
hsBool plInputInterface::IVerifyShiftKey( plKeyDef key, int index )
{
// if we are mapped to the actual shift key, return true
if (key == KEY_SHIFT)
return true;
// if anything else is mapped to this key + shift, return false
/* for (int i=0; i < fControlMap->GetNumBindings(); i++)
{
if (index == i)
continue;
if (fKeyMap->fMap[i]->fKeyDef == key && fKeyMap->fMap[i]->fKeyFlags & plKeyInfo::kKeyShift )
return false;
}
*/ return true;
}
void plInputInterface::IDeactivateBinding(const plKeyBinding *binding)
{
if( !(binding->GetCodeFlags() & kControlFlagNoDeactivate) && !(binding->GetCodeFlags() & kControlFlagToggle) )
{
plCtrlCmd *pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fControlCode = binding->GetCode();
pCmd->fControlActivated = false;
pCmd->SetCmdString( binding->GetExtendedString() );
pCmd->fNetPropagateToPlayers = ( binding->GetCodeFlags() & kControlFlagNetPropagate ) ? true : false;
fMessageQueue->Append( pCmd );
}
IClearKeyControlFlag(binding->GetCode());
}
//// ProcessKeyBindings //////////////////////////////////////////////////////
// Processes the given key event as a key binding, if one exists. If not,
// returns false.
hsBool plInputInterface::ProcessKeyBindings( plInputEventMsg *msg )
{
int i;
hsBool activate;
plKeyEventMsg *keyMsg = plKeyEventMsg::ConvertNoRef( msg );
if( keyMsg == nil )
return false;
/// We might have controls that are currently enabled that are triggered in part by
/// modifiers (ctrl or shift)...if that is true, then we want to disable them if either
/// of those modifiers are up, no matter what key this message is for
hsTArray<Int16> enabledCtrls;
fKeyControlFlags.Enumerate( enabledCtrls );
for( i = 0; i < enabledCtrls.GetCount(); i++ )
{
const plKeyBinding *binding = fControlMap->FindBinding( (ControlEventCode)enabledCtrls[ i ] );
if( binding == nil )
; // Somehow we lost the binding??
else
{
bool wantShift, wantCtrl;
if( fKeyControlsFrom2ndKeyFlags.IsBitSet( enabledCtrls[ i ] ) )
{
wantShift = ( binding->GetKey2().fFlags & plKeyCombo::kShift ) || ( binding->GetKey2().fKey == KEY_SHIFT );
wantCtrl = ( binding->GetKey2().fFlags & plKeyCombo::kCtrl ) || ( binding->GetKey2().fKey == KEY_CTRL );
}
else
{
wantShift = ( binding->GetKey1().fFlags & plKeyCombo::kShift ) || ( binding->GetKey1().fKey == KEY_SHIFT );
wantCtrl = ( binding->GetKey1().fFlags & plKeyCombo::kCtrl ) || ( binding->GetKey1().fKey == KEY_CTRL );
}
if( ( wantShift && !keyMsg->GetShiftKeyDown() ) || ( wantCtrl && !keyMsg->GetCtrlKeyDown() ) )
{
IDeactivateBinding(binding);
fKeyControlsFrom2ndKeyFlags.SetBit(enabledCtrls[i], false);
}
}
}
/// Process any binding for this message's key code now
plKeyCombo combo( keyMsg->GetKeyCode(), ( keyMsg->GetShiftKeyDown() ? plKeyCombo::kShift : 0 ) |
( keyMsg->GetCtrlKeyDown() ? plKeyCombo::kCtrl : 0 ) );
hsTArray<const plKeyBinding *> bindings;
fControlMap->FindAllBindingsByKey(combo, bindings);
// The first binding is the one we want. (FindAllBindingsByKey guarantees this)
const plKeyBinding *binding = (bindings.GetCount() ? bindings[0] : nil);
// If other bindings were found, they lose out to the first one.
for (i = 1; i < bindings.GetCount(); i++)
IDeactivateBinding(bindings[i]);
/*
const plKeyBinding *binding = fControlMap->FindBindingByKey( combo );
if( binding == nil )
{
// Don't panic just yet, there are some special cases with the shift key to check first
if( keyMsg->GetKeyCode() == KEY_SHIFT || keyMsg->GetShiftKeyDown() )
{
// See, there are two other cases to consider: 1) we have a binding directly to the shift
// key, which wouldn't have the shift flag set (so the above search wouldn't have caught it).
// The second case would be if we have a matching binding without shift...
// which is VALID so long as no other bindings respond to this key combo + shift, but of course,
// if there were, we'd have found them already!
// Either way, we remove the shift flag and try again
combo.fFlags &= ~plKeyCombo::kShift;
binding = fControlMap->FindBindingByKey( combo );
}
}
*/
if (!binding)
return false;
UInt32 codeFlags = binding->GetCodeFlags();
// Filter out no-repeat messages
if( ( codeFlags & kControlFlagNoRepeat ) && keyMsg->GetRepeat() )
return false;
if( codeFlags & kControlFlagNormal )
{
// "Normal" behavior--enable on key down, disable on key up
activate = keyMsg->GetKeyDown() ? true : false;
}
else if( codeFlags & kControlFlagToggle )
{
// Toggle behavior
if( ( codeFlags & kControlFlagDownEvent ) && !keyMsg->GetKeyDown() )
return false;
if( ( codeFlags & kControlFlagUpEvent ) && keyMsg->GetKeyDown() )
return false;
if( IHasKeyControlFlag( binding->GetCode() ) )
activate = false;
else
activate = true;
}
else
{
// Remaining ones are triggered to activate on their flagged event and
// deactivate when that turns false
if( ( codeFlags & kControlFlagDownEvent ) && !keyMsg->GetKeyDown() )
activate = false;
else if( ( codeFlags & kControlFlagUpEvent ) && keyMsg->GetKeyDown() )
activate = false;
else
activate = true;
}
hsBool wasActive = IHasKeyControlFlag(binding->GetCode());
// Set or clear our flags, since we do that even if we don't send a message
if( activate )
{
ISetKeyControlFlag( binding->GetCode() );
fKeyControlsFrom2ndKeyFlags.SetBit( binding->GetCode(), ( binding->GetKey2() == combo ) ? true : false );
}
else
{
IClearKeyControlFlag( binding->GetCode() );
fKeyControlsFrom2ndKeyFlags.SetBit( binding->GetCode(), 0 );
}
// Filter out codes that only want their activate messages sent (like console commands)
if( ( codeFlags & kControlFlagNoDeactivate ) && !activate )
return false;
if (!IControlCodeEnabled(binding->GetCode()))
{
if (activate || (codeFlags & kControlFlagToggle) || !wasActive)
{
// It's ok to deactivate a disabled control, but not activate it
return false;
}
}
/// OK, generate the message to send
plCtrlCmd *pCmd = TRACKED_NEW plCtrlCmd( this );
pCmd->fControlCode = binding->GetCode();
pCmd->fControlActivated = activate;
pCmd->SetCmdString( binding->GetExtendedString() );
pCmd->fNetPropagateToPlayers = ( codeFlags & kControlFlagNetPropagate ) ? true : false;
fMessageQueue->Append( pCmd );
return true;
}
hsBool plInputInterface::IControlCodeEnabled(ControlEventCode code )
{
return (!fDisabledControls.IsBitSet(code));
}

View File

@ -0,0 +1,222 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInputInterface.cpp - A single layer on the input interface stack //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 2.20.02 mcn - Created. //
// //
//// Note on GetPriorityLevel() //////////////////////////////////////////////
// //
// The inputInterfaceMgr uses GetPriorityLevel() to place each interface //
// into the stack relative to the other interfaces. Current priority //
// levels are: //
// Console - 100 //
// GUI system - 75 //
// Avatar input - 50 //
// Scene interaction - 25 //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plInputInterface_h
#define _plInputInterface_h
#include "hsRefCnt.h"
#include "hsTemplates.h"
#include "hsBitVector.h"
// Needed for UNIX Build
// only windows will let you predeclare an enum
#include "../../NucleusLib/pnInputCore/plKeyDef.h"
#include "../../NucleusLib/pnInputCore/plControlEventCodes.h"
//// Class Definition ////////////////////////////////////////////////////////
class hsStream;
class hsResMgr;
class plInputEventMsg;
class plInputInterfaceMgr;
class plMessage;
class plKeyMap;
class plCtrlCmd;
class plKeyBinding;
class plInputInterface : public hsRefCnt
{
friend class plInputInterfaceMgr;
protected:
enum Priorities
{
kConsolePriority = 100,
kGUISystemPriority = 75,
kDebugCmdPrioity = 60,
kSceneInteractionPriority = 50,
kTelescopeInputPriority = 26,
kAvatarInputPriority = 25,
};
plInputInterfaceMgr *fManager;
plKeyMap *fControlMap;
hsTArray<plCtrlCmd *> *fMessageQueue;
hsBitVector fKeyControlFlags;
hsBitVector fKeyControlsFrom2ndKeyFlags;
hsBitVector fDisabledControls;
hsBool fEnabled;
void ISetMessageQueue( hsTArray<plCtrlCmd *> *queue ) { fMessageQueue = queue; }
plKeyMap *IGetControlMap( void ) const { return fControlMap; }
hsBool IOwnsControlCode( ControlEventCode code );
hsBool IVerifyShiftKey( plKeyDef key, int index );
hsBool IHasKeyControlFlag(int f) const { return fKeyControlFlags.IsBitSet(f); }
void ISetKeyControlFlag(int f) { fKeyControlFlags.SetBit(f); }
void IClearKeyControlFlag(int which) { fKeyControlFlags.ClearBit( which ); }
void IDisableControl(int which) { fDisabledControls.SetBit(which); }
void IEnableControl(int which) { fDisabledControls.ClearBit(which); }
// The binding lost focus/priority. Behave as though they released the key and send
// a deactivate message for the control code.
void IDeactivateBinding(const plKeyBinding *binding);
// Gets called once per IUpdate(), just like normal IEval()s
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ) { return false; }
// Override to handle special-cased control messages of your own (same as receiving them via a message, but if you process them, nobody else gets them). Return false if you don't handle it.
virtual hsBool IHandleCtrlCmd( plCtrlCmd *cmd ) { return false; }
// Override to let the input interfaces control when a binding is truly active. If this function returns false,
// ProcessKeyBindings will ignore the keypress for the given control. This way, the interfaces can be selective
// about which bindings are active when. By default, always returns true, since there are very few and rare
// cases where you'd want to return false
virtual hsBool IControlCodeEnabled( ControlEventCode code );
// Some helpers for derived classes to avoid including the manager unnecessariliy
public:
plInputInterface();
virtual ~plInputInterface();
enum Cursors
{
kNullCursor = 0,
kCursorUp,
kCursorLeft,
kCursorRight,
kCursorDown,
kCursorPoised,
kCursorClicked,
kCursorUnClicked,
kCursorHidden,
kCursorOpen,
kCursorGrab,
kCursorArrow,
kCursor4WayDraggable,
kCursor4WayDragging,
kCursorUpDownDraggable,
kCursorUpDownDragging,
kCursorLeftRightDraggable,
kCursorLeftRightDragging,
kCursorOfferBook,
kCursorOfferBookHilite,
kCursorOfferBookClicked,
kCursorClickDisabled,
kCursorHand,
kCursorUpward,
};
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
// Returns the priority of this interface layer, based on the Priorities enum
virtual UInt32 GetPriorityLevel( void ) const = 0;
// Returns true if the message was handled, false if not and we want to pass it on to others in the stack
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg ) = 0;
// Returns the currently active mouse cursor for this layer, as defined in pnMessage/plCursorChangeMsg.h
virtual UInt32 GetCurrentCursorID( void ) const = 0;
// Returns the current opacity that this layer wants the cursor to be, from 0 (xparent) to 1 (opaque)
virtual hsScalar GetCurrentCursorOpacity( void ) const { return 1.f; }
// Returns true if this layer is wanting to change the mouse, false if it isn't interested
virtual hsBool HasInterestingCursorID( void ) const = 0;
// Gets called by the manager. If you want a message to come to you, set your manager as the destination
virtual hsBool MsgReceive( plMessage *msg ) { return false; }
// Any initialization that requires a pointer to the manager needs to be done on Init()/Shutdown()
virtual void Init( plInputInterfaceMgr *manager ) { fManager = manager; RestoreDefaultKeyMappings(); }
virtual void Shutdown( void ) {}
// Gets called when any of the key mappings are changed, so that the interface layer can refresh the ones its interested in
virtual void RefreshKeyMap( void ) {}
// Called when the interface manager is setting all key mappings to default
virtual void RestoreDefaultKeyMappings( void ) {}
// Called on each interface layer that gets missed when processing inputEvents in the manager (i.e. you either get this call or InterpretInputEvent)
virtual void MissedInputEvent( plInputEventMsg *pMsg ) {}
// Non-virtual, can't override--processes an inputEventMsg to see if we can handle it via a key binding (if so, InterpretInputEvent won't be called)
hsBool ProcessKeyBindings( plInputEventMsg *keyMsg );
void SetEnabled( hsBool e ) { fEnabled = e; }
hsBool IsEnabled( void ) const { return fEnabled; }
// clear all keys from map
virtual void ClearKeyMap();
// reset clickable state
virtual void ResetClickableState() {;}
};
#endif // _plInputInterface_h

View File

@ -0,0 +1,963 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInputInterfaceMgr.cpp - The manager of all input interface layers //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 2.20.02 mcn - Created. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsConfig.h"
#include "hsWindows.h"
#include "hsTypes.h"
#include "plInputInterfaceMgr.h"
#include "plInputInterface.h"
#include "plInputDevice.h" // For mouse device stuff
#include "../pnInputCore/plKeyMap.h"
#include "../plMessage/plInputEventMsg.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
#include "../pnMessage/plClientMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnMessage/plCmdIfaceModMsg.h"
#include "../pnMessage/plPlayerPageMsg.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../pnNetCommon/plNetApp.h"
#include "../plNetClient/plNetClientMgr.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
#include "plProfile.h"
#include "../plResMgr/plLocalization.h"
plProfile_CreateTimer("Input", "Update", Input);
//// plCtrlCmd ///////////////////////////////////////////////////////////////
void plCtrlCmd::Write(hsStream* stream, hsResMgr* mgr)
{
stream->WriteSwap32( fControlCode );
stream->WriteBool( fControlActivated );
fPt.Write(stream);
// write cmd/string
plMsgCStringHelper::Poke(fCmd, stream);
}
void plCtrlCmd::Read(hsStream* stream, hsResMgr* mgr)
{
fControlCode = (ControlEventCode)stream->ReadSwap32();
fControlActivated = stream->ReadBool();
fPt.Read(stream);
// read cmd/string
plMsgCStringHelper::Peek(fCmd, stream);
}
//// plDefaultKeyCatcher /////////////////////////////////////////////////////
plDefaultKeyCatcher::~plDefaultKeyCatcher()
{
if( plInputInterfaceMgr::GetInstance() != nil )
plInputInterfaceMgr::GetInstance()->SetDefaultKeyCatcher( nil );
}
//// Statics /////////////////////////////////////////////////////////////////
plInputInterfaceMgr *plInputInterfaceMgr::fInstance = nil;
//// Constructor/Destructor //////////////////////////////////////////////////
plInputInterfaceMgr::plInputInterfaceMgr()
{
fClickEnabled = false;
fCurrentCursor = -1;
fCursorOpacity = 1.f;
fForceCursorHidden = false;
fForceCursorHiddenCount = 0;
InitDefaultKeyMap();
#if 0
// make sure we don't miss control keys on remote players
SetSynchFlagsBit(plSynchedObject::kSendReliably);
#endif
hsAssert( fInstance == nil, "Attempting to create two input interface managers!" );
fInstance = this;
fCurrentFocus = nil;
fDefaultCatcher = nil;
}
plInputInterfaceMgr::~plInputInterfaceMgr()
{
Shutdown();
fInstance = nil;
}
//// Init ////////////////////////////////////////////////////////////////////
#include "plAvatarInputInterface.h"
#include "plSceneInputInterface.h"
#include "plDebugInputInterface.h"
#include "plTelescopeInputInterface.h"
void plInputInterfaceMgr::Init( void )
{
RegisterAs( kInputInterfaceMgr_KEY );
plgDispatch::Dispatch()->RegisterForType( plInputIfaceMgrMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForType( plInputEventMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForType( plEvalMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForExactType( plPlayerPageMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForExactType( plCmdIfaceModMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForExactType( plClientMsg::Index(), GetKey() );
/// Hacks (?) for now
plAvatarInputInterface *avatar = TRACKED_NEW plAvatarInputInterface();
IAddInterface( avatar );
hsRefCnt_SafeUnRef( avatar );
plSceneInputInterface *scene = TRACKED_NEW plSceneInputInterface();
IAddInterface( scene );
hsRefCnt_SafeUnRef( scene );
plDebugInputInterface *camDrive = TRACKED_NEW plDebugInputInterface();
IAddInterface( camDrive );
hsRefCnt_SafeUnRef( camDrive );
}
//// Shutdown ////////////////////////////////////////////////////////////////
void plInputInterfaceMgr::Shutdown( void )
{
int i;
// WriteKeyMap();
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
fInterfaces[ i ]->Shutdown();
hsRefCnt_SafeUnRef( fInterfaces[ i ] );
}
fInterfaces.Reset();
for( i = 0; i < fMessageQueue.GetCount(); i++ )
delete fMessageQueue[ i ];
fMessageQueue.Reset();
plgDispatch::Dispatch()->UnRegisterForType( plInputIfaceMgrMsg::Index(), GetKey() );
plgDispatch::Dispatch()->UnRegisterForType( plInputEventMsg::Index(), GetKey() );
plgDispatch::Dispatch()->UnRegisterForType( plEvalMsg::Index(), GetKey() );
plgDispatch::Dispatch()->UnRegisterForExactType( plPlayerPageMsg::Index(), GetKey() );
plgDispatch::Dispatch()->UnRegisterForExactType( plCmdIfaceModMsg::Index(), GetKey() );
plgDispatch::Dispatch()->UnRegisterForExactType( plClientMsg::Index(), GetKey() );
UnRegisterAs( kInputInterfaceMgr_KEY );
}
//// IAdd/RemoveInterface ////////////////////////////////////////////////////
// Each interface has a "priority level", i.e. where in the list it should be.
// Doing it this way allows us to keep the manager unaware of the number or
// types of interfaces.
void plInputInterfaceMgr::IAddInterface( plInputInterface *iface )
{
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
if( fInterfaces[ i ]->GetPriorityLevel() < iface->GetPriorityLevel() )
break;
}
fInterfaces.Insert( i, iface );
hsRefCnt_SafeRef( iface );
iface->Init( this );
iface->ISetMessageQueue( &fMessageQueue );
}
void plInputInterfaceMgr::IRemoveInterface( plInputInterface *iface )
{
int idx = fInterfaces.Find( iface );
if( idx != fInterfaces.kMissingIndex )
{
fInterfaces[ idx ]->Shutdown();
hsRefCnt_SafeUnRef( fInterfaces[ idx ] );
fInterfaces.Remove( idx );
}
}
/// reset clickable state //////////////////////////////////////////////////////////////////////////
void plInputInterfaceMgr::ResetClickableState()
{
// look for the scene input interface
for(int i = 0; i < fInterfaces.GetCount(); i++ )
fInterfaces[i]->ResetClickableState();
}
//// IUpdateCursor ///////////////////////////////////////////////////////////
void plInputInterfaceMgr::IUpdateCursor( Int32 newCursor )
{
char* mouseCursorResID;
fCurrentCursor = newCursor;
if( fCurrentCursor == plInputInterface::kCursorHidden )
plMouseDevice::HideCursor();
else
{
plMouseDevice::ShowCursor();
switch( fCurrentCursor )
{
case plInputInterface::kCursorUp: mouseCursorResID = CURSOR_UP; break;
case plInputInterface::kCursorLeft: mouseCursorResID = CURSOR_LEFT; break;
case plInputInterface::kCursorRight: mouseCursorResID = CURSOR_RIGHT; break;
case plInputInterface::kCursorDown: mouseCursorResID = CURSOR_DOWN; break;
case plInputInterface::kCursorPoised: mouseCursorResID = CURSOR_POISED; break;
case plInputInterface::kCursorClicked: mouseCursorResID = CURSOR_CLICKED; break;
case plInputInterface::kCursorUnClicked: mouseCursorResID = CURSOR_POISED; break;
case plInputInterface::kCursorOpen: mouseCursorResID = CURSOR_OPEN; break;
case plInputInterface::kCursorGrab: mouseCursorResID = CURSOR_GRAB; break;
case plInputInterface::kCursorArrow: mouseCursorResID = CURSOR_ARROW; break;
case plInputInterface::kCursor4WayDraggable: mouseCursorResID = CURSOR_4WAY_OPEN; break;
case plInputInterface::kCursor4WayDragging: mouseCursorResID = CURSOR_4WAY_CLOSED; break;
case plInputInterface::kCursorUpDownDraggable: mouseCursorResID = CURSOR_UPDOWN_OPEN; break;
case plInputInterface::kCursorUpDownDragging: mouseCursorResID = CURSOR_UPDOWN_CLOSED; break;
case plInputInterface::kCursorLeftRightDraggable: mouseCursorResID = CURSOR_LEFTRIGHT_OPEN; break;
case plInputInterface::kCursorLeftRightDragging: mouseCursorResID = CURSOR_LEFTRIGHT_CLOSED; break;
case plInputInterface::kCursorOfferBook: mouseCursorResID = CURSOR_OFFER_BOOK; break;
case plInputInterface::kCursorOfferBookHilite: mouseCursorResID = CURSOR_OFFER_BOOK_HI; break;
case plInputInterface::kCursorOfferBookClicked: mouseCursorResID = CURSOR_OFFER_BOOK_CLICKED; break;
case plInputInterface::kCursorClickDisabled: mouseCursorResID = CURSOR_CLICK_DISABLED; break;
case plInputInterface::kCursorHand: mouseCursorResID = CURSOR_HAND; break;
case plInputInterface::kCursorUpward: mouseCursorResID = CURSOR_UPWARD; break;
default: mouseCursorResID = CURSOR_OPEN; break;
}
plMouseDevice::NewCursor( mouseCursorResID );
}
}
//// IEval ///////////////////////////////////////////////////////////////////
// Inherited from plSingleModifier, gets called once per IUpdate() loop.
hsBool plInputInterfaceMgr::IEval( double secs, hsScalar del, UInt32 dirty )
{
const char *inputEval = "Eval";
plProfile_BeginLap(Input, inputEval);
int i;
// Let all our layers eval
for( i = 0; i < fInterfaces.GetCount(); i++ )
fInterfaces[ i ]->IEval( secs, del, dirty );
// Handle our message queue now
for( i = 0; i < fMessageQueue.Count(); i++ )
{
// Can its layer handle it?
if( !fMessageQueue[ i ]->GetSource()->IHandleCtrlCmd( fMessageQueue[ i ] ) )
{
// Nope, just dispatch it like normal
plControlEventMsg* pMsg = TRACKED_NEW plControlEventMsg;
for (int j = 0; j < fReceivers.Count(); j++)
pMsg->AddReceiver( fReceivers[ j ] );
pMsg->SetControlActivated( fMessageQueue[i]->fControlActivated );
pMsg->SetControlCode( fMessageQueue[i]->fControlCode );
pMsg->SetControlPct(fMessageQueue[i]->fPct);
pMsg->SetTurnToPt( fMessageQueue[i]->fPt );
pMsg->SetCmdString(fMessageQueue[i]->GetCmdString());
pMsg->SetSender( GetKey() );
plgDispatch::MsgSend( pMsg );
///////////////////////////////////////////////////////
// send same msg over network to players
///////////////////////////////////////////////////////
if (fMessageQueue[i]->fNetPropagateToPlayers)
{
pMsg = TRACKED_NEW plControlEventMsg;
for (int j = 0; j < fReceivers.Count(); j++)
if (fReceivers[j] == plNetClientApp::GetInstance()->GetLocalPlayerKey())
pMsg->AddReceiver( fReceivers[j] );
if (pMsg->GetNumReceivers())
{
pMsg->SetControlActivated( fMessageQueue[i]->fControlActivated );
pMsg->SetControlCode( fMessageQueue[i]->fControlCode );
pMsg->SetControlPct(fMessageQueue[i]->fPct);
pMsg->SetTurnToPt( fMessageQueue[i]->fPt );
pMsg->SetCmdString(fMessageQueue[i]->GetCmdString());
pMsg->SetSender( GetKey() );
pMsg->SetBCastFlag(plMessage::kNetPropagate | plMessage::kPropagateToModifiers |
plMessage::kNetUseRelevanceRegions); // bcast only to other players who care about the region I'm in
pMsg->SetBCastFlag(plMessage::kLocalPropagate, false);
plgDispatch::MsgSend( pMsg );
}
else
delete pMsg;
}
}
}
// Clear the message queue
for( i = 0; i < fMessageQueue.Count(); i++ )
delete fMessageQueue[ i ];
fMessageQueue.SetCount( 0 );
plProfile_EndLap(Input, inputEval);
return true;
}
void plInputInterfaceMgr::ForceCursorHidden( hsBool requestedState )
{
if ( requestedState )
{
fForceCursorHiddenCount++;
fForceCursorHidden = requestedState;
}
else
{
fForceCursorHiddenCount--;
// this happens way too often to leave in
// hsAssert(fForceCursorHiddenCount>=0,"ForceCursorHidded: unhiding more times than hidden" );
#define OnlyHideCursorOnLast
#ifdef OnlyHideCursorOnLast
// is this is the last person... then really unforce hidding the mouse cursor
if ( fForceCursorHiddenCount <= 0 )
{
#endif //OnlyHideCursorOnLast
fForceCursorHidden = requestedState;
fForceCursorHiddenCount = 0;
#ifdef OnlyHideCursorOnLast
}
#endif //OnlyHideCursorOnLast
}
}
hsBool plInputInterfaceMgr::ICheckCursor(plInputInterface *iFace)
{
if( iFace->IsEnabled() && iFace->HasInterestingCursorID() )
{
if( iFace->GetCurrentCursorID() != fCurrentCursor )
IUpdateCursor( iFace->GetCurrentCursorID() );
if( iFace->GetCurrentCursorOpacity() != fCursorOpacity )
{
fCursorOpacity = iFace->GetCurrentCursorOpacity();
plMouseDevice::SetCursorOpacity( fCursorOpacity );
}
return true;
}
return false;
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool plInputInterfaceMgr::MsgReceive( plMessage *msg )
{
int i;
plEvalMsg *pEvalMsg = plEvalMsg::ConvertNoRef( msg );
if( pEvalMsg )
{
IEval( pEvalMsg->GetTimeStamp(), pEvalMsg->DelSeconds(), false );
return true;
}
plInputEventMsg *ieMsg = plInputEventMsg::ConvertNoRef( msg );
if( ieMsg != nil )
{
const char *inputIEM = "InputEventMsg";
plProfile_BeginLap(Input, inputIEM);
hsBool handled = false;
UInt32 missedInputStartIdx = 0;
plInputInterface *oldCurrentFocus = fCurrentFocus;
// Current focus (if there is one) gets first crack
if( fCurrentFocus )
{
if( fCurrentFocus->IsEnabled() )
{
handled = (fCurrentFocus->ProcessKeyBindings(ieMsg) || fCurrentFocus->InterpretInputEvent(ieMsg));
}
}
if (!handled)
{
// Walk our stack
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
if( fInterfaces[ i ]->IsEnabled() && fInterfaces[ i ] != oldCurrentFocus)
{
// Try the key bindings first (common for all layers)
if( fInterfaces[ i ]->ProcessKeyBindings( ieMsg ) || fInterfaces[ i ]->InterpretInputEvent( ieMsg ))
{
handled = true;
break;
}
}
}
if( !handled )
{
// Fell all the way through the stack...must've been a very uninteresting message...
if( plKeyEventMsg::ConvertNoRef( ieMsg ) && fDefaultCatcher != nil )
{
// But somebody loves those keys :)
fDefaultCatcher->HandleKeyEvent( plKeyEventMsg::ConvertNoRef( ieMsg ) );
}
}
missedInputStartIdx = i + 1;
}
// Notify the rest of the interfaces in the stack that they missed the event ("lost focus", as it were)
for (i = missedInputStartIdx; i < fInterfaces.GetCount(); i++)
if (fInterfaces[i] != oldCurrentFocus)
fInterfaces[i]->MissedInputEvent(ieMsg);
// Now we re-walk to see who's the new interested party. Note that we have to re-walk
// because a key down may have changed some layer's interest in the cursor
if( !fForceCursorHidden )
{
hsBool cursorHandled = false;
if (fCurrentFocus)
cursorHandled = ICheckCursor(fCurrentFocus);
if (!cursorHandled)
{
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
if (ICheckCursor(fInterfaces[i]))
{
cursorHandled = true;
break;
}
}
if (!cursorHandled)
{
// NOBODY is interested in the mouse, so set to our default cursor
IUpdateCursor( plInputInterface::kCursorUp );
fCursorOpacity = 1.f;
plMouseDevice::SetCursorOpacity( fCursorOpacity );
}
}
}
else
{
// Special debug flag to force the cursor to be hidden
if( fCursorOpacity != 0.f )
{
fCursorOpacity = 0.f;
plMouseDevice::SetCursorOpacity( fCursorOpacity );
}
}
plProfile_EndLap(Input, inputIEM);
return true;
}
plInputIfaceMgrMsg *mgrMsg = plInputIfaceMgrMsg::ConvertNoRef( msg );
if( mgrMsg != nil )
{
if( mgrMsg->GetCommand() == plInputIfaceMgrMsg::kAddInterface )
{
IAddInterface( mgrMsg->GetIFace() );
return true;
}
else if( mgrMsg->GetCommand() == plInputIfaceMgrMsg::kRemoveInterface )
{
IRemoveInterface( mgrMsg->GetIFace() );
return true;
}
else if( mgrMsg->GetCommand() == plInputIfaceMgrMsg::kEnableClickables )
{
fClickEnabled = true;
}
else if( mgrMsg->GetCommand() == plInputIfaceMgrMsg::kDisableClickables )
{
fClickEnabled = false;
}
}
plPlayerPageMsg *pPMsg = plPlayerPageMsg::ConvertNoRef( msg );
if( pPMsg != nil && !pPMsg->fUnload)
{
if( pPMsg->fPlayer == plNetClientMgr::GetInstance()->GetLocalPlayerKey() )
fReceivers.Append( pPMsg->fPlayer );
else
{
int idx = fReceivers.Find( pPMsg->fPlayer );
if( idx != fReceivers.kMissingIndex )
fReceivers.Remove( idx );
}
}
plCmdIfaceModMsg *pCMsg = plCmdIfaceModMsg::ConvertNoRef( msg );
if( pCMsg )
{
if( pCMsg->Cmd( plCmdIfaceModMsg::kAdd ) )
{
for( int i = 0; i < fReceivers.Count(); i++ )
{
if( fReceivers[i] == pCMsg->GetSender() )
return true;
}
fReceivers.Append( pCMsg->GetSender() );
return true;
}
else
if( pCMsg->Cmd( plCmdIfaceModMsg::kRemove ) )
{
for( int i = 0; i < fReceivers.Count(); i++ )
{
if( fReceivers[ i ] == pCMsg->GetSender() )
{
fReceivers.Remove( i );
break;
}
}
return true;
}
}
plClientMsg *cMsg = plClientMsg::ConvertNoRef(msg);
if (cMsg && cMsg->GetClientMsgFlag() == plClientMsg::kInitComplete)
{
// Backwards compatability hack:
// We've loaded in the user prefs for input. If they bind movement
// to an arrow, or numpad, and the other binding is free, automatically
// bind the other one.
plKeyMap *map = plAvatarInputInterface::GetInstance()->fControlMap;
map->HandleAutoDualBinding(KEY_UP, KEY_NUMPAD8);
map->HandleAutoDualBinding(KEY_DOWN, KEY_NUMPAD2);
map->HandleAutoDualBinding(KEY_LEFT, KEY_NUMPAD4);
map->HandleAutoDualBinding(KEY_RIGHT, KEY_NUMPAD6);
plgDispatch::Dispatch()->UnRegisterForExactType( plClientMsg::Index(), GetKey() );
return true;
}
// Wasn't one we want. Was it one that one of our interfaces wanted?
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
if( fInterfaces[ i ]->MsgReceive( msg ) )
return true;
}
// Nothing, pass on...
return plSingleModifier::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void plInputInterfaceMgr::Read( hsStream* s, hsResMgr* mgr )
{
plSingleModifier::Read( s, mgr );
}
void plInputInterfaceMgr::Write( hsStream* s, hsResMgr* mgr )
{
plSingleModifier::Write( s, mgr );
}
//////////////////////////////////////////////////////////////////////////////
//// Key Maps ////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// IGetRoutedKeyMap ////////////////////////////////////////////////////////
plKeyMap *plInputInterfaceMgr::IGetRoutedKeyMap( ControlEventCode code )
{
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
{
if( fInterfaces[ i ]->IOwnsControlCode( code ) )
return fInterfaces[ i ]->fControlMap;
}
return nil;
}
//// IUnbind /////////////////////////////////////////////////////////////////
// Unmaps any mappings with the given key. This prevents you from mapping
// a single key to multiple commands. Currently inactive because some people
// think it's a good idea to be able to do that.
#define ALLOW_MULTIPLE_CMDS_PER_KEY 1
void plInputInterfaceMgr::IUnbind( const plKeyCombo &key )
{
#if !(ALLOW_MULTIPLE_CMDS_PER_KEY)
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
fInterfaces[ i ]->fControlMap->UnmapKey( key );
#endif
}
void plInputInterfaceMgr::ClearAllKeyMaps()
{
for (int i = 0; i < fInterfaces.Count(); i++)
fInterfaces[i]->ClearKeyMap();
}
//// Binding Routers /////////////////////////////////////////////////////////
void plInputInterfaceMgr::BindAction( const plKeyCombo &key, ControlEventCode code )
{
plKeyMap *map = IGetRoutedKeyMap( code );
if( map != nil )
{
// Use default prefs
map->EnsureKeysClear( key, plKeyCombo::kUnmapped );
map->BindKey( key, code );
}
RefreshInterfaceKeyMaps();
}
void plInputInterfaceMgr::BindAction( const plKeyCombo &key1, const plKeyCombo &key2,
ControlEventCode code )
{
plKeyMap *map = IGetRoutedKeyMap( code );
if( map != nil )
{
// Force the bindings to each key, since the user specified both
map->EnsureKeysClear( key1, key2 );
map->BindKey( key1, code, plKeyMap::kFirstAlways );
map->BindKey( key2, code, plKeyMap::kSecondAlways );
}
RefreshInterfaceKeyMaps();
}
const plKeyBinding* plInputInterfaceMgr::FindBinding( ControlEventCode code )\
{
plKeyMap *map = IGetRoutedKeyMap( code );
if( map != nil )
{
// Use default prefs
return map->FindBinding(code);
}
return nil;
}
void plInputInterfaceMgr::BindConsoleCmd( const plKeyCombo &key, const char *cmd, plKeyMap::BindPref pref /*= kNoPreference*/ )
{
// not sure why this is not for external...since its done thru the different interfaces?
//#ifdef PLASMA_EXTERNAL_RELEASE
// return;
//#endif
plKeyMap *map = IGetRoutedKeyMap( B_CONTROL_CONSOLE_COMMAND );
if( map != nil )
{
// Default prefs again
map->EnsureKeysClear( key, plKeyCombo::kUnmapped );
// BindKeyToConsoleCmd only works if the console command in question has already been assigned
// to this map. Oftentimes, this isn't true when the user is binding console commands, so go ahead
// and add the command to this map. If it's already added, this call will just quietly fail and
// we're ok to continue
map->AddConsoleCommand( cmd );
map->BindKeyToConsoleCmd( key, cmd, pref );
}
RefreshInterfaceKeyMaps();
}
const plKeyBinding* plInputInterfaceMgr::FindBindingByConsoleCmd( const char *cmd )
{
plKeyMap *map = IGetRoutedKeyMap( B_CONTROL_CONSOLE_COMMAND );
if( map != nil )
{
return map->FindConsoleBinding(cmd);
}
return nil;
}
//// InitDefaultKeyMap ///////////////////////////////////////////////////////
void plInputInterfaceMgr::InitDefaultKeyMap( void )
{
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
fInterfaces[ i ]->RestoreDefaultKeyMappings();
RefreshInterfaceKeyMaps();
}
//// RefreshInterfaceKeyMaps /////////////////////////////////////////////////
void plInputInterfaceMgr::RefreshInterfaceKeyMaps( void )
{
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
fInterfaces[ i ]->RefreshKeyMap();
}
//// WriteKeyMap /////////////////////////////////////////////////////////////
void plInputInterfaceMgr::WriteKeyMap( void )
{
#ifdef PLASMA_EXTERNAL_RELEASE
return;
#endif
FILE* gKeyFile = 0;
gKeyFile = hsFopen( "init\\keyboard.fni", "wt" );
if (gKeyFile)
{
fprintf(gKeyFile, "# To remap a control to a new key,\n");
fprintf(gKeyFile, "# just change the key listed. \n");
fprintf(gKeyFile, "# The list of available commands is at the bottom.\n");
fprintf(gKeyFile, "# For keys with multi-character names \n");
fprintf(gKeyFile, "# like F1 or Backspace, be sure to enter \n");
fprintf(gKeyFile, "# the key name as it appears in the list \n");
fprintf(gKeyFile, "# at the end of the file. \n");
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# Be sure to put quotes around the actual command\n");
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# To add modifiers to a key mapping (like ctrl or shift)\n");
fprintf(gKeyFile, "# append _C for ctrl or _S for Shift (or both)\n");
fprintf(gKeyFile, "# to the actual name of the key.\n");
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# For example, to map Control-Shift-W to Walk Forward\n");
fprintf(gKeyFile, "# your key mapping entry would look like this:\n");
fprintf(gKeyFile, "# Keyboard.BindAction W_C_S \"Walk Forward\"\n");
fprintf(gKeyFile, "# This also works for console command bindings\n");
fprintf(gKeyFile, "# Keyboard.BindAction \t\tKey1\tKey2\t\t\t\tControl\n");
fprintf(gKeyFile, "#\n");
// fprintf(gKeyFile, "Keyboard.ClearBindings\n");
int i;
for( i = 0; i < fInterfaces.GetCount(); i++ )
IWriteNonConsoleCmdKeys( fInterfaces[ i ]->fControlMap, gKeyFile );
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# Console command bindings:\n");
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# Keyboard.BindConsoleCmd \tKey\t\t\tCommand\n");
fprintf(gKeyFile, "#\n");
for( i = 0; i < fInterfaces.GetCount(); i++ )
IWriteConsoleCmdKeys( fInterfaces[ i ]->fControlMap, gKeyFile );
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# Available game commands:\n");
fprintf(gKeyFile, "#\n");
for( int j = 0; plKeyMap::fCmdConvert[ j ].fCode != END_CONTROLS; j++ )
{
if( stricmp( plKeyMap::fCmdConvert[ j ].fDesc, "Run Modifier" ) == 0)
continue;
fprintf( gKeyFile, "# %s\n", plKeyMap::fCmdConvert[ j ].fDesc );
}
fprintf(gKeyFile, "#\n");
fprintf(gKeyFile, "# Key name list (for a-z or 0-9 just use the character)\n");
fprintf(gKeyFile, "#\n");
Win32keyConvert* keyConvert = &plKeyMap::fKeyConversionEnglish[0];
switch (plLocalization::GetLanguage())
{
case plLocalization::kFrench:
keyConvert = &plKeyMap::fKeyConversionFrench[0];
break;
case plLocalization::kGerman:
keyConvert = &plKeyMap::fKeyConversionGerman[0];
break;
//case plLocalization::kSpanish:
// keyConvert = &plKeyMap::fKeyConversionSpanish[0];
// break;
//case plLocalization::kItalian:
// keyConvert = &plKeyMap::fKeyConversionItalian[0];
// break;
// default is English
}
for (i = 0; keyConvert[i].fVKey != 0xffffffff; i++)
{
// if (stricmp(fKeyMap->fKeyConversion[i].fKeyName, "Shift") == 0)
// continue;
fprintf(gKeyFile, "# %s\n", keyConvert[i].fKeyName);
}
fclose(gKeyFile);
}
}
void plInputInterfaceMgr::SetCurrentFocus(plInputInterface *focus)
{
fCurrentFocus = focus;
}
void plInputInterfaceMgr::ReleaseCurrentFocus(plInputInterface *focus)
{
if (fCurrentFocus == focus)
fCurrentFocus = nil;
}
//// IKeyComboToString ///////////////////////////////////////////////////////
// Uses static string, so don't call twice and expect the first result to
// be still valid!
const char *plInputInterfaceMgr::IKeyComboToString( const plKeyCombo &combo )
{
static char str[ 64 ];
bool unmapped = false;
if( combo == plKeyCombo::kUnmapped )
sprintf( str, "(unmapped)" );
else
{
char *c = plKeyMap::ConvertVKeyToChar( combo.fKey );
if( c != nil )
strncpy( str, c, sizeof( str ) );
else
{
if( isalnum( combo.fKey ) )
{
str[ 0 ] = (char)combo.fKey;
str[ 1 ] = 0;
}
else
{
strcpy( str, "(unmapped)" );
unmapped = true;
}
}
if( !unmapped )
{
if( combo.fFlags & plKeyCombo::kCtrl )
strcat( str, "_C" );
if( combo.fFlags & plKeyCombo::kShift )
strcat( str, "_S" );
}
}
return str;
}
//// IWriteNonConsoleCmdKeys /////////////////////////////////////////////////
void plInputInterfaceMgr::IWriteNonConsoleCmdKeys( plKeyMap *keyMap, FILE *keyFile )
{
int i;
for( i = 0; i < keyMap->GetNumBindings(); i++ )
{
const plKeyBinding &binding = keyMap->GetBinding( i );
if( binding.GetCode() == B_CONTROL_CONSOLE_COMMAND )
continue;
char key1[ 64 ];
strcpy( key1, IKeyComboToString( binding.GetKey1() ) );
const char *key2 = IKeyComboToString( binding.GetKey2() );
const char *desc = plInputMap::ConvertControlCodeToString( binding.GetCode() );
fprintf( keyFile, "Keyboard.BindAction \t\t%s\t%s\t\t\t\t\"%s\"\n", key1, key2, desc );
}
}
//// IWriteConsoleCmdKeys ////////////////////////////////////////////////////
void plInputInterfaceMgr::IWriteConsoleCmdKeys( plKeyMap *keyMap, FILE *keyFile )
{
int i;
for( i = 0; i < keyMap->GetNumBindings(); i++ )
{
const plKeyBinding &binding = keyMap->GetBinding( i );
if( binding.GetCode() != B_CONTROL_CONSOLE_COMMAND )
continue;
// Our bindConsoleCmd console command (echo echo) only takes 1 key combo, not 2,
// so as not to confuse people. Or something. So if we got two bindings, we print
// 2 commands, which is perfectly valid
// if( binding.GetKey1() != plKeyCombo::kUnmapped )
// {
const char *key = IKeyComboToString( binding.GetKey1() );
fprintf( keyFile, "Keyboard.BindConsoleCmd\t%s\t\t\t\"%s\"\n", key, binding.GetExtendedString() );
// }
if( binding.GetKey2() != plKeyCombo::kUnmapped )
{
const char *key = IKeyComboToString( binding.GetKey2() );
fprintf( keyFile, "Keyboard.BindConsoleCmd\t%s\t\t\t\"%s\"\n", key, binding.GetExtendedString() );
}
}
}

View File

@ -0,0 +1,202 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plInputInterfaceMgr.h - The manager of all input interface layers //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 2.20.02 mcn - Created. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plInputInterfaceMgr_h
#define _plInputInterfaceMgr_h
#include "../pnModifier/plSingleModifier.h"
#include "hsTemplates.h"
#include "hsGeometry3.h"
#include "../pnInputCore/plKeyMap.h"
//// Class Definition ////////////////////////////////////////////////////////
class hsStream;
class hsResMgr;
class plInputInterface;
//class plKeyMap;
enum plKeyDef;
enum ControlEventCode;
class plKey;
class plCtrlCmd;
class plKeyCombo;
class plDefaultKeyCatcher;
class plKeyBinding;
class plInputInterfaceMgr : public plSingleModifier
{
protected:
static plInputInterfaceMgr *fInstance;
hsTArray<plInputInterface *> fInterfaces;
hsTArray<plCtrlCmd *> fMessageQueue;
hsTArray<plKey> fReceivers;
#ifdef MCN_DISABLE_OLD_WITH_NEW_HACK
hsTArray<ControlEventCode> fDisabledCodes;
hsTArray<UInt32> fDisabledKeys;
#endif
hsBool fClickEnabled;
Int32 fCurrentCursor;
hsScalar fCursorOpacity;
hsBool fForceCursorHidden;
Int32 fForceCursorHiddenCount;
plInputInterface *fCurrentFocus;
plDefaultKeyCatcher *fDefaultCatcher;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty );
void IAddInterface( plInputInterface *iface );
void IRemoveInterface( plInputInterface *iface );
void IUpdateCursor( Int32 newCursor );
hsBool ICheckCursor(plInputInterface *iFace); // returns true if the iface changed cursor settings
void IWriteConsoleCmdKeys( plKeyMap *keyMap, FILE *keyFile );
void IWriteNonConsoleCmdKeys( plKeyMap *keyMap, FILE *keyFile );
plKeyMap *IGetRoutedKeyMap( ControlEventCode code ); // Null for console commands
void IUnbind( const plKeyCombo &key );
const char *IKeyComboToString( const plKeyCombo &combo );
public:
plInputInterfaceMgr();
virtual ~plInputInterfaceMgr();
CLASSNAME_REGISTER( plInputInterfaceMgr );
GETINTERFACE_ANY( plInputInterfaceMgr, plSingleModifier );
virtual hsBool MsgReceive( plMessage *msg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
void Init( void );
void Shutdown( void );
void InitDefaultKeyMap( void );
void WriteKeyMap( void );
void RefreshInterfaceKeyMaps( void );
void SetCurrentFocus(plInputInterface *focus);
void ReleaseCurrentFocus(plInputInterface *focus);
void SetDefaultKeyCatcher( plDefaultKeyCatcher *c ) { fDefaultCatcher = c; }
hsBool IsClickEnabled() { return fClickEnabled; }
void ForceCursorHidden( hsBool requestedState );
// Binding routers
void BindAction( const plKeyCombo &key, ControlEventCode code );
void BindAction( const plKeyCombo &key1, const plKeyCombo &key2, ControlEventCode code );
void BindConsoleCmd( const plKeyCombo &key, const char *cmd, plKeyMap::BindPref pref = plKeyMap::kNoPreference );
const plKeyBinding* FindBinding( ControlEventCode code );
const plKeyBinding* FindBindingByConsoleCmd( const char *cmd );
void ClearAllKeyMaps();
void ResetClickableState();
static plInputInterfaceMgr *GetInstance( void ) { return fInstance; }
};
//// plCtrlCmd ///////////////////////////////////////////////////////////////
// Networkable helper class that represents a single control statement
class plCtrlCmd
{
private:
char* fCmd;
plInputInterface *fSource;
public:
plCtrlCmd( plInputInterface *source ) : fCmd(nil),fPct(1.0f), fSource(source) {;}
~plCtrlCmd() { delete [] fCmd; }
const char* GetCmdString() { return fCmd; }
void SetCmdString(const char* cs) { delete [] fCmd; fCmd=hsStrcpy(cs); }
ControlEventCode fControlCode;
hsBool fControlActivated;
hsPoint3 fPt;
hsScalar fPct;
hsBool fNetPropagateToPlayers;
void Read( hsStream* s, hsResMgr* mgr );
void Write( hsStream* s, hsResMgr* mgr );
plInputInterface *GetSource( void ) const { return fSource; }
};
//// Tiny Virtual Class For The Default Key Processor ////////////////////////
//
// Basically, if you want to be the one to catch the leftover key events,
// derive from this class and pass yourself to inputIFaceMgr.
// (it'll auto-tell inputIFaceMgr when it goes away)
//
// Note: if you want to do more than just get the darned key event (like
// mouse events or key bindings or change the cursor or the like), don't do
// this; create your own plInputInterface instead.
class plKeyEventMsg;
class plDefaultKeyCatcher
{
public:
virtual ~plDefaultKeyCatcher();
virtual void HandleKeyEvent( plKeyEventMsg *eventMsg ) = 0;
};
#endif // _plInputInterfaceMgr_h

View File

@ -0,0 +1,744 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsConfig.h"
#include "hsWindows.h"
// plInputManager.cpp
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include "hsTypes.h"
#include "plInputManager.h"
#include "plPipeline.h"
#include "plInputDevice.h"
#include "plDInputDevice.h"
#include "../plMessage/plInputEventMsg.h"
#include "plInputInterfaceMgr.h"
#include "hsStream.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "hsResMgr.h"
#include "hsTimer.h"
#include "plgDispatch.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnMessage/plCmdIfaceModMsg.h"
#include "../pnMessage/plPlayerPageMsg.h"
hsBool plInputManager::fUseDInput = false;
UInt8 plInputManager::bRecenterMouse = 0;
HWND plInputManager::fhWnd = nil;
#define NUM_ACTIONS 17
struct plDIDevice
{
plDIDevice() : fDevice(nil), fCaps(nil) {;}
plDIDevice(IDirectInputDevice8* _device) : fCaps(nil) { fDevice = _device;}
IDirectInputDevice8* fDevice;
DIDEVCAPS* fCaps;
};
struct plDInput
{
plDInput() :
fDInput(nil),
fActionFormat(nil)
{;}
IDirectInput8* fDInput;
hsTArray<plDIDevice*> fSticks;
DIACTIONFORMAT* fActionFormat;
};
class plDInputMgr
{
public:
plDInputMgr();
~plDInputMgr();
void Init(HINSTANCE hInst, HWND hWnd);
void Update();
void AddDevice(IDirectInputDevice8* device);
void ConfigureDevice();
virtual hsBool MsgReceive(plMessage* msg);
// dinput callback functions
static int __stdcall EnumGamepadCallback(const DIDEVICEINSTANCE* device, void* pRef);
// I should be using these but they don't work...
// static int __stdcall SetAxisRange(const DIDEVICEOBJECTINSTANCE* obj, void* pRef);
// static int __stdcall EnumSuitableDevices(const struct DIDEVICEINSTANCEA* devInst, struct IDirectInputDevice8* dev, unsigned long why, unsigned long devRemaining, void* pRef);
protected:
plDInput* fDI;
hsTArray<plDInputDevice*> fInputDevice;
static DIACTION fActionMap[];
HWND fhWnd;
};
// function pointers to dinput callbacks
typedef int (__stdcall * Pfunc1) (const DIDEVICEINSTANCE* device, void* pRef);
// I should need these...
//typedef int (__stdcall * Pfunc2) (const DIDEVICEOBJECTINSTANCE* device, void* pRef);
//typedef int (__stdcall * Pfunc3) (const struct DIDEVICEINSTANCEA* devInst, struct IDirectInputDevice8* dev, unsigned long why, unsigned long devRemaining, void* pRef);
plInputManager* plInputManager::fInstance = nil;
plInputManager::plInputManager( HWND hWnd ) :
fDInputMgr(nil),
fInterfaceMgr(nil)
{
fhWnd = hWnd;
fInstance = this;
fActive = false;
fFirstActivated = false;
fMouseScale = 1.f;
}
plInputManager::plInputManager() :
fDInputMgr(nil),
fInterfaceMgr(nil)
{
fInstance = this;
fActive = false;
fFirstActivated = false;
fMouseScale = 1.f;
}
plInputManager::~plInputManager()
{
fInterfaceMgr->Shutdown();
fInterfaceMgr = nil;
for (int i = 0; i < fInputDevices.Count(); i++)
{
fInputDevices[i]->Shutdown();
delete(fInputDevices[i]);
}
if (fDInputMgr)
delete fDInputMgr;
}
//static
void plInputManager::SetRecenterMouse(hsBool b)
{
if (b)
bRecenterMouse++;
else if (bRecenterMouse > 0)
bRecenterMouse--;
}
void plInputManager::RecenterCursor()
{
RECT rect;
GetClientRect(fhWnd, &rect);
POINT pt;
// pt.y = ( (rect.bottom - rect.top) / 2 ) / fInstance->fMouseScale;
// pt.x = ( (rect.right - rect.left) / 2 ) / fInstance->fMouseScale;
ClientToScreen(fhWnd, &pt);
SetCursorPos( pt.x, pt.y );
}
void plInputManager::CreateInterfaceMod(plPipeline* p)
{
fInterfaceMgr = TRACKED_NEW plInputInterfaceMgr();
fInterfaceMgr->Init();
}
void plInputManager::InitDInput(HINSTANCE hInst, HWND hWnd)
{
if (fUseDInput)
{
fDInputMgr = TRACKED_NEW plDInputMgr;
fDInputMgr->Init(hInst, hWnd);
}
}
hsBool plInputManager::MsgReceive(plMessage* msg)
{
for (int i=0; i<fInputDevices.Count(); i++)
if (fInputDevices[i]->MsgReceive(msg))
return true;
if (fDInputMgr)
return fDInputMgr->MsgReceive(msg);
return hsKeyedObject::MsgReceive(msg);
}
void plInputManager::Update()
{
if (fDInputMgr)
fDInputMgr->Update();
}
void plInputManager::SetMouseScale( hsScalar s )
{
/* RECT rect;
POINT currPos;
// Gotta make sure to move the mouse to the correct new position for the scale
GetClientRect( fhWnd, &rect );
GetCursorPos( &currPos );
ScreenToClient( fhWnd, &currPos );
float x = (float)currPos.x / rect.right;
float y = (float)currPos.y / rect.bottom;
x *= fMouseScale; y *= fMouseScale;
fMouseScale = s;
// Refreshes all of the input devices so that they can reset mouse limits, etc
RECT rect2 = rect;
rect2.right /= fMouseScale;
rect2.bottom /= fMouseScale;
::MapWindowPoints( fhWnd, NULL, (POINT *)&rect2, 2 );
BOOL ret = ::ClipCursor( &rect );
// Now move the cursor to the right spot
currPos.x = ( x / fMouseScale ) * rect.right;
currPos.y = ( y / fMouseScale ) * rect.bottom;
ClientToScreen( fhWnd, &currPos );
SetCursorPos( currPos.x, currPos.y );
*/
}
// Sometimes the keyboard driver "helps" us translating a key involved in a key
// combo. For example pressing shif-numpad8 will actually generate a KEY_UP event,
// the same as the up arrow. This function undoes that translation.
plKeyDef plInputManager::UntranslateKey(plKeyDef key, hsBool extended)
{
if (!extended)
{
if (key == KEY_UP)
return KEY_NUMPAD8;
if (key == KEY_DOWN)
return KEY_NUMPAD2;
if (key == KEY_LEFT)
return KEY_NUMPAD4;
if (key == KEY_RIGHT)
return KEY_NUMPAD6;
}
return key;
}
#if HS_BUILD_FOR_WIN32
/** Determines if we need to hackily flush cursor updates
* \remarks Normally, we would just call SetCursorPos directly. However, in Windows 10's
* 2017 Fall Creator's Update, SetCursorPos, GetCursorPos, and WM_MOUSEMOVE are buggy.
* Research done by Deledrius matches my independent observations and failed fixes:
* https://discourse.libsdl.org/t/win10-fall-creators-update-breaks-mouse-warping/23526
* Many thanks to these fine folks who work on libsdl!
*/
static bool INeedsWin10CursorHack()
{
// According to Chromium, Microsoft will be fixing the cursor bug in the next build
// of Windows 10, so we only need to test for the dreaded 2017 FCU...
// Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=781182#c15
// UPDATE: Bug is still present in the April 2018 Update (build 17134)...
// so this bandage will now be applied to anything 2017 FCU and later :(
const RTL_OSVERSIONINFOW& version = hsGetWindowsVersion();
return version.dwMajorVersion == 10 && version.dwBuildNumber >= 16299;
}
#endif // HS_BUILD_FOR_WIN32
void plInputManager::HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM Lparam, HWND hWnd)
{
if( !fhWnd )
fhWnd = hWnd;
hsBool bExtended;
switch (message)
{
case SYSKEYDOWN:
case KEYDOWN:
{
bExtended = Lparam >> 24 & 1;
hsBool bRepeat = ((Lparam >> 29) & 0xf) != 0;
for (int i=0; i<fInputDevices.Count(); i++)
fInputDevices[i]->HandleKeyEvent( KEYDOWN, UntranslateKey((plKeyDef)Wparam, bExtended), true, bRepeat );
}
break;
case SYSKEYUP:
case KEYUP:
{
bExtended = Lparam >> 24 & 1;
for (int i=0; i<fInputDevices.Count(); i++)
fInputDevices[i]->HandleKeyEvent( KEYUP, UntranslateKey((plKeyDef)Wparam, bExtended), false, false );
}
break;
case MOUSEWHEEL:
{
plMouseEventMsg* pMsg = TRACKED_NEW plMouseEventMsg;
int zDelta = GET_WHEEL_DELTA_WPARAM(Wparam);
pMsg->SetWheelDelta((float)zDelta);
if (zDelta < 0)
pMsg->SetButton(kWheelNeg);
else
pMsg->SetButton(kWheelPos);
RECT rect;
GetClientRect(hWnd, &rect);
pMsg->SetXPos(LOWORD(Lparam) / (float)rect.right);
pMsg->SetYPos(HIWORD(Lparam) / (float)rect.bottom);
pMsg->Send();
}
break;
case MOUSEMOVE:
case L_BUTTONDN:
case L_BUTTONUP:
case R_BUTTONDN:
case R_BUTTONUP:
case L_BUTTONDBLCLK:
case R_BUTTONDBLCLK:
case M_BUTTONDN:
case M_BUTTONUP:
{
RECT rect;
GetClientRect(hWnd, &rect);
plIMouseXEventMsg* pXMsg = TRACKED_NEW plIMouseXEventMsg;
plIMouseYEventMsg* pYMsg = TRACKED_NEW plIMouseYEventMsg;
plIMouseBEventMsg* pBMsg = TRACKED_NEW plIMouseBEventMsg;
pXMsg->fWx = LOWORD(Lparam);
pXMsg->fX = (float)LOWORD(Lparam) / (float)rect.right;
pYMsg->fWy = HIWORD(Lparam);
pYMsg->fY = (float)HIWORD(Lparam) / (float)rect.bottom;
// Apply mouse scale
// pXMsg->fX *= fMouseScale;
// pYMsg->fY *= fMouseScale;
if (Wparam & MK_LBUTTON && message != L_BUTTONUP)
{
pBMsg->fButton |= kLeftButtonDown;
}
else
{
pBMsg->fButton |= kLeftButtonUp;
}
if (Wparam & MK_RBUTTON && message != R_BUTTONUP)
{
pBMsg->fButton |= kRightButtonDown;
}
else
{
pBMsg->fButton |= kRightButtonUp;
}
if (Wparam & MK_MBUTTON && message != M_BUTTONUP)
{
pBMsg->fButton |= kMiddleButtonDown;
}
else
{
pBMsg->fButton |= kMiddleButtonUp;
}
if( message == L_BUTTONDBLCLK )
pBMsg->fButton |= kLeftButtonDblClk; // We send the double clicks separately
if( message == R_BUTTONDBLCLK )
pBMsg->fButton |= kRightButtonDblClk;
for (int i=0; i<fInputDevices.Count(); i++)
{
fInputDevices[i]->MsgReceive(pXMsg);
fInputDevices[i]->MsgReceive(pYMsg);
fInputDevices[i]->MsgReceive(pBMsg);
}
POINT pt;
if (RecenterMouse() && (pXMsg->fX <= 0.1 || pXMsg->fX >= 0.9) )
{
pt.x = (rect.right - rect.left) / 2;
pt.y = HIWORD(Lparam);
if (INeedsWin10CursorHack()) {
pXMsg->fWx = pt.x;
pXMsg->fX = pt.x / (float)rect.right;
for (int i = 0; i < fInputDevices.Count(); i++)
fInputDevices[i]->MsgReceive(pXMsg);
}
ClientToScreen(hWnd, &pt);
SetCursorPos( pt.x, pt.y );
}
else
if (RecenterMouse() && (pYMsg->fY <= 0.1 || pYMsg->fY >= 0.9) )
{
pt.y = (rect.bottom - rect.top) / 2;
pt.x = LOWORD(Lparam);
if (INeedsWin10CursorHack()) {
pYMsg->fWy = pt.y;
pYMsg->fY = pYMsg->fWy / (float)rect.bottom;
for (int i = 0; i < fInputDevices.Count(); i++)
fInputDevices[i]->MsgReceive(pYMsg);
}
ClientToScreen(hWnd, &pt);
SetCursorPos( pt.x, pt.y );
}
if (RecenterMouse() && Lparam == 0)
{
pt.y = (rect.bottom - rect.top) / 2;
pt.x = (rect.right - rect.left) / 2;
if (INeedsWin10CursorHack()) {
pXMsg->fWx = pt.x;
pXMsg->fX = pXMsg->fWx / (float)rect.right;
pYMsg->fWy = pt.y;
pYMsg->fY = pYMsg->fWy / (float)rect.bottom;
for (int i = 0; i < fInputDevices.Count(); i++) {
fInputDevices[i]->MsgReceive(pXMsg);
fInputDevices[i]->MsgReceive(pYMsg);
}
}
ClientToScreen(hWnd, &pt);
SetCursorPos( pt.x, pt.y );
}
delete(pXMsg);
delete(pYMsg);
delete(pBMsg);
}
break;
case WM_ACTIVATE:
{
bool activated = ( LOWORD( Wparam ) == WA_INACTIVE ) ? false : true;
Activate( activated );
}
break;
}
}
//// Activate ////////////////////////////////////////////////////////////////
// Handles what happens when the app (window) activates/deactivates
void plInputManager::Activate( bool activating )
{
int i;
for( i = 0; i < fInputDevices.GetCount(); i++ )
fInputDevices[ i ]->HandleWindowActivate( activating, fhWnd );
fActive = activating;
fFirstActivated = true;
}
//// AddInputDevice //////////////////////////////////////////////////////////
void plInputManager::AddInputDevice( plInputDevice *pDev )
{
fInputDevices.Append( pDev );
if( fFirstActivated )
pDev->HandleWindowActivate( fActive, fhWnd );
}
//
//
// dinput manager
//
//
plDInputMgr::plDInputMgr() :
fDI(nil)
{
fDI = TRACKED_NEW plDInput;
}
plDInputMgr::~plDInputMgr()
{
if (fDI)
{
for (int i = 0; i < fDI->fSticks.Count(); i++)
{
plDIDevice* pD = fDI->fSticks[i];
pD->fDevice->Release();
delete(pD->fCaps);
delete(pD);
}
fDI->fSticks.SetCountAndZero(0);
delete(fDI->fActionFormat);
fDI->fDInput->Release();
for(int j = 0; j < fInputDevice.Count(); j++)
delete(fInputDevice[j]);
fInputDevice.SetCountAndZero(0);
delete fDI;
}
}
void plDInputMgr::Init(HINSTANCE hInst, HWND hWnd)
{
HRESULT hr;
hr = DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&fDI->fDInput, NULL);
hsAssert(!hr, "failed to initialize directInput!");
// enumerate game controllers
Pfunc1 fPtr = &plDInputMgr::EnumGamepadCallback;
int i = 0;
// set up the action mapping
fDI->fActionFormat = TRACKED_NEW DIACTIONFORMAT;
fDI->fActionFormat->dwSize = sizeof(DIACTIONFORMAT);
fDI->fActionFormat->dwActionSize = sizeof(DIACTION);
fDI->fActionFormat->dwDataSize = NUM_ACTIONS * sizeof(DWORD);
fDI->fActionFormat->dwNumActions = NUM_ACTIONS;
fDI->fActionFormat->guidActionMap = PL_ACTION_GUID;
fDI->fActionFormat->dwGenre = DIVIRTUAL_FIGHTING_THIRDPERSON;
fDI->fActionFormat->rgoAction = fActionMap;
fDI->fActionFormat->dwBufferSize = 16;
fDI->fActionFormat->lAxisMin = -1000;
fDI->fActionFormat->lAxisMax = 1000;
sprintf( fDI->fActionFormat->tszActionMap, "Plasma 2.0 Game Actions" );
// this call should not work:
fDI->fDInput->EnumDevices(DI8DEVCLASS_GAMECTRL, fPtr, fDI, DIEDFL_ATTACHEDONLY);
// apply the mapping to the game controller
// this is the correct <but broken> way to apply the action map:
// Pfunc3 fPtr3 = &plDInputMgr::EnumSuitableDevices;
// hr = fDI->fDInput->EnumDevicesBySemantics(NULL, fDI->fActionFormat, EnumSuitableDevices, fDI, NULL);
for (i = 0; i < fDI->fSticks.Count(); i++)
{
fDI->fSticks[i]->fCaps = TRACKED_NEW DIDEVCAPS;
fDI->fSticks[i]->fCaps->dwSize = sizeof(DIDEVCAPS);
hr = fDI->fSticks[i]->fDevice->GetCapabilities(fDI->fSticks[i]->fCaps);
hsAssert(!hr, "Unable to acquire devcaps in DInput Device!");
hr = fDI->fSticks[i]->fDevice->Acquire();
hsAssert(!hr, "Unable to acquire DInput Device!");
}
fhWnd = hWnd;
for (i = 0; i < fDI->fSticks.Count(); i++)
fInputDevice.Append( TRACKED_NEW plDInputDevice );
}
void plDInputMgr::Update()
{
HRESULT hr;
if (!fDI->fSticks.Count())
return;
// Poll the devices to read the current state
for (int i = 0; i < fDI->fSticks.Count(); i++)
{
hr = fDI->fSticks[i]->fDevice->Poll();
if (FAILED(hr))
{
// Attempt to reacquire joystick
while(hr == DIERR_INPUTLOST)
{
hr = fDI->fSticks[i]->fDevice->Acquire();
char str[256];
sprintf(str, "DInput Device # %d connection lost - press Ignore to attempt to reacquire!", i);
hsAssert(!hr, str);
}
}
DIDEVICEOBJECTDATA data;
ULONG size = 1;
hr = fDI->fSticks[i]->fDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),&data,&size,0);
fInputDevice[i]->Update(&data);
}
}
void plDInputMgr::AddDevice(IDirectInputDevice8* device)
{
HRESULT hr = device->BuildActionMap(fDI->fActionFormat, NULL, NULL);
if (!FAILED(hr))
device->SetActionMap( fDI->fActionFormat, NULL, NULL );
}
void plDInputMgr::ConfigureDevice()
{
::ShowCursor( TRUE );
DICOLORSET dics;
ZeroMemory(&dics, sizeof(DICOLORSET));
dics.dwSize = sizeof(DICOLORSET);
DICONFIGUREDEVICESPARAMS dicdp;
ZeroMemory(&dicdp, sizeof(dicdp));
dicdp.dwSize = sizeof(dicdp);
dicdp.dwcUsers = 1;
dicdp.lptszUserNames = NULL;
dicdp.dwcFormats = 1;
dicdp.lprgFormats = fDI->fActionFormat;
dicdp.hwnd = fhWnd;
dicdp.lpUnkDDSTarget = NULL;
fDI->fDInput->ConfigureDevices(NULL, &dicdp, DICD_EDIT, NULL);
for (int i = 0; i < fDI->fSticks.Count(); i++)
fDI->fSticks[i]->fDevice->SetActionMap( fDI->fActionFormat, NULL, DIDSAM_FORCESAVE );
::ShowCursor( FALSE );
}
hsBool plDInputMgr::MsgReceive(plMessage* msg)
{
plInputEventMsg* pMsg = plInputEventMsg::ConvertNoRef(msg);
if (pMsg && pMsg->fEvent == plInputEventMsg::kConfigure)
{
ConfigureDevice();
}
return false;
}
// dinput required callback functions:
// enumerate the dinput devices
int __stdcall plDInputMgr::EnumGamepadCallback(const DIDEVICEINSTANCE* device, void* pRef)
{
HRESULT hr;
plDInput* pDI = (plDInput*)pRef;
IDirectInputDevice8* fStick = nil;
hr = pDI->fDInput->CreateDevice(device->guidInstance, &fStick, NULL);
if(!FAILED(hr))
{
pDI->fSticks.Append(TRACKED_NEW plDIDevice(fStick));
// the following code pertaining to the action map shouldn't be here.
// in fact this shouldn't work at all according to MS, but this is
// currently the only way this works. Whatever - the correct
// code is here and commented out in case this ever gets fixed by MS
// in a future release of dinput.
HRESULT hr = fStick->BuildActionMap(pDI->fActionFormat, NULL, NULL);
if (!FAILED(hr))
{
hr = fStick->SetActionMap( pDI->fActionFormat, NULL, NULL );
DIPROPDWORD dipW;
dipW.diph.dwSize = sizeof(DIPROPDWORD);
dipW.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipW.diph.dwHow = DIPH_DEVICE;
dipW.diph.dwObj = 0;
dipW.dwData = 500; // 5% of axis range for deadzone
hr = fStick->SetProperty(DIPROP_DEADZONE , &dipW.diph);
}
return DIENUM_CONTINUE;
}
return DIENUM_STOP;
}
// look for axes on the controller and set the output range to +-100
// apparently not needed with action mapping:
/*
int __stdcall plDInputMgr::SetAxisRange(const DIDEVICEOBJECTINSTANCE* obj, void* pRef)
{
HRESULT hr;
DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYID;
diprg.diph.dwObj = obj->dwType;
diprg.lMin = -100;
diprg.lMax = +100;
plDInput* pDI = (plDInput*)pRef;
for (int i = 0; i < pDI->fSticks.Count(); i++)
hr = pDI->fSticks[i]->fDevice->SetProperty(DIPROP_RANGE, &diprg.diph);
if(!FAILED(hr))
return DIENUM_CONTINUE;
return DIENUM_STOP;
}
*/
// apply mapping to controller
// not used. why? no one really knows.
// leave this here in case dinput ever gets fixed...
/*
int __stdcall plDInputMgr::EnumSuitableDevices(const struct DIDEVICEINSTANCEA* devInst, struct IDirectInputDevice8* dev, unsigned long why, unsigned long devRemaining, void* pRef)
{
plDInput* pDI = (plDInput*)pRef;
HRESULT hr = dev->BuildActionMap(pDI->fActionFormat, NULL, NULL);
if (!FAILED(hr))
{
hr = dev->SetActionMap( pDI->fActionFormat, NULL, NULL );
}
return DIENUM_STOP;
}
*/
DIACTION plDInputMgr::fActionMap[NUM_ACTIONS] =
{
{A_CONTROL_MOVE, DIAXIS_TPS_MOVE, 0, "Walk Forward-Backward" ,},
{A_CONTROL_TURN, DIAXIS_TPS_TURN, 0, "Turn Left-Right" ,},
{A_CONTROL_MOUSE_X, DIAXIS_ANY_1, 0, "Move Camera Left-Right",},
{A_CONTROL_MOUSE_Y, DIAXIS_ANY_2, 0, "Move Camera Up-Down" ,},
{B_CONTROL_ACTION, DIBUTTON_TPS_ACTION, 0, "Action" ,},
{B_CONTROL_JUMP, DIBUTTON_TPS_JUMP, 0, "Jump" ,},
{B_CONTROL_STRAFE_LEFT, DIBUTTON_TPS_STEPLEFT, 0, "Strafe Left" ,},
{B_CONTROL_STRAFE_RIGHT, DIBUTTON_TPS_STEPRIGHT, 0, "Strafe Right" ,},
{B_CONTROL_MODIFIER_FAST, DIBUTTON_TPS_RUN, 0, "Run" ,},
{B_CONTROL_EQUIP, DIBUTTON_TPS_SELECT, 0, "Equip Item" ,},
{B_CONTROL_DROP, DIBUTTON_TPS_USE, 0, "Drop Item" ,},
{B_CONTROL_MOVE_FORWARD, DIBUTTON_ANY(0), 0, "Walk Forward" ,},
{B_CONTROL_MOVE_BACKWARD, DIBUTTON_ANY(1), 0, "Walk Backward" ,},
{B_CONTROL_ROTATE_LEFT, DIBUTTON_ANY(2), 0, "Turn Left" ,},
{B_CONTROL_ROTATE_RIGHT, DIBUTTON_ANY(3), 0, "Turn Right" ,},
{B_CONTROL_TURN_TO, DIBUTTON_ANY(4), 0, "Pick Item" ,},
{B_CAMERA_RECENTER, DIBUTTON_ANY(5), 0, "Recenter Camera" ,},
};

View File

@ -0,0 +1,112 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// plInputManager.h
#ifndef PL_INPUT_MANAGER_H
#define PL_INPUT_MANAGER_H
#include <windows.h>
#include "hsTypes.h"
#include "hsTemplates.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../pnInputCore/plInputMap.h"
class plDInputMgr;
class plInputDevice;
class plDInputDevice;
class plInputInterfaceMgr;
class plPipeline;
class plInputManager :public hsKeyedObject
{
private:
static hsBool fUseDInput;
public:
plInputManager();
plInputManager( HWND hWnd );
~plInputManager();
CLASSNAME_REGISTER( plInputManager );
GETINTERFACE_ANY( plInputManager, hsKeyedObject );
void AddInputDevice(plInputDevice* pDev);
void InitDInput(HINSTANCE hInst, HWND hWnd);
static void UseDInput(hsBool b) { fUseDInput = b; }
void Update();
static plInputManager* GetInstance() { return fInstance; }
static plInputManager* fInstance;
virtual hsBool MsgReceive(plMessage* msg);
static hsBool RecenterMouse() { return bRecenterMouse > 0; }
static void SetRecenterMouse(hsBool b);
static void RecenterCursor();
void CreateInterfaceMod(plPipeline* p);
void Activate( bool activating );
hsScalar GetMouseScale( void ) const { return fMouseScale; }
void SetMouseScale( hsScalar s );
static plKeyDef UntranslateKey(plKeyDef key, hsBool extended);
protected:
hsTArray<plInputDevice*> fInputDevices;
plDInputMgr* fDInputMgr;
plInputInterfaceMgr *fInterfaceMgr;
bool fActive, fFirstActivated;
hsScalar fMouseScale;
static UInt8 bRecenterMouse;
static HWND fhWnd;
public:
// event handlers
void HandleWin32ControlEvent(UINT message, WPARAM Wparam, LPARAM Lparam, HWND hWnd);
};
// {049DE53E-23A2-4d43-BF68-36AC1B57E357}
static const GUID PL_ACTION_GUID = { 0x49de53e, 0x23a2, 0x4d43, { 0xbf, 0x68, 0x36, 0xac, 0x1b, 0x57, 0xe3, 0x57 } };
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSceneInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSceneInputInterface_h
#define _plSceneInputInterface_h
#include "plInputInterface.h"
#include "hsGeometry3.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnUtils/pnUtils.h"
//// Class Definition ////////////////////////////////////////////////////////
class plPipeline;
class plSceneObject;
class plSceneInputInterface : public plInputInterface
{
enum
{
kNotOffering = 0,
kOfferBook,
kBookOffered,
kOfferAccepted,
kOfferLinkPending,
};
protected:
static plSceneInputInterface *fInstance;
UInt32 fCurrentCursor;
UInt8 fButtonState;
hsBool fClickability;
plKey fCurrentClickable, fLastClicked, fCurrentClickableLogicMod;
hsPoint3 fCurrentClickPoint;
hsBool fCurrClickIsAvatar, fLastClickIsAvatar,fFadedLocalAvatar;
hsBool fPendingLink;
int fBookMode; // are we in offer book mode?
plKey fBookKey; // key for the python file modifier for the book we are offering
plKey fOffereeKey;
UInt32 fOffereeID; // ID for the guy who's accepted our link offer
const char* fOfferedAgeFile;
const char* fOfferedAgeInstance;
const char* fSpawnPoint;
Uuid fAgeInstanceGuid;
struct clickableTest
{
clickableTest(plKey k)
{
key = k;
val = false;
}
plKey key;
hsBool val;
};
hsTArray<clickableTest *> fClickableMap;
hsTArray<plKey> fIgnoredAvatars; // these are ignored because they are engaged in avatar-avatar interactions which need to be left undisturbed
hsTArray<plKey> fGUIIgnoredAvatars; // these are ignored because they have a GUI in their face right now
hsTArray<plKey> fLocalIgnoredAvatars; // these are ALL avatars currently in your age. they are ignored when you press the 'ignore' key so you can
// select clickable non-avatar objects through them.
hsPoint3 fLastStartPt, fLastEndPt;
plPipeline *fPipe;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty );
void IRequestLOSCheck( hsScalar xPos, hsScalar yPos, int ID );
void ISetLastClicked( plKey obj, hsPoint3 hitPoint );
void IHalfFadeAvatar(hsBool out);
hsBool IWorldPosMovedSinceLastLOSCheck( void );
void ClearClickableMap();
void ISendOfferNotification(plKey& offeree, int ID, hsBool net);
void IManageIgnoredAvatars(plKey& offeree, hsBool add);
void ISendAvatarDisabledNotification(hsBool enabled);
void ILinkOffereeToAge();
public:
plSceneInputInterface();
virtual ~plSceneInputInterface();
static hsBool fShowLOS;
// Always return true, since the cursor should be representing how we control the avatar
virtual hsBool HasInterestingCursorID( void ) const { return ( fCurrentCursor != kNullCursor ) ? true : false; }
virtual UInt32 GetPriorityLevel( void ) const { return kSceneInteractionPriority; }
virtual UInt32 GetCurrentCursorID( void ) const {return fCurrentCursor;}
UInt32 SetCurrentCursorID(UInt32 id);
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
void RequestAvatarTurnToPointLOS();
virtual hsBool MsgReceive( plMessage *msg );
virtual void Init( plInputInterfaceMgr *manager );
virtual void Shutdown( void );
virtual void ResetClickableState();
plKey GetCurrMousedAvatar( void ) const { if( fCurrClickIsAvatar ) return fCurrentClickable; else return nil; }
static plSceneInputInterface *GetInstance( void ) { return fInstance; }
};
#endif //_plSceneInputInterface_h

View File

@ -0,0 +1,141 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plTelescopeInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsConfig.h"
#include "hsWindows.h"
#include "hsTypes.h"
#include "plTelescopeInputInterface.h"
#include "plInputInterfaceMgr.h"
#include "plInputManager.h"
#include "plInputDevice.h"
#include "../pnInputCore/plKeyMap.h"
#include "plgDispatch.h"
//// Constructor/Destructor //////////////////////////////////////////////////
plTelescopeInputInterface::plTelescopeInputInterface()
{
SetEnabled( true ); // Always enabled
// Add our control codes to our control map. Do NOT add the key bindings yet.
// Note: HERE is where you specify the actions for each command, i.e. net propagate and so forth.
// This part basically declares us master of the bindings for these commands.
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
fControlMap->AddCode( B_CONTROL_EXIT_MODE, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_PAN_LEFT, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_PAN_RIGHT, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_PAN_UP, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_PAN_DOWN, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_RECENTER, kControlFlagNormal | kControlFlagNoRepeat );
fControlMap->AddCode( B_CAMERA_ZOOM_IN, kControlFlagNormal );
fControlMap->AddCode( B_CAMERA_ZOOM_OUT, kControlFlagNormal );
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
}
plTelescopeInputInterface::~plTelescopeInputInterface()
{
}
//// Init/Shutdown ///////////////////////////////////////////////////////////
void plTelescopeInputInterface::Init( plInputInterfaceMgr *manager )
{
plInputInterface::Init( manager );
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool plTelescopeInputInterface::IEval( double secs, hsScalar del, UInt32 dirty )
{
return true;
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool plTelescopeInputInterface::MsgReceive( plMessage *msg )
{
return false;
}
//// InterpretInputEvent /////////////////////////////////////////////////////
hsBool plTelescopeInputInterface::InterpretInputEvent( plInputEventMsg *pMsg )
{
return false;
}
//// RestoreDefaultKeyMappings ///////////////////////////////////////////////
void plTelescopeInputInterface::RestoreDefaultKeyMappings( void )
{
if( fControlMap == nil )
return;
fControlMap->UnmapAllBindings();
fControlMap->BindKey( KEY_BACKSPACE, B_CONTROL_EXIT_MODE );
fControlMap->BindKey( KEY_NUMPAD5, B_CAMERA_RECENTER );
fControlMap->BindKey( KEY_C, B_CAMERA_RECENTER );
fControlMap->BindKey( KEY_NUMPAD_ADD, B_CAMERA_ZOOM_IN );
fControlMap->BindKey( KEY_NUMPAD_SUBTRACT, B_CAMERA_ZOOM_OUT );
fControlMap->BindKey( KEY_NUMPAD4, B_CAMERA_PAN_LEFT );
fControlMap->BindKey( KEY_NUMPAD6, B_CAMERA_PAN_RIGHT );
fControlMap->BindKey( KEY_NUMPAD8, B_CAMERA_PAN_UP );
fControlMap->BindKey( KEY_NUMPAD2, B_CAMERA_PAN_DOWN );
}

View File

@ -0,0 +1,90 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plTelescopeInputInterface //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plTelescopeInputInterface_h
#define _plTelescopeInputInterface_h
#include "plInputInterface.h"
#include "../pnKeyedObject/plKey.h"
//// Class Definition ////////////////////////////////////////////////////////
class plTelescopeInputInterface : public plInputInterface
{
protected:
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty );
public:
plTelescopeInputInterface();
virtual ~plTelescopeInputInterface();
virtual void RestoreDefaultKeyMappings( void );
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
virtual hsBool MsgReceive( plMessage *msg );
virtual void Init( plInputInterfaceMgr *manager );
virtual void Shutdown( void ) {;}
// Returns the priority of this interface layer, based on the Priorities enum
virtual UInt32 GetPriorityLevel( void ) const { return kTelescopeInputPriority; }
// Returns the currently active mouse cursor for this layer, as defined in pnMessage/plCursorChangeMsg.h
virtual UInt32 GetCurrentCursorID( void ) const { return kCursorUp; }
// Returns the current opacity that this layer wants the cursor to be, from 0 (xparent) to 1 (opaque)
virtual hsScalar GetCurrentCursorOpacity( void ) const { return 1.f; }
// Returns true if this layer is wanting to change the mouse, false if it isn't interested
virtual hsBool HasInterestingCursorID( void ) const { return false; }
};
#endif //_plTelescopeInputInterface_h