parent
7223a4d208
commit
a307c383f9
@ -1,204 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_DI_EVENT_EMITTER_H
|
||||
#define NL_DI_EVENT_EMITTER_H
|
||||
|
||||
|
||||
|
||||
#include "types_nl.h"
|
||||
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
|
||||
#include "input_device_server.h"
|
||||
#include "input_device_manager.h"
|
||||
#include "event_emitter.h"
|
||||
#include "smart_ptr.h"
|
||||
#include "events.h"
|
||||
#include "rect.h"
|
||||
#include "game_device.h"
|
||||
#ifndef NL_COMP_MINGW
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <dinput.h>
|
||||
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
|
||||
class CWinEventEmitter;
|
||||
class CDIKeyboard;
|
||||
class CDIMouse;
|
||||
struct IMouseDevice;
|
||||
struct IKeyboardDevice;
|
||||
|
||||
//
|
||||
struct EDirectInput : public EInputDevice
|
||||
{
|
||||
EDirectInput(const char *reason) : EInputDevice(reason) {}
|
||||
};
|
||||
//
|
||||
struct EDirectInputLibNotFound : public EDirectInput
|
||||
{
|
||||
EDirectInputLibNotFound() : EDirectInput("can't found the direct input dll") {}
|
||||
};
|
||||
//
|
||||
struct EDirectInputInitFailed : public EDirectInput
|
||||
{
|
||||
EDirectInputInitFailed() : EDirectInput("Direct input initialization failed") {}
|
||||
};
|
||||
//
|
||||
struct EDirectInputCooperativeLevelFailed : public EDirectInput
|
||||
{
|
||||
EDirectInputCooperativeLevelFailed() : EDirectInput("Direct Input Device Cooperative level couldn't be set") {}
|
||||
};
|
||||
|
||||
|
||||
// Class to represent Direct Inputs events
|
||||
struct CDIEvent : public IInputDeviceEvent
|
||||
{
|
||||
virtual bool operator < (const IInputDeviceEvent &ide) const
|
||||
{
|
||||
// just compare the dates
|
||||
return Datas.dwTimeStamp < (safe_cast<const CDIEvent *>(&ide))->Datas.dwTimeStamp;
|
||||
}
|
||||
DIDEVICEOBJECTDATA Datas;
|
||||
};
|
||||
|
||||
/**
|
||||
* This manage events by using DirectInput8.
|
||||
* This should be polled regularly.
|
||||
* This can be mixed with a CWinEmitter (for example, you may have mouse using direct input, and keyboard using standard messages)
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
class CDIEventEmitter : public IEventEmitter, public IInputDeviceManager
|
||||
{
|
||||
public:
|
||||
/** Build a Direct Input Event Emitter object. An exception containing the reason is thrown if the initialization failed.
|
||||
* The obtained object must be released by deleting it.
|
||||
* \param hinst the instance of the application.
|
||||
* \param hwnd the main window of the application.
|
||||
* \param we A windows eventsemitter. Can be NULL. Needed if you want to mix WIN32 events and Direct Input events
|
||||
* (for example, a Direct Input Mouse and a Win32 Keyboard)
|
||||
*/
|
||||
static CDIEventEmitter *create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we) throw(EDirectInput);
|
||||
~CDIEventEmitter();
|
||||
public:
|
||||
|
||||
/// This poll the direct input state, directly storing the result in the given server, or keeping the result in internal server if NULL.
|
||||
void poll(CEventServer *server = NULL);
|
||||
|
||||
///\name From IDeviceManager, access to devices
|
||||
//@{
|
||||
// Test if a mouse has been created (by a call to getMouseDeivce)
|
||||
virtual bool isMouseCreated() { return _Mouse != NULL; }
|
||||
/** Create the mouse device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. An exception if thrown if it couldn't be obtained.
|
||||
* If this object has a pointer on a win32 emiter, Win32 mouse messages are replaced by this mouse messages.
|
||||
*/
|
||||
virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice);
|
||||
/// remove the direct input mouse
|
||||
virtual void releaseMouse();
|
||||
/** Create the keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it.
|
||||
* If this object has a pointer on a win32 emiter, Win32 keyboard messages are replaced by this keyboard messages.
|
||||
* NB: A direct input has no notion of localization or key combinations. See keyboard_device.h for more infos
|
||||
*/
|
||||
virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice);
|
||||
/// remove the direct input keyboard
|
||||
virtual void releaseKeyboard();
|
||||
// Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector
|
||||
virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice);
|
||||
// Create the given game device from its instance name. It also means that it will begin to sends inputs
|
||||
virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice);
|
||||
// Release the given game device
|
||||
virtual void releaseGameDevice(IGameDevice *);
|
||||
//@}
|
||||
|
||||
/// from IEventEmitter
|
||||
virtual void submitEvents(CEventServer &server, bool allWindows);
|
||||
virtual void emulateMouseRawMode(bool enable);
|
||||
|
||||
// Build a TMouseButton value from the current buttons state
|
||||
TMouseButton buildButtonsFlags() const;
|
||||
// Build a TMouseButton value (but with no mouse values)
|
||||
TMouseButton buildKeyboardButtonFlags() const
|
||||
{
|
||||
return (TMouseButton) (buildButtonsFlags() & (ctrlButton|shiftButton|altButton));
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//================================================================
|
||||
//================================================================
|
||||
private:
|
||||
typedef HRESULT (WINAPI * TPDirectInput8Create) (HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter);
|
||||
// Private internal server message, used to stored all messages internally before to dispatch them, when no server is supplied to poll(...
|
||||
class CDIEventServer : CEventServer
|
||||
{
|
||||
friend class CDIEventEmitter;
|
||||
public:
|
||||
void setServer (CEventServer *server)
|
||||
{
|
||||
_Server = server;
|
||||
}
|
||||
private:
|
||||
bool pumpEvent(CEvent *event)
|
||||
{
|
||||
CEventServer::pumpEvent(event);
|
||||
_Server->postEvent (event);
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
CEventServer *_Server;
|
||||
};
|
||||
private:
|
||||
HWND _hWnd;
|
||||
TMouseButton _ButtonsFlags;
|
||||
NLMISC::CRefPtr<CWinEventEmitter> _WE;
|
||||
static HMODULE _DirectInputLibHandle;
|
||||
static TPDirectInput8Create _PDirectInput8Create;
|
||||
static uint _NumCreatedInterfaces;
|
||||
private:
|
||||
static bool loadLib();
|
||||
static void unloadLib();
|
||||
//====
|
||||
private:
|
||||
CDIEventServer _InternalServer;
|
||||
CInputDeviceServer _DeviceServer;
|
||||
IDirectInput8 *_DInput8;
|
||||
CDIMouse *_Mouse;
|
||||
CDIKeyboard *_Keyboard;
|
||||
private:
|
||||
CDIEventEmitter(HWND hwnd, CWinEventEmitter *we);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
#endif // NL_WINDOWS
|
||||
|
||||
|
||||
#endif // NL_DX_EVENT_EMITTER_H
|
||||
|
||||
/* End of dx_event_emitter.h */
|
@ -1,114 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_GAME_DEVICE_H
|
||||
#define NL_GAME_DEVICE_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include "input_device.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
/// Describe a game device
|
||||
struct CGameDeviceDesc
|
||||
{
|
||||
// type of the device
|
||||
enum TDevType { GamePad, Joystick, DontKnow, DevTypeLast } DevType;
|
||||
// Friendly name for the instance. For example, "Joystick 1."
|
||||
std::string InstanceName;
|
||||
// Friendly name for the product
|
||||
std::string ProductName;
|
||||
// Tells whether this device is connected
|
||||
bool Connected;
|
||||
};
|
||||
|
||||
// a list of game device description
|
||||
typedef std::vector<CGameDeviceDesc> TDeviceDescVect;
|
||||
|
||||
/// for devices comparison. The 'Connected' field is ignored.
|
||||
inline bool operator == (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs)
|
||||
{
|
||||
return lhs.InstanceName == rhs.InstanceName && lhs.ProductName == rhs.ProductName;
|
||||
}
|
||||
//
|
||||
inline bool operator != (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This abstract a joystick or gamepad
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
struct IGameDevice : public IInputDevice
|
||||
{
|
||||
enum TAxis { XAxis = 0, YAxis, ZAxis, /* translation */
|
||||
RXAxis, RYAxis, RZAxis, /* rotations */
|
||||
MaxNumAxis
|
||||
};
|
||||
|
||||
/// Get a general description of this device
|
||||
virtual const CGameDeviceDesc &getDescription() const = 0;
|
||||
|
||||
///\name Controls presence
|
||||
//@{
|
||||
// returns the number of buttons available on this game device
|
||||
virtual uint getNumButtons() const = 0;
|
||||
/** Check if the given axe is present on this game device
|
||||
* NB : only absolute axis are managed
|
||||
*/
|
||||
virtual bool hasAxis(TAxis axis) const = 0;
|
||||
// Check the number of sliders presents on this game device
|
||||
virtual uint getNumSliders() const = 0;
|
||||
// Check the number of point of views controls present on this game device
|
||||
virtual uint getNumPOV() const = 0;
|
||||
//@}
|
||||
|
||||
///\name Controls names. Must ensure that controls are present before calling these methods.
|
||||
//@{
|
||||
virtual const char *getButtonName(uint index) const = 0;
|
||||
virtual const char *getAxisName(TAxis axis) const = 0;
|
||||
virtual const char *getSliderName(uint index) const = 0;
|
||||
virtual const char *getPOVName(uint index) const = 0;
|
||||
//@}
|
||||
|
||||
///\name Controls state. Must ensure that controls are present before calling these methods.
|
||||
//@{
|
||||
// Return true if the given button is pushed.
|
||||
virtual bool getButtonState(uint index) const = 0;
|
||||
// Return a value in [-1, 1] for a translation axis, or an orientation.
|
||||
virtual float getAxisValue(TAxis axis) const = 0;
|
||||
// Return a value in [0, 1]
|
||||
virtual float getSliderPos(uint index) const = 0;
|
||||
// Return a CCW angle in degrees
|
||||
virtual float getPOVAngle(uint index) const = 0;
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_GAME_DEVICE_H
|
||||
|
||||
/* End of GAME_device.h */
|
@ -1,209 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_GAME_DEVICE_EVENT_H
|
||||
#define NL_GAME_DEVICE_EVENT_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include "events.h"
|
||||
#include "game_device.h"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
struct IMouseDevice;
|
||||
struct IGameDevice;
|
||||
|
||||
const CClassId EventGDMouseMove(0x12142bc4, 0x43c73e74);
|
||||
const CClassId EventGDButtonDownId(0x57141957, 0x3efb143a);
|
||||
const CClassId EventGDButtonUpId(0x16105e06, 0x302536b2);
|
||||
const CClassId EventGDAxisMovedId(0x073306, 0x41173626);
|
||||
const CClassId EventGDSliderMovedId(0x68776586, 0x394a6916);
|
||||
const CClassId EventGDPOVChanged(0x362851b9, 0x395c4d61);
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
/// A raw mouse move message, expressed in mickeys (relative values)
|
||||
class CGDMouseMove : public CEvent
|
||||
{
|
||||
public:
|
||||
IMouseDevice *MD;
|
||||
sint X, Y;
|
||||
public:
|
||||
CGDMouseMove(IEventEmitter *emitter, IMouseDevice *md, sint x, sint y) : CEvent(emitter, EventGDMouseMove), MD(md), X(x), Y(y)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDMouseMove(*this);}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
/**
|
||||
* An event from a game device (joystick, joypad ...)
|
||||
*/
|
||||
class CGameDeviceEvent : public CEvent
|
||||
{
|
||||
public:
|
||||
/// the game device this event come from
|
||||
IGameDevice *GameDevice;
|
||||
public:
|
||||
CGameDeviceEvent(
|
||||
IGameDevice *gameDevice,
|
||||
IEventEmitter *emitter,
|
||||
const CClassId &classId
|
||||
)
|
||||
: CEvent(emitter, classId),
|
||||
GameDevice(gameDevice)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
/** A button state has changed
|
||||
*/
|
||||
class CGDButton : public CGameDeviceEvent
|
||||
{
|
||||
public:
|
||||
// index of the buttons that has been pushed
|
||||
uint ButtonIndex;
|
||||
bool Pushed;
|
||||
public:
|
||||
///
|
||||
CGDButton(
|
||||
uint buttonIndex,
|
||||
bool pushed,
|
||||
IGameDevice *gameDevice,
|
||||
IEventEmitter *emitter,
|
||||
const CClassId &classId
|
||||
)
|
||||
: CGameDeviceEvent(gameDevice, emitter, classId),
|
||||
ButtonIndex(buttonIndex),
|
||||
Pushed(pushed)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
/** A button has been pushed
|
||||
*/
|
||||
class CGDButtonDown : public CGDButton
|
||||
{
|
||||
public:
|
||||
///
|
||||
CGDButtonDown(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter)
|
||||
: CGDButton(buttonIndex, true, gameDevice, emitter, EventGDButtonDownId)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDButtonDown(*this);}
|
||||
};
|
||||
|
||||
//==========================================================================================
|
||||
/** A button has been released
|
||||
*/
|
||||
class CGDButtonUp : public CGDButton
|
||||
{
|
||||
public:
|
||||
///
|
||||
CGDButtonUp(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter)
|
||||
: CGDButton(buttonIndex, false, gameDevice, emitter, EventGDButtonUpId)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDButtonUp(*this);}
|
||||
};
|
||||
|
||||
//==========================================================================================
|
||||
/// An axis has moved
|
||||
class CGDAxisMoved : public CGameDeviceEvent
|
||||
{
|
||||
public:
|
||||
IGameDevice::TAxis Axis;
|
||||
// current position of the axis, ranges from -1.f to 1.f
|
||||
float Value;
|
||||
public:
|
||||
CGDAxisMoved(
|
||||
IGameDevice::TAxis axis,
|
||||
float value,
|
||||
IGameDevice *gameDevice,
|
||||
IEventEmitter *emitter
|
||||
)
|
||||
: CGameDeviceEvent(gameDevice, emitter, EventGDAxisMovedId),
|
||||
Axis(axis),
|
||||
Value(value)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDAxisMoved(*this);}
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
/// A slider position has changed
|
||||
class CGDSliderMoved : public CGameDeviceEvent
|
||||
{
|
||||
public:
|
||||
uint SliderIndex;
|
||||
// current position of the slider, ranges from 0.f to 1.f
|
||||
float SliderPos;
|
||||
public:
|
||||
CGDSliderMoved(
|
||||
float sliderPos,
|
||||
uint sliderIndex,
|
||||
IGameDevice *gameDevice,
|
||||
IEventEmitter *emitter
|
||||
)
|
||||
: CGameDeviceEvent(gameDevice, emitter, EventGDSliderMovedId),
|
||||
SliderIndex(sliderIndex),
|
||||
SliderPos(sliderPos)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDSliderMoved(*this);}
|
||||
};
|
||||
|
||||
//==========================================================================================
|
||||
/// A point of view control changed
|
||||
class CGDPOVChanged : public CGameDeviceEvent
|
||||
{
|
||||
public:
|
||||
uint POVIndex;
|
||||
bool Centered;
|
||||
// The POV angle, in degrees (CW)
|
||||
float POVAngle;
|
||||
public:
|
||||
CGDPOVChanged(
|
||||
bool centered,
|
||||
float povAngle,
|
||||
uint povIndex,
|
||||
IGameDevice *gameDevice,
|
||||
IEventEmitter *emitter
|
||||
)
|
||||
: CGameDeviceEvent(gameDevice, emitter, EventGDPOVChanged),
|
||||
POVIndex(povIndex),
|
||||
Centered(centered),
|
||||
POVAngle(povAngle)
|
||||
{}
|
||||
|
||||
virtual CEvent *clone() const {return new CGDPOVChanged(*this);}
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_GAME_DEVICE_EVENT_H
|
||||
|
||||
/* End of game_device_event.h */
|
@ -1,84 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_INPUT_DEVICE_H
|
||||
#define NL_INPUT_DEVICE_H
|
||||
|
||||
#include "types_nl.h"
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
|
||||
class CEventServer;
|
||||
class CInputDeviceServer;
|
||||
struct IInputDeviceEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Base class that wrap to a device
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
|
||||
struct IInputDevice
|
||||
{
|
||||
/** Set the buffer size for this device (the number of samples it can retains).
|
||||
* This return true if the size could be set
|
||||
*/
|
||||
virtual bool setBufferSize(uint size) = 0;
|
||||
/// Get the buffer size for this device
|
||||
virtual uint getBufferSize() const = 0;
|
||||
|
||||
///\name Device server specifics. You usually don't want to call these
|
||||
//@{
|
||||
/** For device server usage :
|
||||
* Called at the beginning of each events retrieval.
|
||||
* If a device doesn't support buffered datas, the state changes can be directly send to the event server.
|
||||
* The default does nothing.
|
||||
*/
|
||||
virtual void begin(CEventServer * /* server */) {}
|
||||
|
||||
/** For device server usage :
|
||||
* Poll all events from that device, and notify them to the given device server, so that they can be sorted between devices.
|
||||
* This retrieves messages, but do not process them.
|
||||
*/
|
||||
virtual void poll(CInputDeviceServer *dev) = 0;
|
||||
/** For device server usage :
|
||||
* Process an event (eventually update this device state), and translate the message to a IEventServerMessage
|
||||
*/
|
||||
virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server) = 0;
|
||||
/** For device server usage :
|
||||
* Says that the next message is for another device, or that it is the last message that will be received.
|
||||
* This allow to pack several messages in one (for example, to sum up mouse moves until a click occurs)
|
||||
* The default does nothing.
|
||||
* The next message can be used to get a time stamp for example. It may be NULL is no next message is available
|
||||
*/
|
||||
virtual void transitionOccured(CEventServer * /* server */, const IInputDeviceEvent * /* nextMessage */) {}
|
||||
//@}
|
||||
|
||||
// dtor
|
||||
virtual ~IInputDevice() {}
|
||||
};
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_INPUT_DEVICE_H
|
||||
|
||||
/* End of input_device.h */
|
@ -1,69 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_INPUT_DEVICE_MANAGER_H
|
||||
#define NL_INPUT_DEVICE_MANAGER_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include "game_device.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
|
||||
struct IMouseDevice;
|
||||
struct IKeyboardDevice;
|
||||
|
||||
|
||||
|
||||
struct EInputDevice : public Exception
|
||||
{
|
||||
EInputDevice(const char *reason) : Exception(reason) {}
|
||||
};
|
||||
|
||||
|
||||
/** Interface for objects that give low level access to devices (mouse, keyboard, joypads and joysticks).
|
||||
* Generally an object implementing this interface will send the appropriate events when a device is 'created'.
|
||||
* (Example of implementation : a direct input event emitter)
|
||||
*/
|
||||
struct IInputDeviceManager
|
||||
{
|
||||
// Test if a mouse has been created (by a call to getMouseDeivce)
|
||||
virtual bool isMouseCreated() = 0;
|
||||
/// Create the low level mouse device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained.
|
||||
virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice) = 0;
|
||||
/// remove the low level mouse
|
||||
virtual void releaseMouse() = 0;
|
||||
/// Create the low level keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained.
|
||||
virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice) = 0;
|
||||
/// remove the low level keyboard
|
||||
virtual void releaseKeyboard() = 0;
|
||||
// Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector
|
||||
virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice) = 0;
|
||||
// Create the given game device interface from its instance name. It also means that it will begin to sends events.
|
||||
virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice) = 0;
|
||||
// Release the given game device.
|
||||
virtual void releaseGameDevice(IGameDevice *gd) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_INPUT_DEVICE_MANAGER_H
|
||||
|
||||
/* End of device_manager.h */
|
@ -1,84 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_INPUT_DEVICE_SERVER_H
|
||||
#define NL_INPUT_DEVICE_SERVER_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
class CEventServer;
|
||||
struct IInputDevice;
|
||||
struct IInputDeviceEvent;
|
||||
|
||||
|
||||
/** Base class for an input device server. Unlike an event server, it manages several devices, and can sort their events (by date for example).
|
||||
* It keeps a list of active devices.
|
||||
* It can poll datas from every active device.
|
||||
* It can sort devices messages to submit them in correct order to a CEventServer.
|
||||
*/
|
||||
|
||||
class CInputDeviceServer
|
||||
{
|
||||
public:
|
||||
/// register a device into this device server.
|
||||
void registerDevice(IInputDevice *device);
|
||||
/// remove a device from this server (but does not delete it).
|
||||
void removeDevice(IInputDevice *device);
|
||||
// returns the number of registered devices
|
||||
uint getNumDevices() const { return (uint)_Devices.size(); }
|
||||
// return a device
|
||||
IInputDevice *getDevice(uint index) { return _Devices[index]; }
|
||||
/// Test whether the given device is handled by this server.
|
||||
bool isDevice(IInputDevice *device) const;
|
||||
/// Retrieve datas from the devices, and submit them to the given CEventServer.
|
||||
void poll(CEventServer *server);
|
||||
/// Allow an input device to register an event. The event will then be deleted by this server
|
||||
void submitEvent(IInputDeviceEvent *deviceEvent);
|
||||
// dtor
|
||||
virtual ~CInputDeviceServer() {}
|
||||
private:
|
||||
typedef std::vector<IInputDevice *> TDeviceCont;
|
||||
typedef std::vector<IInputDeviceEvent *> TEventCont;
|
||||
private:
|
||||
TDeviceCont _Devices;
|
||||
TEventCont _Events;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** An event from an input device.
|
||||
*/
|
||||
struct IInputDeviceEvent
|
||||
{
|
||||
IInputDevice *Emitter; // the input device that emitted that event
|
||||
// Used to sort events by time stamp.
|
||||
virtual bool operator < (const IInputDeviceEvent &IInputDeviceEvent) const = 0;
|
||||
virtual ~IInputDeviceEvent() {}
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_INPUT_DEVICE_SERVER_H
|
||||
|
||||
/* End of input_device_server.h */
|
@ -1,63 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_KEYBOARD_DEVICE_H
|
||||
#define NL_KEYBOARD_DEVICE_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include "events.h"
|
||||
#include "input_device.h"
|
||||
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
/** Gives access to low level keyboard parameters
|
||||
* - 'Shift' messages are replaced by RShift and LShift msg.
|
||||
* - 'Control' messages are replaced by 'RControl' and 'LControl' msg.
|
||||
* - 'Menu' (alternate) messages are replaced by 'RMenu' and 'LMenu' msg.
|
||||
*/
|
||||
struct IKeyboardDevice : public IInputDevice
|
||||
{
|
||||
/// Max number of supported keys
|
||||
enum { NumKeys = 256 };
|
||||
/// Get the delay before key repeat, in milliseconds
|
||||
virtual uint getKeyRepeatDelay() const = 0;
|
||||
/// Get the delay before key repeat, in milliseconds
|
||||
virtual void setKeyRepeatDelay(uint delay) = 0;
|
||||
/// Get the period before key repeat, in milliseconds
|
||||
virtual uint getKeyRepeatPeriod() const = 0;
|
||||
/// Get the period before key repeat, in milliseconds
|
||||
virtual void setKeyRepeatPeriod(uint period) = 0;
|
||||
/// Set a set of keys for which repetition is disabled
|
||||
virtual void disableRepetition(const TKey *keyTab, uint numKey) = 0;
|
||||
/// Get the number of disabled keys
|
||||
virtual uint getNumDisabledRepetition() const = 0;
|
||||
/** Get the disabled keys and stores in the given tab.
|
||||
* NB: must ensure the destination table has the right size
|
||||
* \see getNumDisabledKeys()
|
||||
*/
|
||||
virtual void getDisabledRepetitions(TKey *destTab) const = 0;
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_KEYBOARD_DEVICE_H
|
||||
|
||||
/* End of keyboard_device.h */
|
@ -1,130 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_MOUSE_DEVICE_H
|
||||
#define NL_MOUSE_DEVICE_H
|
||||
|
||||
#include "types_nl.h"
|
||||
#include "input_device.h"
|
||||
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
class CRect;
|
||||
|
||||
/// An interface to a low level mouse device
|
||||
struct IMouseDevice : public IInputDevice
|
||||
{
|
||||
enum TAxisMode { Raw, Clamped, AxisModeLast };
|
||||
enum TAxis { XAxis = 0, YAxis = 1, AxisLast };
|
||||
enum TMessageMode { NormalMode, RawMode, MessageModeLast };
|
||||
|
||||
///\name Messages
|
||||
//@{
|
||||
/** Tells what messages should be sent :
|
||||
* DEFAULT is 'raw' messages
|
||||
* Raw messages : - no clamping nor frames applied
|
||||
* - no speed applied
|
||||
* - no factor applied
|
||||
* - CGDMouseMove messages are sent
|
||||
* - Move expressed in mickeys
|
||||
* Normal messages : - CEventMouseMove messages are sent
|
||||
* - A frame may clamp one or both axis
|
||||
* - The mouse speed can be changed
|
||||
*/
|
||||
virtual void setMessagesMode(TMessageMode mode) = 0;
|
||||
/// retrieve what kinds of messages are sent
|
||||
virtual TMessageMode getMessagesMode() const = 0;
|
||||
//@}
|
||||
|
||||
///\name Mouse MOVE, valid only
|
||||
//@{
|
||||
/** Set the mode of axis of the mouse. This can be raw, or clamped. In clamped mode, a frame is used to limit the move.
|
||||
* NB : invalid in raw message mode
|
||||
* \see setMouseFrame(const CRect &rect)
|
||||
*/
|
||||
virtual void setMouseMode(TAxis axis, TAxisMode axisMode) = 0;
|
||||
/** returns the mode of the mouse for the given axis.
|
||||
* NB : invalid in raw message mode
|
||||
*/
|
||||
virtual TAxisMode getMouseMode(TAxis axis) const = 0;
|
||||
/** Set the mouse speed. It must be in the ]0, +inf] range, 1 gives the natural mouse speed.
|
||||
* NB : invalid in raw message mode
|
||||
*/
|
||||
virtual void setMouseSpeed(float speed) = 0;
|
||||
/** Get the mouse speed.
|
||||
* NB : invalid in raw message mode
|
||||
*/
|
||||
virtual float getMouseSpeed() const = 0;
|
||||
/** Set the mouse acceleration. It is the threshold in mickey, when start the acceleration. 0 means not acceleration.
|
||||
*/
|
||||
virtual void setMouseAcceleration(uint speed) = 0;
|
||||
/** Get the mouse acceleration.
|
||||
*/
|
||||
virtual uint getMouseAcceleration() const = 0;
|
||||
/** Set the current frame in which the mouse can move, expressed in pixels.
|
||||
* NB do not forget to call setMouseFactors if you want the results to be reported in the 0-1 range.
|
||||
* NB : invalid in raw message mode.
|
||||
* \see setMouseFactors
|
||||
*/
|
||||
virtual void setMouseFrame(const CRect &rect) = 0;
|
||||
/** Gives factor by which the mouse coordinates must be multiplied before an event is sent.
|
||||
* The default factor is 1.
|
||||
* NB : invalid in raw message mode.
|
||||
*
|
||||
* Example : this set a frame of 800x600 and reports event in the [0, 1] range.
|
||||
* \code
|
||||
* mouse->setMouseFrame(800, 600);
|
||||
* mouse->setMouseMode(XAxis, IMouseDevice::Clamped);
|
||||
* mouse->setMouseMode(YAxis, IMouseDevice::Clamped);
|
||||
* mouse->setFactors(1.f / 800, 1.f / 600);
|
||||
* \endcode
|
||||
*/
|
||||
virtual void setFactors(float xFactor, float yFactor) = 0;
|
||||
/** Get the x factor, use to multiply the mouse position before an event is sent.
|
||||
* NB : invalid in raw message mode.
|
||||
* \see setFactors()
|
||||
*/
|
||||
virtual float getXFactor() const = 0;
|
||||
/** Get the y factor, use to multiply the mouse position before an event is sent.
|
||||
* NB : invalid in raw message mode.
|
||||
* \see setFactors()
|
||||
*/
|
||||
virtual float getYFactor() const = 0;
|
||||
//@}
|
||||
|
||||
// Get the current frame used for limiting mouse movements
|
||||
virtual const CRect &getMouseFrame() const = 0;
|
||||
// Set the maximum delay for a double click to be taken in account (in ms).
|
||||
virtual void setDoubleClickDelay(uint ms) = 0;
|
||||
// Get the maximum delay for double click (in ms)
|
||||
virtual uint getDoubleClickDelay() const = 0;
|
||||
// Force the position of the mouse, expressed in pixels
|
||||
virtual void setMousePos(float x, float y) = 0;
|
||||
|
||||
/// From a delta of a mouse position input (eg from CEventMouseMove), deduce delta in mickeys (eg: like received from a CGDMouseMove)
|
||||
virtual void convertStdMouseMoveInMickeys(float &dx, float &dy) const = 0;
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_MOUSE_DEVICE_H
|
||||
|
||||
/* End of u_mouse_device.h */
|
@ -1,354 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "stdmisc.h"
|
||||
|
||||
#include "nel/misc/di_event_emitter.h"
|
||||
#include "nel/misc/events.h"
|
||||
#include "nel/misc/win_event_emitter.h"
|
||||
//
|
||||
#include "di_mouse_device.h"
|
||||
#include "di_keyboard_device.h"
|
||||
#include "di_game_device.h"
|
||||
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
static const char DirectInputLibName[] = "dinput8.dll";
|
||||
|
||||
/////////////////////////////////
|
||||
// CDIEventEmitter statics //
|
||||
/////////////////////////////////
|
||||
|
||||
HMODULE CDIEventEmitter::_DirectInputLibHandle = 0;
|
||||
CDIEventEmitter::TPDirectInput8Create CDIEventEmitter::_PDirectInput8Create = NULL;
|
||||
uint CDIEventEmitter::_NumCreatedInterfaces = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////
|
||||
// CDIEventEmitter implementation //
|
||||
////////////////////////////////////
|
||||
|
||||
|
||||
//======================================================
|
||||
CDIEventEmitter::CDIEventEmitter(HWND hwnd, CWinEventEmitter *we)
|
||||
:
|
||||
_hWnd(hwnd),
|
||||
_WE(we),
|
||||
_DInput8(NULL),
|
||||
_Keyboard(NULL),
|
||||
_Mouse(NULL),
|
||||
_ButtonsFlags(noButton)
|
||||
{
|
||||
}
|
||||
//======================================================
|
||||
CDIEventEmitter::~CDIEventEmitter()
|
||||
{
|
||||
releaseMouse();
|
||||
releaseKeyboard();
|
||||
// release all devices
|
||||
while (_DeviceServer.getNumDevices() != 0)
|
||||
{
|
||||
IInputDevice *dev = _DeviceServer.getDevice(0);
|
||||
_DeviceServer.removeDevice(dev);
|
||||
delete dev;
|
||||
}
|
||||
if (_DInput8) _DInput8->Release();
|
||||
-- _NumCreatedInterfaces;
|
||||
if (_NumCreatedInterfaces == 0) unloadLib();
|
||||
}
|
||||
|
||||
//======================================================
|
||||
CDIEventEmitter *CDIEventEmitter::create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we) throw(EDirectInput)
|
||||
{
|
||||
if (!loadLib()) throw EDirectInputLibNotFound();
|
||||
std::auto_ptr<CDIEventEmitter> dxee(new CDIEventEmitter(hwnd, we));
|
||||
HRESULT result = _PDirectInput8Create(hinst,
|
||||
DIRECTINPUT_VERSION,
|
||||
IID_IDirectInput8A,
|
||||
(void **) &dxee->_DInput8,
|
||||
NULL);
|
||||
if (result != DI_OK) throw EDirectInputInitFailed();
|
||||
|
||||
// ok, everything's fine, commit changes
|
||||
++_NumCreatedInterfaces;
|
||||
return dxee.release();
|
||||
}
|
||||
|
||||
|
||||
//======================================================
|
||||
bool CDIEventEmitter::loadLib()
|
||||
{
|
||||
if (_DirectInputLibHandle != 0) return true; // library already loaded ?
|
||||
HMODULE handle = ::LoadLibrary(DirectInputLibName);
|
||||
if (handle == 0) return false;
|
||||
// try to get the creation function
|
||||
TPDirectInput8Create cf = (TPDirectInput8Create) ::GetProcAddress(handle, "DirectInput8Create");
|
||||
if (!cf)
|
||||
{
|
||||
::FreeLibrary(handle);
|
||||
return false;
|
||||
}
|
||||
// commit changes
|
||||
_DirectInputLibHandle = handle;
|
||||
_PDirectInput8Create = cf;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//======================================================
|
||||
void CDIEventEmitter::unloadLib()
|
||||
{
|
||||
nlassert(_DirectInputLibHandle != 0);
|
||||
::FreeLibrary(_DirectInputLibHandle);
|
||||
_DirectInputLibHandle = 0;
|
||||
_PDirectInput8Create = NULL;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIEventEmitter::poll(CEventServer *server)
|
||||
{
|
||||
if (_WE) _ButtonsFlags = _WE->buildFlags();
|
||||
if (!server)
|
||||
server=&_InternalServer;
|
||||
_DeviceServer.poll(server);
|
||||
}
|
||||
|
||||
|
||||
//======================================================
|
||||
TMouseButton CDIEventEmitter::buildButtonsFlags() const
|
||||
{
|
||||
uint mouseFlags;
|
||||
uint keybFlags;
|
||||
//
|
||||
if (_Mouse) // takes the flags from the direct input mouse
|
||||
{
|
||||
mouseFlags = (_Mouse->getButton(0) ? leftButton : 0)
|
||||
| (_Mouse->getButton(1) ? rightButton : 0)
|
||||
| (_Mouse->getButton(2) ? middleButton : 0);
|
||||
}
|
||||
else // takes the flags from the system mouse
|
||||
{
|
||||
mouseFlags = _ButtonsFlags & (leftButton | rightButton | middleButton);
|
||||
}
|
||||
//
|
||||
if (_Keyboard) // takes the flags from the direct input keyboard
|
||||
{
|
||||
keybFlags = (_Keyboard->ShiftPressed ? shiftButton : 0)
|
||||
| (_Keyboard->AltPressed ? altButton : 0)
|
||||
| (_Keyboard->CtrlPressed ? ctrlButton : 0);
|
||||
}
|
||||
else // takes the flags from the system keyboard
|
||||
{
|
||||
keybFlags = _ButtonsFlags & (shiftButton | altButton | ctrlButton);
|
||||
}
|
||||
return (TMouseButton) (keybFlags | mouseFlags);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
IMouseDevice *CDIEventEmitter::getMouseDevice(bool hardware) throw(EInputDevice)
|
||||
{
|
||||
if (_Mouse) return _Mouse; // already created ?
|
||||
try
|
||||
{
|
||||
// Create a mouse
|
||||
std::auto_ptr<CDIMouse> mouse(CDIMouse::createMouseDevice(_DInput8, _hWnd, this, hardware, _WE));
|
||||
// register to the device server
|
||||
_DeviceServer.registerDevice(mouse.get());
|
||||
_Mouse = mouse.get();
|
||||
return mouse.release();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (_WE) _WE->enableMouseEvents(true);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIEventEmitter::releaseMouse()
|
||||
{
|
||||
if (!_Mouse) return;
|
||||
// reupdate the system keyboard flags
|
||||
if (_WE)
|
||||
{
|
||||
_WE->resetButtonFlagState();
|
||||
_WE->enableMouseEvents(true);
|
||||
}
|
||||
// remove the device
|
||||
_DeviceServer.removeDevice(_Mouse);
|
||||
delete _Mouse;
|
||||
_Mouse = NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
IKeyboardDevice *CDIEventEmitter::getKeyboardDevice() throw(EInputDevice)
|
||||
{
|
||||
if (_Keyboard) return _Keyboard;
|
||||
try
|
||||
{
|
||||
// create a keyboard
|
||||
std::auto_ptr<CDIKeyboard> keyboard(CDIKeyboard::createKeyboardDevice(_DInput8, _hWnd, this, _WE));
|
||||
// register to the device server
|
||||
_DeviceServer.registerDevice(keyboard.get());
|
||||
_Keyboard = keyboard.get();
|
||||
return keyboard.release();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (_WE) _WE->enableKeyboardEvents(true);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
void CDIEventEmitter::releaseKeyboard()
|
||||
{
|
||||
if (!_Keyboard) return;
|
||||
// reupdate the system keyboard flags
|
||||
if (_WE)
|
||||
{
|
||||
_WE->resetButtonFlagState();
|
||||
_WE->enableKeyboardEvents(true);
|
||||
}
|
||||
//
|
||||
_DeviceServer.removeDevice(_Keyboard);
|
||||
delete _Keyboard;
|
||||
_Keyboard = NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
void CDIEventEmitter::submitEvents(CEventServer &server, bool allWindows)
|
||||
{
|
||||
_InternalServer.setServer(&server);
|
||||
_InternalServer.pump(allWindows);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
void CDIEventEmitter::emulateMouseRawMode(bool enable)
|
||||
{
|
||||
nlerror("no raw mode emulation on windows, the CDIMouse has a real raw mode");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
/// Tool fct to retrieve the game devices.
|
||||
static BOOL CALLBACK DIEnumDevicesDescCallback
|
||||
(
|
||||
LPCDIDEVICEINSTANCE lpddi,
|
||||
LPVOID pvRef
|
||||
)
|
||||
{
|
||||
CGameDeviceDesc desc;
|
||||
desc.InstanceName = lpddi->tszInstanceName;
|
||||
desc.ProductName = lpddi->tszProductName;
|
||||
switch (lpddi->wUsage & 0xff)
|
||||
{
|
||||
case DI8DEVTYPE_JOYSTICK: desc.DevType = CGameDeviceDesc::Joystick; break;
|
||||
case DI8DEVTYPE_GAMEPAD: desc.DevType = CGameDeviceDesc::GamePad; break;
|
||||
default: desc.DevType = CGameDeviceDesc::DontKnow; break;
|
||||
}
|
||||
TDeviceDescVect *dv = (TDeviceDescVect *) pvRef;
|
||||
dv->push_back(desc);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
/// Tool fct to retrieve the game devices GUID
|
||||
static BOOL CALLBACK DIEnumDevicesGUIDCallback
|
||||
(
|
||||
LPCDIDEVICEINSTANCE lpddi,
|
||||
LPVOID pvRef
|
||||
)
|
||||
{
|
||||
std::vector<GUID> *gv = (std::vector<GUID> *) pvRef;
|
||||
gv->push_back(lpddi->guidInstance);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
void CDIEventEmitter::enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice)
|
||||
{
|
||||
uint k;
|
||||
nlassert(_DInput8);
|
||||
descs.clear();
|
||||
// enum all devices of interest
|
||||
_DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &descs, DIEDFL_ALLDEVICES);
|
||||
for (k = 0; k < descs.size(); ++k) descs[k].Connected = false;
|
||||
// enum all connected devices
|
||||
static TDeviceDescVect connecteds;
|
||||
_DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &connecteds, DIEDFL_ATTACHEDONLY);
|
||||
// see which devices are connected
|
||||
for (k = 0; k < connecteds.size(); ++k)
|
||||
{
|
||||
TDeviceDescVect::iterator it = std::find(descs.begin(), descs.end(), connecteds[k]);
|
||||
it->Connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
IGameDevice *CDIEventEmitter::createGameDevice(const std::string &instanceName) throw(EInputDevice)
|
||||
{
|
||||
static TDeviceDescVect deviceDescs;
|
||||
static std::vector<GUID> deviceGUID;
|
||||
|
||||
nlassert(_DInput8);
|
||||
enumerateGameDevice(deviceDescs);
|
||||
// get the ID for each device
|
||||
deviceGUID.clear();
|
||||
HRESULT r = _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesGUIDCallback, (LPVOID) &deviceGUID, DIEDFL_ALLDEVICES);
|
||||
nlassert(r == DI_OK);
|
||||
nlassert(deviceDescs.size() == deviceGUID.size());
|
||||
|
||||
// search the device that match the instance name
|
||||
for (uint k = 0; k < deviceDescs.size(); ++k)
|
||||
{
|
||||
if (deviceDescs[k].InstanceName == instanceName)
|
||||
{
|
||||
std::auto_ptr<CDIGameDevice> gd(CDIGameDevice::createGameDevice(_DInput8, _hWnd, this, deviceDescs[k], deviceGUID[k]));
|
||||
// insert in the device server
|
||||
_DeviceServer.registerDevice(gd.get());
|
||||
return gd.release();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
void CDIEventEmitter::releaseGameDevice(IGameDevice *gd)
|
||||
{
|
||||
nlassert(gd);
|
||||
CDIGameDevice *digd = safe_cast<CDIGameDevice *>(gd);
|
||||
_DeviceServer.removeDevice(digd);
|
||||
delete gd;
|
||||
}
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
@ -1,523 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "stdmisc.h"
|
||||
#include "di_game_device.h"
|
||||
#include "nel/misc/game_device_events.h"
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
//============================================================================
|
||||
CDIGameDevice::CDIGameDevice() : _Device(NULL)
|
||||
{
|
||||
::memset(&_CurrentState, 0, sizeof(_CurrentState));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CDIGameDevice::~CDIGameDevice()
|
||||
{
|
||||
if (_Device)
|
||||
{
|
||||
_Device->Unacquire();
|
||||
_Device->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CDIGameDevice *CDIGameDevice::createGameDevice(IDirectInput8 *di8,
|
||||
HWND hwnd,
|
||||
CDIEventEmitter *diEventEmitter,
|
||||
const CGameDeviceDesc &desc,
|
||||
REFGUID rguid) throw(EDirectInput)
|
||||
{
|
||||
nlassert(diEventEmitter);
|
||||
nlassert(di8);
|
||||
std::auto_ptr<CDIGameDevice> dev(new CDIGameDevice);
|
||||
//
|
||||
|
||||
HRESULT r = di8->CreateDevice(rguid, &dev->_Device, NULL);
|
||||
if (r != DI_OK) throw EDirectInputGameDeviceNotCreated();
|
||||
|
||||
r = dev->_Device->SetDataFormat(pJoyDataFormat);
|
||||
nlassert(r == DI_OK);
|
||||
//
|
||||
r = dev->_Device->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
|
||||
if (r != DI_OK) throw EDirectInputCooperativeLevelFailed();
|
||||
//
|
||||
//
|
||||
dev->_Desc = desc;
|
||||
dev->_EventEmitter = diEventEmitter;
|
||||
dev->querryControls();
|
||||
return dev.release();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void CDIGameDevice::begin(CEventServer *server)
|
||||
{
|
||||
nlassert(_Device);
|
||||
HRESULT r;
|
||||
r = _Device->Poll();
|
||||
if (r == DIERR_INPUTLOST || r == DIERR_NOTACQUIRED)
|
||||
{
|
||||
r = _Device->Acquire();
|
||||
if (r != DI_OK) return;
|
||||
r = _Device->Poll();
|
||||
if (r != DI_OK) return;
|
||||
}
|
||||
|
||||
CDIJoyState newState;
|
||||
r = _Device->GetDeviceState(sizeof(CDIJoyState), &newState);
|
||||
if (r != DI_OK) return;
|
||||
|
||||
uint k;
|
||||
//////////
|
||||
// Axis //
|
||||
//////////
|
||||
for (k = 0; k < MaxNumAxis; ++k)
|
||||
{
|
||||
CAxis &axis = _Axis[k];
|
||||
if (axis.Present)
|
||||
{
|
||||
|
||||
if (((LONG *) &newState)[k] != ((LONG *) &_CurrentState)[k]) // state changed ?
|
||||
{
|
||||
// update position
|
||||
axis.Value = 2.f * (((LONG *) &newState)[k] - axis.Min) / (float) (axis.Max - axis.Min) - 1.f;
|
||||
// create event
|
||||
CGDAxisMoved *event = new CGDAxisMoved((IGameDevice::TAxis) k, axis.Value, this, _EventEmitter);
|
||||
// update state
|
||||
((LONG *) &_CurrentState)[k] = ((LONG *) &newState)[k];
|
||||
//
|
||||
server->postEvent(event);
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////
|
||||
// Buttons //
|
||||
/////////////
|
||||
for (k = 0; k < _Buttons.size(); ++k)
|
||||
{
|
||||
CButton &bt = _Buttons[k];
|
||||
if ((newState.rgbButtons[k] & 0x80) != (_CurrentState.rgbButtons[k] & 0x80))
|
||||
{
|
||||
bool pushed = (newState.rgbButtons[k] & 0x80) != 0;
|
||||
// update the state of the button
|
||||
bt.Pushed = pushed;
|
||||
CGDButton *event;
|
||||
if (pushed) event = new CGDButtonDown(k, this, _EventEmitter);
|
||||
else event = new CGDButtonUp(k, this, _EventEmitter);
|
||||
// update state
|
||||
_CurrentState.rgbButtons[k] = newState.rgbButtons[k];
|
||||
server->postEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////
|
||||
// Sliders //
|
||||
/////////////
|
||||
for (k = 0; k < _Sliders.size(); ++k)
|
||||
{
|
||||
CSlider &sl = _Sliders[k];
|
||||
if (newState.rglSlider[k] != _CurrentState.rglSlider[k]) // state changed ?
|
||||
{
|
||||
// update position
|
||||
sl.Pos = ( newState.rglSlider[k] - sl.Min) / (float) (sl.Max - sl.Min);
|
||||
// create event
|
||||
CGDSliderMoved *event = new CGDSliderMoved(sl.Pos, k, this, _EventEmitter);
|
||||
// update state
|
||||
_CurrentState.rglSlider[k] = newState.rglSlider[k];
|
||||
//
|
||||
server->postEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
// POVs //
|
||||
//////////
|
||||
for (k = 0; k < _POVs.size(); ++k)
|
||||
{
|
||||
CPOV &pov = _POVs[k];
|
||||
if (newState.rgdwPOV[k] != _CurrentState.rgdwPOV[k]) // state changed ?
|
||||
{
|
||||
DWORD value = newState.rgdwPOV[k];
|
||||
|
||||
pov.Centered = (LOWORD(value) == 0xFFFF);
|
||||
if (!pov.Centered)
|
||||
{
|
||||
// update position
|
||||
pov.Angle = value / 100.f;
|
||||
}
|
||||
// create event
|
||||
CGDPOVChanged *event = new CGDPOVChanged(pov.Centered, pov.Angle, k, this, _EventEmitter);
|
||||
// update state
|
||||
_CurrentState.rgdwPOV[k] = newState.rgdwPOV[k];
|
||||
//
|
||||
server->postEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void CDIGameDevice::poll(CInputDeviceServer *dev)
|
||||
{
|
||||
// buffered datas not supported
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void CDIGameDevice::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
|
||||
{
|
||||
// should never be called, buffered datas not supported
|
||||
nlassert(0);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
/** Tool fct : tests whether a DIDEVICEOBJECTINSTANCE contains a controls name and return it,
|
||||
* or build a default one
|
||||
*/
|
||||
static void BuildCtrlName(LPCDIDEVICEOBJECTINSTANCE lpddoi,
|
||||
std::string &destName,
|
||||
const char *defaultName)
|
||||
{
|
||||
if (lpddoi->dwSize >= offsetof(DIDEVICEOBJECTINSTANCE, tszName) + sizeof(TCHAR[MAX_PATH]))
|
||||
{
|
||||
destName = (::strcmp("N/A", lpddoi->tszName) == 0) ? defaultName
|
||||
: lpddoi->tszName;
|
||||
}
|
||||
else
|
||||
{
|
||||
destName = defaultName;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// A callback to enumerate the controls of a device
|
||||
BOOL CALLBACK DIEnumDeviceObjectsCallback
|
||||
(
|
||||
LPCDIDEVICEOBJECTINSTANCE lpddoi,
|
||||
LPVOID pvRef
|
||||
)
|
||||
{
|
||||
|
||||
CDIGameDevice *gd = (CDIGameDevice *) pvRef;
|
||||
return gd->processEnumObject(lpddoi);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=======================================================================
|
||||
// get range for an axis
|
||||
static HRESULT GetDIAxisRange(LPDIRECTINPUTDEVICE8 device, uint offset, DWORD type, sint &min, sint &max)
|
||||
{
|
||||
DIPROPRANGE diprg;
|
||||
diprg.diph.dwSize = sizeof(DIPROPRANGE);
|
||||
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
diprg.diph.dwHow = DIPH_BYOFFSET;
|
||||
diprg.diph.dwObj = offset;
|
||||
|
||||
// Set the range for the axis
|
||||
HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
|
||||
|
||||
if (r == DIERR_OBJECTNOTFOUND)
|
||||
{
|
||||
// try from its ID
|
||||
diprg.diph.dwHow = DIPH_BYID;
|
||||
diprg.diph.dwObj = type;
|
||||
|
||||
// Set the range for the axis
|
||||
HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
|
||||
if (r != DI_OK)
|
||||
{
|
||||
// setup default values ...
|
||||
min = 0;
|
||||
max = 65535;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else if (r != DI_OK)
|
||||
{
|
||||
min = 0;
|
||||
max = 65535;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* switch (r)
|
||||
{
|
||||
default:
|
||||
nlinfo("ok");
|
||||
break;
|
||||
case DIERR_INVALIDPARAM:
|
||||
nlinfo("invalid param");
|
||||
break;
|
||||
case DIERR_NOTEXCLUSIVEACQUIRED:
|
||||
nlinfo("DIERR_NOTEXCLUSIVEACQUIRED");
|
||||
break;
|
||||
case DIERR_NOTINITIALIZED:
|
||||
nlinfo("DIERR_NOTINITIALIZED");
|
||||
break;
|
||||
case DIERR_OBJECTNOTFOUND:
|
||||
nlinfo("DIERR_OBJECTNOTFOUND");
|
||||
break;
|
||||
case DIERR_UNSUPPORTED:
|
||||
nlinfo("DIERR_UNSUPPORTED");
|
||||
break;
|
||||
}*/
|
||||
|
||||
|
||||
min = (sint) diprg.lMin;
|
||||
max = (sint) diprg.lMax;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
BOOL CDIGameDevice::processEnumObject(LPCDIDEVICEOBJECTINSTANCE lpddoi)
|
||||
{
|
||||
// the dwSize field gives us the size of the objects, and the available fields
|
||||
// has this object the field guidType and dwOfs ?
|
||||
if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwOfs) + sizeof(DWORD)) return DIENUM_CONTINUE;
|
||||
|
||||
uint ctrlType = (uint) lpddoi->dwType;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// axis, we only support absolute ones //
|
||||
///////////////////////////////////////////
|
||||
|
||||
if (lpddoi->guidType == GUID_XAxis && (ctrlType & DIDFT_ABSAXIS) )
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[XAxis].Min, _Axis[XAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[XAxis].Name, "X Axis");
|
||||
_Axis[XAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
if (lpddoi->guidType == GUID_YAxis && (ctrlType & DIDFT_ABSAXIS))
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[YAxis].Min, _Axis[YAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[YAxis].Name, "Y Axis");
|
||||
_Axis[YAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
if (lpddoi->guidType == GUID_ZAxis && (ctrlType & DIDFT_ABSAXIS))
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[ZAxis].Min, _Axis[ZAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[ZAxis].Name, "Z Axis");
|
||||
_Axis[ZAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
if (lpddoi->guidType == GUID_RxAxis && (ctrlType & DIDFT_ABSAXIS))
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RXAxis].Min, _Axis[RXAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[RXAxis].Name, "RX Axis");
|
||||
_Axis[RXAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
if (lpddoi->guidType == GUID_RyAxis && (ctrlType & DIDFT_ABSAXIS))
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RYAxis].Min, _Axis[RYAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[RYAxis].Name, "RY Axis");
|
||||
_Axis[RYAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
if (lpddoi->guidType == GUID_RzAxis && (ctrlType & DIDFT_ABSAXIS))
|
||||
{
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RZAxis].Min, _Axis[RZAxis].Max);
|
||||
BuildCtrlName(lpddoi, _Axis[RZAxis].Name, "RZ Axis");
|
||||
_Axis[RZAxis].Present = true;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
// has this object the field dwType ?
|
||||
if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwType) + sizeof(DWORD)) return DIENUM_CONTINUE;
|
||||
|
||||
|
||||
uint type = lpddoi->dwType;
|
||||
/////////////
|
||||
// Buttons //
|
||||
/////////////
|
||||
if (type & DIDFT_BUTTON)
|
||||
{
|
||||
if (_Buttons.size() < MaxNumButtons)
|
||||
{
|
||||
_Buttons.push_back(CButton());
|
||||
uint buttonIndex = (uint)_Buttons.size() - 1;
|
||||
char defaultButtonName[32];
|
||||
smprintf(defaultButtonName, 32, "BUTTON %d", buttonIndex + 1);
|
||||
BuildCtrlName(lpddoi, _Buttons[buttonIndex].Name, defaultButtonName);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////
|
||||
// Sliders //
|
||||
/////////////
|
||||
if (type & DIDFT_ABSAXIS)
|
||||
{
|
||||
if (_Sliders.size() < MaxNumSliders)
|
||||
{
|
||||
_Sliders.push_back(CSlider());
|
||||
uint sliderIndex = (uint)_Sliders.size() - 1;
|
||||
GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Sliders[sliderIndex].Min, _Sliders[sliderIndex].Max);
|
||||
char defaultSliderName[32];
|
||||
smprintf(defaultSliderName, 32, "SLIDER %d", sliderIndex + 1);
|
||||
BuildCtrlName(lpddoi, _Sliders[sliderIndex].Name, defaultSliderName);
|
||||
}
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//////////
|
||||
// POVs //
|
||||
//////////
|
||||
if (type & DIDFT_POV)
|
||||
{
|
||||
if (_POVs.size() < MaxNumPOVs)
|
||||
{
|
||||
_POVs.push_back(CPOV());
|
||||
uint povIndex = (uint)_POVs.size() - 1;
|
||||
char defaultPOVName[16];
|
||||
smprintf(defaultPOVName, 16, "POV %d", povIndex + 1);
|
||||
BuildCtrlName(lpddoi, _POVs[povIndex].Name, defaultPOVName);
|
||||
}
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void CDIGameDevice::querryControls()
|
||||
{
|
||||
HRESULT r = _Device->EnumObjects(&DIEnumDeviceObjectsCallback, (LPVOID) this, DIDFT_ALL);
|
||||
nlassert(r == DI_OK);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool CDIGameDevice::setBufferSize(uint size)
|
||||
{
|
||||
// uisually not supported by this kind of devices
|
||||
return false;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
uint CDIGameDevice::getBufferSize() const
|
||||
{
|
||||
// uisually not supported by this kind of devices
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
uint CDIGameDevice::getNumButtons() const
|
||||
{
|
||||
return (uint)_Buttons.size();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool CDIGameDevice::hasAxis(TAxis axis) const
|
||||
{
|
||||
nlassert(axis < MaxNumAxis);
|
||||
return _Axis[axis].Present;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
uint CDIGameDevice::getNumSliders() const
|
||||
{
|
||||
return (uint)_Sliders.size();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
uint CDIGameDevice::getNumPOV() const
|
||||
{
|
||||
return (uint)_POVs.size();
|
||||
}
|
||||
//============================================================================
|
||||
const char *CDIGameDevice::getButtonName(uint index) const
|
||||
{
|
||||
nlassert(index < _Buttons.size());
|
||||
return _Buttons[index].Name.c_str();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
const char *CDIGameDevice::getAxisName(TAxis axis) const
|
||||
{
|
||||
nlassert(axis < MaxNumAxis);
|
||||
nlassert(hasAxis(axis)); // ! Not an axis of this device
|
||||
return _Axis[axis].Name.c_str();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
const char *CDIGameDevice::getSliderName(uint index) const
|
||||
{
|
||||
nlassert(index < _Sliders.size());
|
||||
return _Sliders[index].Name.c_str();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
const char *CDIGameDevice::getPOVName(uint index) const
|
||||
{
|
||||
nlassert(index < _POVs.size());
|
||||
return _POVs[index].Name.c_str();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
bool CDIGameDevice::getButtonState(uint index) const
|
||||
{
|
||||
nlassert(index < _Buttons.size());
|
||||
return _Buttons[index].Pushed;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
float CDIGameDevice::getAxisValue(TAxis axis) const
|
||||
{
|
||||
nlassert(axis < MaxNumAxis);
|
||||
nlassert(hasAxis(axis)); // ! Not an axis of this device
|
||||
return _Axis[axis].Value;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
float CDIGameDevice::getSliderPos(uint index) const
|
||||
{
|
||||
nlassert(index < _Sliders.size());
|
||||
return _Sliders[index].Pos;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
float CDIGameDevice::getPOVAngle(uint index) const
|
||||
{
|
||||
nlassert(index < _POVs.size());
|
||||
return _POVs[index].Angle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
@ -1,170 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_DI_GAME_DEVICE_H
|
||||
#define NL_DI_GAME_DEVICE_H
|
||||
|
||||
#include "nel/misc/types_nl.h"
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#include "nel/misc/di_event_emitter.h"
|
||||
#include "nel/misc/game_device.h"
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
//
|
||||
typedef DIJOYSTATE2 CDIJoyState;
|
||||
const DIDATAFORMAT * const pJoyDataFormat = &c_dfDIJoystick2;
|
||||
const uint MaxNumSliders = 2;
|
||||
const uint MaxNumPOVs = 4;
|
||||
const uint MaxNumButtons = 128;
|
||||
//
|
||||
|
||||
struct EDirectInputGameDeviceNotCreated : EDirectInput
|
||||
{
|
||||
EDirectInputGameDeviceNotCreated() : EDirectInput("Unable to create a game device") {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Direct input implementation of a game device.
|
||||
*/
|
||||
|
||||
class CDIGameDevice : public IGameDevice
|
||||
{
|
||||
public:
|
||||
/// Create a direct input game device from the given RGUID. Destroy it with delete
|
||||
static CDIGameDevice *createGameDevice(IDirectInput8 *di8,
|
||||
HWND hwnd,
|
||||
CDIEventEmitter *diEventEmitter,
|
||||
const CGameDeviceDesc &desc,
|
||||
REFGUID rguid) throw(EDirectInput);
|
||||
~CDIGameDevice();
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
virtual bool setBufferSize(uint size);
|
||||
virtual uint getBufferSize() const;
|
||||
//@}
|
||||
|
||||
///\name From IGameDevice
|
||||
//@{
|
||||
virtual const CGameDeviceDesc &getDescription() const { return _Desc; }
|
||||
//
|
||||
virtual uint getNumButtons() const;
|
||||
virtual bool hasAxis(TAxis axis) const;
|
||||
virtual uint getNumSliders() const;
|
||||
virtual uint getNumPOV() const;
|
||||
//
|
||||
virtual const char *getButtonName(uint index) const;
|
||||
virtual const char *getAxisName(TAxis axis) const;
|
||||
virtual const char *getSliderName(uint index) const;
|
||||
virtual const char *getPOVName(uint index) const;
|
||||
//
|
||||
virtual bool getButtonState(uint index) const;
|
||||
virtual float getAxisValue(TAxis axis) const;
|
||||
virtual float getSliderPos(uint index) const;
|
||||
virtual float getPOVAngle(uint index) const;
|
||||
//@}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
|
||||
// base class for controls
|
||||
struct CCtrl
|
||||
{
|
||||
std::string Name;
|
||||
};
|
||||
|
||||
// a button
|
||||
struct CButton : public CCtrl
|
||||
{
|
||||
bool Pushed;
|
||||
CButton() : Pushed(false) {}
|
||||
};
|
||||
|
||||
// an axis. Its value either gives its position (-1 .. 1) or its angle (CCW in radians)
|
||||
struct CAxis : public CCtrl
|
||||
{
|
||||
bool Present; // is this axis used ?
|
||||
// min and max values from Direct Input
|
||||
sint Min, Max;
|
||||
float Value;
|
||||
CAxis() : Value(0.f), Present(false) {}
|
||||
};
|
||||
|
||||
// a slider
|
||||
struct CSlider : public CCtrl
|
||||
{
|
||||
sint Min, Max;
|
||||
float Pos;
|
||||
CSlider() : Pos(0.f) {}
|
||||
};
|
||||
|
||||
// a POV
|
||||
struct CPOV : public CCtrl
|
||||
{
|
||||
bool Centered;
|
||||
float Angle;
|
||||
CPOV() : Angle(0.f), Centered(true) {}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
// ctor
|
||||
CDIGameDevice();
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
virtual void begin(CEventServer *server);
|
||||
virtual void poll(CInputDeviceServer *dev);
|
||||
virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server);
|
||||
//@}
|
||||
/** Get the controls (buttons, slider..) of this device from the Direct Input interface to build this object infos.
|
||||
*/
|
||||
void querryControls();
|
||||
|
||||
/// Called during EnumObject
|
||||
BOOL processEnumObject(LPCDIDEVICEOBJECTINSTANCE lpddoi);
|
||||
friend BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef);
|
||||
private:
|
||||
LPDIRECTINPUTDEVICE8 _Device;
|
||||
CGameDeviceDesc _Desc;
|
||||
CDIEventEmitter *_EventEmitter;
|
||||
|
||||
///\name Device infos
|
||||
//@{
|
||||
CAxis _Axis[MaxNumAxis];
|
||||
std::vector<CButton> _Buttons;
|
||||
std::vector<CSlider> _Sliders;
|
||||
std::vector<CPOV> _POVs;
|
||||
//@}
|
||||
CDIJoyState _CurrentState;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
||||
|
||||
|
||||
#endif // NL_DI_GAME_DEVICE_H
|
||||
|
||||
/* End of di_play_device.h */
|
@ -1,686 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
#include "stdmisc.h"
|
||||
#include "di_keyboard_device.h"
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#include "nel/misc/win_event_emitter.h"
|
||||
#include <dinput.h>
|
||||
#include <Winuser.h>
|
||||
|
||||
#include "Mmsystem.h"
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
// used to do a conversion from DX key code to Nel keys enums
|
||||
struct CKeyConv
|
||||
{
|
||||
uint DIKey;
|
||||
TKey NelKey;
|
||||
const char *KeyName;
|
||||
bool Repeatable;
|
||||
};
|
||||
|
||||
// this is used to build a conversion table
|
||||
static const CKeyConv DIToNel[] =
|
||||
{
|
||||
//
|
||||
{DIK_F1, KeyF1, "F1", true},
|
||||
{DIK_F2, KeyF2, "F2", true},
|
||||
{DIK_F3, KeyF3, "F3", true},
|
||||
{DIK_F4, KeyF4, "F4", true},
|
||||
{DIK_F5, KeyF5, "F5", true},
|
||||
{DIK_F6, KeyF6, "F6", true},
|
||||
{DIK_F7, KeyF7, "F7", true},
|
||||
{DIK_F8, KeyF8, "F8", true},
|
||||
{DIK_F9, KeyF9, "F9", true},
|
||||
{DIK_F10, KeyF10, "F10", true},
|
||||
{DIK_F11, KeyF11, "F11", true},
|
||||
{DIK_F12, KeyF12, "F12", true},
|
||||
{DIK_F13, KeyF13, "F13", true},
|
||||
{DIK_F14, KeyF14, "F14", true},
|
||||
{DIK_F15, KeyF15, "F15", true},
|
||||
//
|
||||
{DIK_NUMPAD0, KeyNUMPAD0, "NUMPAD0", true},
|
||||
{DIK_NUMPAD1, KeyNUMPAD1, "NUMPAD1", true},
|
||||
{DIK_NUMPAD2, KeyNUMPAD2, "NUMPAD2", true},
|
||||
{DIK_NUMPAD3, KeyNUMPAD3, "NUMPAD3", true},
|
||||
{DIK_NUMPAD4, KeyNUMPAD4, "NUMPAD4", true},
|
||||
{DIK_NUMPAD5, KeyNUMPAD5, "NUMPAD5", true},
|
||||
{DIK_NUMPAD6, KeyNUMPAD6, "NUMPAD6", true},
|
||||
{DIK_NUMPAD7, KeyNUMPAD7, "NUMPAD7", true},
|
||||
{DIK_NUMPAD8, KeyNUMPAD8, "NUMPAD8", true},
|
||||
{DIK_NUMPAD9, KeyNUMPAD9, "NUMPAD9", true},
|
||||
//
|
||||
{DIK_DIVIDE, KeyDIVIDE, "/", true},
|
||||
{DIK_DECIMAL, KeyDECIMAL, "NUMPAD .", true},
|
||||
//
|
||||
{DIK_LSHIFT, KeyLSHIFT, "LEFT SHIFT", false},
|
||||
{DIK_RSHIFT, KeyRSHIFT, "RIGHT SHIFT", false},
|
||||
//
|
||||
{DIK_LCONTROL, KeyLCONTROL, "LEFT CONTROL", false},
|
||||
{DIK_RCONTROL, KeyRCONTROL, "RIGHT CONTROL", false},
|
||||
//
|
||||
{DIK_LMENU, KeyLMENU, "ALT", false},
|
||||
{DIK_RMENU, KeyRMENU, "ALT GR", false},
|
||||
//
|
||||
{DIK_UP, KeyUP, "UP", true},
|
||||
{DIK_PRIOR, KeyPRIOR, "PRIOR", true},
|
||||
{DIK_LEFT, KeyLEFT, "LEFT", true},
|
||||
{DIK_RIGHT, KeyRIGHT, "RIGHT", true},
|
||||
{DIK_END, KeyEND, "END", true},
|
||||
{DIK_DOWN, KeyDOWN, "DOWN", true},
|
||||
{DIK_NEXT, KeyNEXT, "NEXT", true},
|
||||
{DIK_INSERT, KeyINSERT, "INSERT", true},
|
||||
{DIK_DELETE, KeyDELETE, "DELETE", true},
|
||||
{DIK_HOME, KeyHOME, "HOME", true},
|
||||
{DIK_LWIN, KeyLWIN, "LEFT WIN", false},
|
||||
{DIK_RWIN, KeyRWIN, "RIGHT WIN", false},
|
||||
{DIK_APPS, KeyAPPS, "APPS", false},
|
||||
{DIK_BACK, KeyBACK, "BACK", true},
|
||||
//
|
||||
{DIK_SYSRQ, KeySNAPSHOT, "SNAPSHOT", false},
|
||||
{DIK_SCROLL, KeySCROLL, "SCROLL", false},
|
||||
{DIK_PAUSE, KeyPAUSE, "PAUSE", false},
|
||||
//
|
||||
{DIK_NUMLOCK, KeyNUMLOCK, "NUMLOCK", false},
|
||||
//
|
||||
{DIK_NUMPADENTER, KeyRETURN, "RETURN", true},
|
||||
//{DIK_NUMPADENTER, KeyRETURN, "ENTER", true},
|
||||
//
|
||||
{DIK_CONVERT, KeyCONVERT, "CONVERT", false},
|
||||
{DIK_NOCONVERT, KeyNONCONVERT, "NOCONVERT", true},
|
||||
//
|
||||
{DIK_KANA, KeyKANA, "KANA", false},
|
||||
{DIK_KANJI, KeyKANJI, "KANJI", false},
|
||||
};
|
||||
|
||||
|
||||
///========================================================================
|
||||
const CKeyConv *CDIKeyboard::DIKeyToNelKeyTab[CDIKeyboard::NumKeys];
|
||||
|
||||
///========================================================================
|
||||
CDIKeyboard::CDIKeyboard(CWinEventEmitter *we, HWND hwnd)
|
||||
: _Keyboard(NULL),
|
||||
_WE(we),
|
||||
ShiftPressed(false),
|
||||
CtrlPressed(false),
|
||||
AltPressed(false),
|
||||
_CapsLockToggle(true),
|
||||
_hWnd(hwnd),
|
||||
_RepeatDelay(250),
|
||||
_RepeatPeriod(200),
|
||||
_FirstPressDate(-1),
|
||||
_LastDIKeyPressed(0)
|
||||
{
|
||||
if (::GetKeyboardState((PBYTE) _VKKeyState) == FALSE)
|
||||
{
|
||||
std::fill(_VKKeyState, _VKKeyState + NumKeys, 0);
|
||||
}
|
||||
// test whether the user toggle its keyboard with shift or not..
|
||||
HKEY hKey;
|
||||
if (::RegOpenKeyEx(HKEY_CURRENT_USER, "Keyboard Layout", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD type = REG_DWORD;
|
||||
DWORD value;
|
||||
DWORD size = sizeof(DWORD);
|
||||
if (::RegQueryValueEx(hKey, "Attributes", NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
|
||||
{
|
||||
_CapsLockToggle = (value & (1 << 16)) == 0;
|
||||
}
|
||||
::RegCloseKey(hKey);
|
||||
}
|
||||
// get repeat delay and period
|
||||
int keybDelay;
|
||||
if (::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &keybDelay, 0) != 0)
|
||||
{
|
||||
_RepeatDelay = 250 + 250 * keybDelay;
|
||||
}
|
||||
DWORD keybSpeed;
|
||||
if (::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &keybSpeed, 0) != 0)
|
||||
{
|
||||
_RepeatPeriod = (uint) (1000.f / (keybSpeed * (27.5f / 31.f) + 2.5f));
|
||||
}
|
||||
// get keyboard layout
|
||||
_KBLayout = ::GetKeyboardLayout(0);
|
||||
|
||||
_RepetitionDisabled.resize(NumKeys);
|
||||
_RepetitionDisabled.clearAll();
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::updateVKKeyState(uint diKey, bool pressed, TKey &keyValue, TKey &charValue)
|
||||
{
|
||||
bool extKey;
|
||||
bool repeatable;
|
||||
keyValue = DIKeyToNelKey(diKey, extKey, repeatable);
|
||||
//
|
||||
if (keyValue == 0)
|
||||
{
|
||||
charValue = keyValue;
|
||||
return;
|
||||
}
|
||||
//
|
||||
if (pressed)
|
||||
{
|
||||
// check for toggle key
|
||||
switch (keyValue)
|
||||
{
|
||||
case KeyPAUSE:
|
||||
case KeyKANA:
|
||||
case KeyKANJI:
|
||||
_VKKeyState[keyValue] ^= 0x01; // toggle first bit
|
||||
break;
|
||||
case KeyCAPITAL:
|
||||
if (_CapsLockToggle)
|
||||
{
|
||||
_VKKeyState[keyValue] ^= 0x01;
|
||||
//toggleCapsLock(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_VKKeyState[keyValue] & 0x01) == 0)
|
||||
{
|
||||
_VKKeyState[keyValue] |= 0x01;
|
||||
//toggleCapsLock(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KeyNUMLOCK:
|
||||
_VKKeyState[keyValue] ^= 0x01;
|
||||
//setNumLock((_VKKeyState[keyValue] & 0x01) != 0);
|
||||
break;
|
||||
case KeySCROLL:
|
||||
_VKKeyState[keyValue] ^= 0x01;
|
||||
//toggleScrollLock();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
_VKKeyState[keyValue] |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_VKKeyState[keyValue] &= ~0x80;
|
||||
}
|
||||
//
|
||||
switch (keyValue)
|
||||
{
|
||||
case KeyLSHIFT: charValue = KeySHIFT; break;
|
||||
case KeyRSHIFT: charValue = KeySHIFT; break;
|
||||
case KeyLCONTROL: charValue = KeyCONTROL; break;
|
||||
case KeyRCONTROL: charValue = KeyCONTROL; break;
|
||||
case KeyLMENU: charValue = KeyMENU; break;
|
||||
case KeyRMENU: charValue = KeyMENU; break;
|
||||
default: charValue = keyValue; break;
|
||||
}
|
||||
//
|
||||
if (charValue == KeySHIFT && !_CapsLockToggle)
|
||||
{
|
||||
if (_VKKeyState[KeyCAPITAL] & 0x01)
|
||||
{
|
||||
_VKKeyState[KeyCAPITAL] &= ~0x01;
|
||||
//toggleCapsLock(true);
|
||||
}
|
||||
}
|
||||
//
|
||||
if (charValue != keyValue)
|
||||
{
|
||||
_VKKeyState[charValue] = _VKKeyState[keyValue];
|
||||
}
|
||||
//
|
||||
updateCtrlAltShiftValues();
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::updateCtrlAltShiftValues()
|
||||
{
|
||||
ShiftPressed = (_VKKeyState[KeySHIFT] & 0x80) != 0;
|
||||
CtrlPressed = (_VKKeyState[KeyCONTROL] & 0x80) != 0;
|
||||
AltPressed = (_VKKeyState[KeyMENU] & 0x80) != 0;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
CDIKeyboard::~CDIKeyboard()
|
||||
{
|
||||
if (_Keyboard)
|
||||
{
|
||||
_Keyboard->Unacquire();
|
||||
_Keyboard->Release();
|
||||
}
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
CDIKeyboard *CDIKeyboard::createKeyboardDevice(IDirectInput8 *di8,
|
||||
HWND hwnd,
|
||||
CDIEventEmitter *diEventEmitter,
|
||||
CWinEventEmitter *we
|
||||
) throw(EDirectInput)
|
||||
{
|
||||
std::auto_ptr<CDIKeyboard> kb(new CDIKeyboard(we, hwnd));
|
||||
kb->_DIEventEmitter = diEventEmitter;
|
||||
HRESULT result = di8->CreateDevice(GUID_SysKeyboard, &kb->_Keyboard, NULL);
|
||||
if (result != DI_OK) throw EDirectInputNoKeyboard();
|
||||
result = kb->_Keyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
|
||||
if (result != DI_OK) throw EDirectInputCooperativeLevelFailed();
|
||||
result = kb->_Keyboard->SetDataFormat(&c_dfDIKeyboard);
|
||||
kb->setBufferSize(16);
|
||||
kb->_Keyboard->Acquire();
|
||||
|
||||
// Enable win32 keyboard messages only if hardware mouse in normal mode
|
||||
if (kb->_WE)
|
||||
kb->_WE->enableKeyboardEvents(false);
|
||||
|
||||
return kb.release();
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::poll(CInputDeviceServer *dev)
|
||||
{
|
||||
nlassert(_Keyboard);
|
||||
nlassert(_KeyboardBufferSize > 0);
|
||||
static std::vector<DIDEVICEOBJECTDATA> datas;
|
||||
datas.resize(_KeyboardBufferSize);
|
||||
DWORD numElements = _KeyboardBufferSize;
|
||||
HRESULT result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
|
||||
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
|
||||
{
|
||||
result = _Keyboard->Acquire();
|
||||
if (result != DI_OK) return;
|
||||
// get device state
|
||||
::GetKeyboardState((unsigned char *) _VKKeyState);
|
||||
_LastDIKeyPressed = 0;
|
||||
updateCtrlAltShiftValues();
|
||||
result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
|
||||
if (result != DI_OK) return;
|
||||
}
|
||||
else if (result != DI_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_PollTime = (uint32) CTime::getLocalTime();
|
||||
|
||||
|
||||
// process each message in the list
|
||||
for (uint k = 0; k < numElements; ++k)
|
||||
{
|
||||
CDIEvent *die = new CDIEvent;
|
||||
die->Emitter = this;
|
||||
die->Datas = datas[k];
|
||||
dev->submitEvent(die);
|
||||
}
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage)
|
||||
{
|
||||
repeatKey(buildDateFromEvent(nextMessage), server);
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
TKeyButton CDIKeyboard::buildKeyButtonsFlags() const
|
||||
{
|
||||
return (TKeyButton) ( (ShiftPressed ? shiftKeyButton : 0)
|
||||
| (CtrlPressed ? ctrlKeyButton : 0)
|
||||
| (AltPressed ? altKeyButton : 0)
|
||||
);
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::keyTriggered(bool pressed, uint dikey, CEventServer *server, uint32 date)
|
||||
{
|
||||
#if 0
|
||||
const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv);
|
||||
for (uint k = 0; k < numPairs; ++k)
|
||||
{
|
||||
if (DIToNel[k].DIKey == key)
|
||||
{
|
||||
nlinfo(DIToNel[k].KeyName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TKey keyValue, charValue;
|
||||
updateVKKeyState(dikey, pressed, keyValue, charValue);
|
||||
if (keyValue == 0) return;
|
||||
|
||||
CEventKey *ek;
|
||||
if (pressed )
|
||||
{
|
||||
ek = new CEventKeyDown(keyValue, buildKeyButtonsFlags(), true, _DIEventEmitter);
|
||||
}
|
||||
else
|
||||
{
|
||||
ek = new CEventKeyUp(keyValue, buildKeyButtonsFlags(), _DIEventEmitter);
|
||||
}
|
||||
server->postEvent(ek);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
if (_RepetitionDisabled[(uint) keyValue] == false)
|
||||
{
|
||||
_LastEmitDate = _FirstPressDate = date;
|
||||
_LastDIKeyPressed = dikey;
|
||||
}
|
||||
else // not a repeatable key
|
||||
{
|
||||
_LastDIKeyPressed = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// key released ?
|
||||
if (dikey == _LastDIKeyPressed)
|
||||
{
|
||||
_LastDIKeyPressed = 0;
|
||||
}
|
||||
|
||||
if (_RepetitionDisabled[(uint) keyValue] == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// first char event (if repetition not disabled)
|
||||
if (keyValue >= KeyNUMPAD0 && keyValue <= KeyNUMPAD9 || keyValue == KeyDECIMAL)
|
||||
{
|
||||
if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0)
|
||||
{
|
||||
sendUnicode(charValue, dikey, server, pressed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sendUnicode(charValue, dikey, server, pressed);
|
||||
}
|
||||
|
||||
_FirstPressDate = (uint32) NLMISC::CTime::getLocalTime(); // can't use the time stamp, because we can't not sure it matches the local time.
|
||||
// time stamp is used for evenrts sorting only
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
|
||||
{
|
||||
CDIEvent *die = safe_cast<CDIEvent *>(deviceEvent);
|
||||
bool pressed = (die->Datas.dwData & 0x80) != 0;
|
||||
keyTriggered(pressed, (uint) die->Datas.dwOfs, server, die->Datas.dwTimeStamp);
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
TMouseButton CDIKeyboard::buildKeyboardButtonFlags() const
|
||||
{
|
||||
nlassert(_Keyboard);
|
||||
return _DIEventEmitter->buildKeyboardButtonFlags();
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
bool CDIKeyboard::setBufferSize(uint size)
|
||||
{
|
||||
nlassert(size > 0);
|
||||
nlassert(_Keyboard);
|
||||
_Keyboard->Unacquire();
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = size;
|
||||
HRESULT r = _Keyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
|
||||
if (r != DI_OK) return false;
|
||||
_KeyboardBufferSize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
uint CDIKeyboard::getBufferSize() const
|
||||
{
|
||||
return _KeyboardBufferSize;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
TKey CDIKeyboard::DIKeyToNelKey(uint diKey, bool &extKey, bool &repeatable)
|
||||
{
|
||||
// some key are not handled by MapVirtualKeyEx so we need to convert them ourselves
|
||||
static bool tableBuilt = false;
|
||||
|
||||
if (!tableBuilt)
|
||||
{
|
||||
uint k;
|
||||
for (k = 0; k < NumKeys; ++k)
|
||||
{
|
||||
DIKeyToNelKeyTab[k] = NULL; // set as not a valid key by default
|
||||
}
|
||||
const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv);
|
||||
for (k = 0; k < numPairs; ++k)
|
||||
{
|
||||
DIKeyToNelKeyTab[DIToNel[k].DIKey] = &DIToNel[k];
|
||||
}
|
||||
tableBuilt = true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
if (DIKeyToNelKeyTab[diKey] != NULL)
|
||||
{
|
||||
const CKeyConv &keyConv = *DIKeyToNelKeyTab[diKey];
|
||||
extKey = true;
|
||||
repeatable = keyConv.Repeatable;
|
||||
return keyConv.NelKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// try doing the conversion using MapVirtualKey
|
||||
TKey key = (TKey) ::MapVirtualKeyEx(diKey, 1, _KBLayout);
|
||||
extKey = false;
|
||||
return key;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::sendUnicode(TKey vkey, uint dikey, CEventServer *server, bool pressed)
|
||||
{
|
||||
uint8 oldShift = _VKKeyState[KeySHIFT];
|
||||
/// If caps lock is off when pressing shift, we must disable shift, to get no minuscule letters when it is pressed and capslocks is on.
|
||||
if (!_CapsLockToggle && _VKKeyState[KeyCAPITAL] & 0x01)
|
||||
{
|
||||
_VKKeyState[KeySHIFT] = 0;
|
||||
}
|
||||
// 'ToUnicode??' is supported since NT4.0 only
|
||||
// Check if there's support
|
||||
|
||||
|
||||
static bool init = false;
|
||||
static bool toUnicodeSupported = false;
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
OSVERSIONINFO osvi;
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
if (::GetVersionEx (&osvi))
|
||||
{
|
||||
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
if (osvi.dwMajorVersion >= 4)
|
||||
{
|
||||
toUnicodeSupported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (toUnicodeSupported)
|
||||
{
|
||||
const uint maxNumKeys = 8;
|
||||
WCHAR keyUnicodes[maxNumKeys];
|
||||
int res = ::ToUnicodeEx(vkey, dikey | (pressed ? 0 : (1 << 15)), (unsigned char *) _VKKeyState, keyUnicodes, maxNumKeys, 0, _KBLayout);
|
||||
//
|
||||
_VKKeyState[KeySHIFT] = oldShift;
|
||||
//
|
||||
for (sint k = 0; k < res; ++k)
|
||||
{
|
||||
CEventChar *evc = new CEventChar((ucchar) keyUnicodes[k], buildKeyButtonsFlags(), _DIEventEmitter);
|
||||
server->postEvent(evc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char buf[2];
|
||||
int res = ::ToAsciiEx(vkey, dikey | (pressed ? 0 : (1 << 15)), (unsigned char *) _VKKeyState, (LPWORD) buf, 0, _KBLayout);
|
||||
for (sint k = 0; k < res; ++k)
|
||||
{
|
||||
CEventChar *evc = new CEventChar((ucchar) buf[k], buildKeyButtonsFlags(), _DIEventEmitter);
|
||||
server->postEvent(evc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::repeatKey(uint32 currentDate, CEventServer *server)
|
||||
{
|
||||
if (_LastDIKeyPressed == 0 || _LastDIKeyPressed == DIK_INSERT) return;
|
||||
bool extKey;
|
||||
bool repeatable;
|
||||
TKey vkey = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable);
|
||||
if (vkey == 0) return;
|
||||
if (currentDate - _FirstPressDate < _RepeatDelay) return;
|
||||
|
||||
sint32 firstDate = _LastEmitDate - (_FirstPressDate + _RepeatDelay);
|
||||
sint32 lastDate = currentDate - (_FirstPressDate + _RepeatDelay);
|
||||
if (firstDate < 0) firstDate = 0;
|
||||
|
||||
if (lastDate < firstDate) return;
|
||||
|
||||
uint numRep = (uint) ((lastDate + _RepeatPeriod - 1) / _RepeatPeriod - (firstDate + _RepeatPeriod - 1) / _RepeatPeriod);
|
||||
//numRep = std::min(16u, numRep); // too much repetitions don't make sense...
|
||||
if ((sint) numRep < 0) return; // 50 days loop..
|
||||
numRep = 1; // fix : for now it seems better to limit the number of repetition to 1 per frame (it can be greater than 1 only if framerate is slow, but its not very useable)
|
||||
|
||||
|
||||
// numpad case
|
||||
if (vkey >= KeyNUMPAD0 && vkey <= KeyNUMPAD9 || vkey == KeyDECIMAL)
|
||||
{
|
||||
// check whether numlock is activated
|
||||
if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0)
|
||||
{
|
||||
for (uint k = 0; k < numRep; ++k)
|
||||
{
|
||||
sendUnicode(vkey, _LastDIKeyPressed, server, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// arrow, home, end.. events
|
||||
for (uint k = 0; k < numRep; ++k)
|
||||
{
|
||||
CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), false, _DIEventEmitter);
|
||||
server->postEvent(ek);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint k = 0; k < numRep; ++k)
|
||||
{
|
||||
// if it is an extended key, repetition won't be managed by sendUnicode
|
||||
if (extKey && repeatable)
|
||||
{
|
||||
CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), false, _DIEventEmitter);
|
||||
server->postEvent(ek);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendUnicode(vkey, _LastDIKeyPressed, server, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_LastEmitDate = currentDate;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
uint32 CDIKeyboard::buildDateFromEvent(const IInputDeviceEvent *deviceEvent)
|
||||
{
|
||||
if (deviceEvent)
|
||||
{
|
||||
const CDIEvent *die = safe_cast<const CDIEvent *>(deviceEvent);
|
||||
return (uint32) die->Datas.dwData;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _PollTime;
|
||||
}
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::disableRepetition(const TKey *keyTab, uint numKey)
|
||||
{
|
||||
_RepetitionDisabled.clearAll();
|
||||
for (uint k = 0; k < numKey; ++k)
|
||||
{
|
||||
_RepetitionDisabled.set((sint) keyTab[k]);
|
||||
}
|
||||
|
||||
if (_LastDIKeyPressed != 0)
|
||||
{
|
||||
bool extKey;
|
||||
bool repeatable;
|
||||
TKey key = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable);
|
||||
if (_RepetitionDisabled[(uint) key])
|
||||
{
|
||||
// disable this key repetition
|
||||
_LastDIKeyPressed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
uint CDIKeyboard::getNumDisabledRepetition() const
|
||||
{
|
||||
uint numKey = 0;
|
||||
for (uint k = 0; k < NumKeys; ++k)
|
||||
{
|
||||
if (_RepetitionDisabled[k]) ++numKey;
|
||||
}
|
||||
return numKey;
|
||||
}
|
||||
|
||||
///========================================================================
|
||||
void CDIKeyboard::getDisabledRepetitions(TKey *destTab) const
|
||||
{
|
||||
for (uint k = 0; k < NumKeys; ++k)
|
||||
{
|
||||
if (_RepetitionDisabled[k]) *destTab++ = (TKey) k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
@ -1,163 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_DI_KEYBOARD_H
|
||||
#define NL_DI_KEYBOARD_H
|
||||
|
||||
#include "nel/misc/types_nl.h"
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#include "nel/misc/input_device_server.h"
|
||||
#include "nel/misc/keyboard_device.h"
|
||||
#include "nel/misc/di_event_emitter.h"
|
||||
#include "nel/misc/bit_set.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
class CWinEventEmitter;
|
||||
|
||||
//
|
||||
struct EDirectInputNoKeyboard : public EDirectInput
|
||||
{
|
||||
EDirectInputNoKeyboard() : EDirectInput("No keyboard found") {}
|
||||
};
|
||||
|
||||
|
||||
struct CKeyConv;
|
||||
|
||||
/**
|
||||
* Direct Input implementation of a keyboard.
|
||||
* \see CDIEventEmitter
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
class CDIKeyboard : public IKeyboardDevice
|
||||
{
|
||||
public:
|
||||
bool ShiftPressed, CtrlPressed, AltPressed;
|
||||
public:
|
||||
///\name Object
|
||||
//@{
|
||||
/** Create a keyboard device, that must then be deleted by the caller
|
||||
* An optional WinEventEmiter can be provided, so that its flags can be in sync
|
||||
* with a win32 keyboard flags (shift, ctrl, and alt)
|
||||
*/
|
||||
static CDIKeyboard *createKeyboardDevice(IDirectInput8 *di8,
|
||||
HWND hwnd,
|
||||
CDIEventEmitter *diEventEmitter,
|
||||
CWinEventEmitter *we = NULL
|
||||
) throw(EDirectInput);
|
||||
// dtor
|
||||
virtual ~CDIKeyboard();
|
||||
//@}
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
virtual bool setBufferSize(uint size);
|
||||
virtual uint getBufferSize() const;
|
||||
//@}
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
uint getKeyRepeatDelay() const { return _RepeatDelay; }
|
||||
void setKeyRepeatDelay(uint delay) { nlassert(delay > 0); _RepeatDelay = delay; }
|
||||
uint getKeyRepeatPeriod() const { return _RepeatPeriod; }
|
||||
void setKeyRepeatPeriod(uint period) { nlassert(period > 0); _RepeatPeriod = period; }
|
||||
void disableRepetition(const TKey *keyTab, uint numKey);
|
||||
uint getNumDisabledRepetition() const;
|
||||
void getDisabledRepetitions(TKey *destTab) const;
|
||||
//@}
|
||||
|
||||
TMouseButton buildKeyboardFlags() const;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
//
|
||||
bool _CapsLockToggle; // true if caps lock off is triggered by caps lock, false if it toggled by shift
|
||||
uint _RepeatDelay; // the delay before a key is repeated (in ms)
|
||||
uint _RepeatPeriod; // The period for key repetitions (in ms)
|
||||
//
|
||||
LPDIRECTINPUTDEVICE8 _Keyboard;
|
||||
uint _KeyboardBufferSize;
|
||||
// virtual code state
|
||||
uint8 _VKKeyState[NumKeys];
|
||||
// tells for which keys repetition is disabled
|
||||
CBitSet _RepetitionDisabled;
|
||||
// The date at which the last key pressed has been pressed (not using 64 bits since note handled by Direct Input)
|
||||
uint32 _FirstPressDate;
|
||||
// The last date at which key repetition occured (not using 64 bits since note handled by Direct Input)
|
||||
uint32 _LastEmitDate;
|
||||
// The system date at which the last polling occured (not using 64 bits since note handled by Direct Input)
|
||||
uint32 _PollTime;
|
||||
uint _LastDIKeyPressed;
|
||||
CWinEventEmitter *_WE;
|
||||
HWND _hWnd;
|
||||
HKL _KBLayout;
|
||||
//
|
||||
CDIEventEmitter *_DIEventEmitter;
|
||||
//
|
||||
static const CKeyConv *DIKeyToNelKeyTab[NumKeys];
|
||||
private:
|
||||
/// ctor
|
||||
CDIKeyboard(CWinEventEmitter *we, HWND hwnd);
|
||||
/** Convert a direct input scancode to a virtual key. Note that DirectInput scancodes do not always match system scan codes.
|
||||
* Repeatable has a meaning only for extended keys
|
||||
*/
|
||||
TKey DIKeyToNelKey(uint diKey, bool &extKey, bool &repeatable);
|
||||
/** This update virtual key state table.
|
||||
* \param keyValue contains the value to send to a EventKeyDown or EventKeyUp message.
|
||||
* \param charValue contains the value that must be used for Unicode conversion (which generate EventChar messages)
|
||||
*/
|
||||
void updateVKKeyState(uint diKey, bool pressed, TKey &keyValue, TKey &charValue);
|
||||
// Use the given virtual key code and the current keyb state to produce Unicode
|
||||
void sendUnicode(TKey vkey, uint dikey, CEventServer *server, bool pressed);
|
||||
// Build a TKeyButton value from the state of shift, ctrl and alt
|
||||
TKeyButton buildKeyButtonsFlags() const;
|
||||
// Update the state of this object and send the appropriate message when a direct / input key has been pressed / released
|
||||
void keyTriggered(bool pressed, uint key, CEventServer *server, uint32 date);
|
||||
// The same as buildKeyButtonsFlags(), but the return is a TMouseButtonValue (with no mouse value setupped)
|
||||
TMouseButton buildKeyboardButtonFlags() const;
|
||||
// setup the state of the Ctrl, Alt and Shift key from the state in the _VKKeyState buffer
|
||||
void updateCtrlAltShiftValues();
|
||||
/// Repeat the current key, and create events
|
||||
void repeatKey(uint32 currentDate, CEventServer *server);
|
||||
/// Build a date by using an event time stamp, or generate one if NULL
|
||||
uint32 buildDateFromEvent(const IInputDeviceEvent *deviceEvent);
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
virtual void poll(CInputDeviceServer *dev);
|
||||
virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server);
|
||||
virtual void transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage);
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
||||
|
||||
#endif // NL_DI_KEYBOARD_H
|
||||
|
||||
/* End of di_keyboard.h */
|
@ -1,507 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
|
||||
#include "di_mouse_device.h"
|
||||
#include "nel/misc/game_device_events.h"
|
||||
#include "nel/misc/win_event_emitter.h"
|
||||
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#ifdef NL_COMP_MINGW
|
||||
# undef FIELD_OFFSET
|
||||
# define FIELD_OFFSET(t,f) offsetof(t,f)
|
||||
#endif
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
//======================================================
|
||||
CDIMouse::CDIMouse() : _MessageMode(RawMode),
|
||||
_MouseSpeed(1.0f),
|
||||
_MouseAccel(10000),
|
||||
_Mouse(NULL),
|
||||
_XAcc(0),
|
||||
_YAcc(0),
|
||||
_XMousePos(0),
|
||||
_YMousePos(0),
|
||||
_LastMouseButtonClicked(-1),
|
||||
_DoubleClickDelay(300),
|
||||
_XFactor(1.f),
|
||||
_YFactor(1.f),
|
||||
OldDIXPos(0),
|
||||
OldDIYPos(0),
|
||||
OldDIZPos(0),
|
||||
_FirstX(true),
|
||||
_FirstY(true),
|
||||
_SwapButton(false)
|
||||
|
||||
{
|
||||
std::fill(_MouseButtons, _MouseButtons + MaxNumMouseButtons, false);
|
||||
std::fill(_MouseAxisMode, _MouseAxisMode + NumMouseAxis, Raw);
|
||||
_MouseFrame.setWH(0, 0, 640, 480);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
CDIMouse::~CDIMouse()
|
||||
{
|
||||
if (_Mouse)
|
||||
{
|
||||
_Mouse->Unacquire();
|
||||
_Mouse->Release();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMouseMode(TAxis axis, TAxisMode axisMode)
|
||||
{
|
||||
nlassert(axisMode < AxisModeLast);
|
||||
nlassert(axis < AxisLast);
|
||||
_MouseAxisMode[axis] = axisMode;
|
||||
clampMouseAxis();
|
||||
}
|
||||
|
||||
//======================================================
|
||||
CDIMouse::TAxisMode CDIMouse::getMouseMode(TAxis axis) const
|
||||
{
|
||||
nlassert((int)axis < (int)NumMouseAxis);
|
||||
return _MouseAxisMode[axis];
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMouseSpeed(float speed)
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
nlassert(speed > 0);
|
||||
_MouseSpeed = speed;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMouseAcceleration(uint accel)
|
||||
{
|
||||
_MouseAccel = accel;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
uint CDIMouse::getMouseAcceleration() const
|
||||
{
|
||||
return _MouseAccel;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
bool CDIMouse::setBufferSize(uint size)
|
||||
{
|
||||
nlassert(size > 0);
|
||||
nlassert(_Mouse);
|
||||
_Mouse->Unacquire();
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dipdw.diph.dwObj = 0;
|
||||
dipdw.diph.dwHow = DIPH_DEVICE;
|
||||
dipdw.dwData = size;
|
||||
HRESULT r = _Mouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
|
||||
if (r != DI_OK) return false;
|
||||
_MouseBufferSize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
uint CDIMouse::getBufferSize() const { return _MouseBufferSize; }
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMousePos(float x, float y)
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
_XMousePos = (sint64) ((double) x * ((sint64) 1 << 32));
|
||||
_YMousePos = (sint64) ((double) y * ((sint64) 1 << 32));
|
||||
}
|
||||
|
||||
//======================================================
|
||||
CDIMouse *CDIMouse::createMouseDevice(IDirectInput8 *di8, HWND hwnd, CDIEventEmitter *diEventEmitter, bool hardware, CWinEventEmitter *we) throw(EDirectInput)
|
||||
{
|
||||
std::auto_ptr<CDIMouse> mouse(new CDIMouse);
|
||||
mouse->_DIEventEmitter = diEventEmitter;
|
||||
mouse->_Hardware = hardware;
|
||||
HRESULT result = di8->CreateDevice(GUID_SysMouse, &(mouse->_Mouse), NULL);
|
||||
if (result != DI_OK) throw EDirectInputNoMouse();
|
||||
result = mouse->_Mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | (!hardware ? DISCL_EXCLUSIVE:DISCL_NONEXCLUSIVE));
|
||||
if (result != DI_OK) throw EDirectInputCooperativeLevelFailed();
|
||||
mouse->_Mouse->SetDataFormat(&c_dfDIMouse2);
|
||||
mouse->setBufferSize(64);
|
||||
mouse->_WE = we;
|
||||
mouse->setDoubleClickDelay(::GetDoubleClickTime());
|
||||
|
||||
/** we want an absolute mouse mode, so that, if the event buffer get full, we can retrieve the right position
|
||||
*/
|
||||
DIPROPDWORD prop;
|
||||
prop.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
prop.diph.dwHow = DIPH_DEVICE;
|
||||
prop.diph.dwObj = 0;
|
||||
prop.dwData = DIPROPAXISMODE_ABS;
|
||||
HRESULT r = mouse->_Mouse->SetProperty(DIPROP_AXISMODE, &prop.diph);
|
||||
nlassert(r == DI_OK); // should always succeed...
|
||||
//
|
||||
mouse->_Mouse->Acquire();
|
||||
mouse->_hWnd = hwnd;
|
||||
|
||||
// Enable win32 mouse message only if hardware mouse in normal mode
|
||||
if (mouse->_WE)
|
||||
mouse->_WE->enableMouseEvents(mouse->_Hardware && (mouse->_MessageMode == IMouseDevice::NormalMode));
|
||||
|
||||
mouse->_SwapButton = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
|
||||
return mouse.release();
|
||||
}
|
||||
|
||||
//======================================================
|
||||
float CDIMouse::getMouseSpeed() const
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
return _MouseSpeed;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
const CRect &CDIMouse::getMouseFrame() const
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
return _MouseFrame;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
uint CDIMouse::getDoubleClickDelay() const { return _DoubleClickDelay; }
|
||||
|
||||
//======================================================
|
||||
inline void CDIMouse::clampMouseAxis()
|
||||
{
|
||||
if (_MouseAxisMode[XAxis] == Clamped) clamp(_XMousePos, (sint64) _MouseFrame.X << 32, (sint64) (_MouseFrame.X + _MouseFrame.Width - 1) << 32);
|
||||
if (_MouseAxisMode[YAxis] == Clamped) clamp(_YMousePos, (sint64) _MouseFrame.Y << 32, (sint64) (_MouseFrame.X + _MouseFrame.Height - 1) << 32);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::poll(CInputDeviceServer *dev)
|
||||
{
|
||||
nlassert(_Mouse);
|
||||
nlassert(_MouseBufferSize > 0);
|
||||
static std::vector<DIDEVICEOBJECTDATA> datas;
|
||||
datas.resize(_MouseBufferSize);
|
||||
DWORD numElements = _MouseBufferSize;
|
||||
HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
|
||||
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
|
||||
{
|
||||
result = _Mouse->Acquire();
|
||||
HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
|
||||
if (result != DI_OK) return;
|
||||
}
|
||||
else if (result != DI_OK) return;
|
||||
|
||||
if (::IsWindowEnabled(_hWnd) && ::IsWindowVisible(_hWnd))
|
||||
{
|
||||
for(uint k = 0; k < numElements; ++k)
|
||||
{
|
||||
CDIEvent *die = new CDIEvent;
|
||||
die->Emitter = this;
|
||||
die->Datas = datas[k];
|
||||
dev->submitEvent(die);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
TMouseButton CDIMouse::buildMouseButtonFlags() const
|
||||
{
|
||||
if (_SwapButton)
|
||||
return (TMouseButton) (
|
||||
_DIEventEmitter->buildKeyboardButtonFlags()
|
||||
| (_MouseButtons[0] ? rightButton : 0)
|
||||
| (_MouseButtons[1] ? leftButton : 0)
|
||||
| (_MouseButtons[2] ? middleButton : 0)
|
||||
);
|
||||
else
|
||||
return (TMouseButton) (
|
||||
_DIEventEmitter->buildKeyboardButtonFlags()
|
||||
| (_MouseButtons[0] ? leftButton : 0)
|
||||
| (_MouseButtons[1] ? rightButton : 0)
|
||||
| (_MouseButtons[2] ? middleButton : 0)
|
||||
);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
TMouseButton CDIMouse::buildMouseSingleButtonFlags(uint button)
|
||||
{
|
||||
static const TMouseButton mb[] = { leftButton, rightButton, middleButton };
|
||||
static const TMouseButton mbswap[] = { rightButton, leftButton, middleButton };
|
||||
nlassert(button < MaxNumMouseButtons);
|
||||
if (_SwapButton)
|
||||
return (TMouseButton) (_DIEventEmitter->buildKeyboardButtonFlags() | mbswap[button]);
|
||||
else
|
||||
return (TMouseButton) (_DIEventEmitter->buildKeyboardButtonFlags() | mb[button]);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::onButtonClicked(uint button, CEventServer *server, uint32 date)
|
||||
{
|
||||
// check for double click
|
||||
if (_LastMouseButtonClicked == (sint) button)
|
||||
{
|
||||
if (date - _MouseButtonsLastClickDate < _DoubleClickDelay)
|
||||
{
|
||||
CEventMouseDblClk *emdc
|
||||
= new CEventMouseDblClk((float) (_XMousePos >> 32),
|
||||
(float) (_YMousePos >> 32),
|
||||
buildMouseSingleButtonFlags(button),
|
||||
_DIEventEmitter);
|
||||
server->postEvent(emdc);
|
||||
_LastMouseButtonClicked = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_MouseButtonsLastClickDate = date;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_LastMouseButtonClicked = button;
|
||||
_MouseButtonsLastClickDate = date;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::processButton(uint button, bool pressed, CEventServer *server, uint32 date)
|
||||
{
|
||||
updateMove(server);
|
||||
float mx = (float) (_XFactor * (double) _XMousePos / ((double) 65536 * (double) 65536));
|
||||
float my = (float) (_YFactor * (double) _YMousePos / ((double) 65536 * (double) 65536));
|
||||
if (pressed)
|
||||
{
|
||||
CEventMouseDown *emd =
|
||||
new CEventMouseDown(mx, my, buildMouseSingleButtonFlags(button),
|
||||
_DIEventEmitter);
|
||||
server->postEvent(emd);
|
||||
}
|
||||
else
|
||||
{
|
||||
CEventMouseUp *emu =
|
||||
new CEventMouseUp(mx, my, buildMouseSingleButtonFlags(button), _DIEventEmitter);
|
||||
server->postEvent(emu);
|
||||
onButtonClicked(button, server, date);
|
||||
}
|
||||
_MouseButtons[button] = pressed;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
|
||||
{
|
||||
if (!_Hardware || (_MessageMode == RawMode))
|
||||
{
|
||||
CDIEvent *die = safe_cast<CDIEvent *>(deviceEvent);
|
||||
bool pressed;
|
||||
switch(die->Datas.dwOfs)
|
||||
{
|
||||
case DIMOFS_X:
|
||||
{
|
||||
if (!_FirstX)
|
||||
{
|
||||
sint dep = (sint32) die->Datas.dwData - OldDIXPos;
|
||||
|
||||
// Acceleration
|
||||
if (_MouseAccel)
|
||||
{
|
||||
sint accelFactor = abs (dep) / (sint)_MouseAccel;
|
||||
dep <<= accelFactor;
|
||||
}
|
||||
|
||||
_XAcc += dep;
|
||||
}
|
||||
else
|
||||
{
|
||||
_FirstX = false;
|
||||
}
|
||||
OldDIXPos = (sint32) die->Datas.dwData;
|
||||
}
|
||||
break;
|
||||
case DIMOFS_Y:
|
||||
{
|
||||
if (!_FirstY)
|
||||
{
|
||||
sint dep = (sint32) die->Datas.dwData - OldDIYPos;
|
||||
|
||||
// Acceleration
|
||||
if (_MouseAccel)
|
||||
{
|
||||
sint accelFactor = abs (dep) / (sint)_MouseAccel;
|
||||
dep <<= accelFactor;
|
||||
}
|
||||
|
||||
_YAcc -= dep;
|
||||
}
|
||||
else
|
||||
{
|
||||
_FirstY = false;
|
||||
}
|
||||
OldDIYPos = (sint32) die->Datas.dwData;
|
||||
}
|
||||
break;
|
||||
case DIMOFS_Z:
|
||||
{
|
||||
updateMove(server);
|
||||
sint dep = die->Datas.dwData - OldDIZPos;
|
||||
OldDIZPos = (sint32) die->Datas.dwData;
|
||||
CEventMouseWheel *emw =
|
||||
new CEventMouseWheel((float) (_XMousePos >> 32),
|
||||
(float) (_XMousePos >> 32),
|
||||
buildMouseButtonFlags(),
|
||||
dep > 0,
|
||||
_DIEventEmitter);
|
||||
server->postEvent(emw);
|
||||
}
|
||||
break;
|
||||
case DIMOFS_BUTTON0: /* left button */
|
||||
pressed = (die->Datas.dwData & 0x80) != 0;
|
||||
processButton(0, pressed, server, die->Datas.dwTimeStamp);
|
||||
break;
|
||||
case DIMOFS_BUTTON1: /* right button */
|
||||
pressed = (die->Datas.dwData & 0x80) != 0;
|
||||
processButton(1, pressed, server, die->Datas.dwTimeStamp);
|
||||
break;
|
||||
case DIMOFS_BUTTON2: /* middle button */
|
||||
pressed = (die->Datas.dwData & 0x80) != 0;
|
||||
processButton(2, pressed, server, die->Datas.dwTimeStamp);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::updateMove(CEventServer *server)
|
||||
{
|
||||
if (_XAcc != 0 || _YAcc != 0)
|
||||
{
|
||||
if (_MessageMode == NormalMode)
|
||||
{
|
||||
_XMousePos += (sint64) ((double) _MouseSpeed * (sint64) _XAcc * ((sint64) 1 << 32));
|
||||
_YMousePos += (sint64) ((double) _MouseSpeed * (sint64) _YAcc * ((sint64) 1 << 32));
|
||||
clampMouseAxis();
|
||||
CEventMouseMove *emm = new CEventMouseMove((float) (_XFactor * (double) _XMousePos / ((double) 65536 * (double) 65536)), (float) (_YFactor * (double) _YMousePos / ((double) 65536 * (double) 65536)), buildMouseButtonFlags(), _DIEventEmitter);
|
||||
server->postEvent(emm);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGDMouseMove *emm = new CGDMouseMove(_DIEventEmitter, this, _XAcc, _YAcc);
|
||||
server->postEvent(emm);
|
||||
}
|
||||
_XAcc = _YAcc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::convertStdMouseMoveInMickeys(float &dx, float &dy) const
|
||||
{
|
||||
// get in same scale as _XAcc and _YAcc
|
||||
double xacc= ((double)dx/_XFactor) / _MouseSpeed;
|
||||
double yacc= ((double)dy/_YFactor) / _MouseSpeed;
|
||||
|
||||
dx= float(xacc);
|
||||
dy =float(yacc);
|
||||
}
|
||||
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::transitionOccured(CEventServer *server, const IInputDeviceEvent *)
|
||||
{
|
||||
updateMove(server);
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setButton(uint button, bool pushed)
|
||||
{
|
||||
nlassert(button < MaxNumMouseButtons);
|
||||
_MouseButtons[button] = pushed;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
bool CDIMouse::getButton(uint button) const
|
||||
{
|
||||
nlassert(button < MaxNumMouseButtons);
|
||||
return _MouseButtons[button];
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setDoubleClickDelay(uint ms)
|
||||
{
|
||||
nlassert(ms > 0);
|
||||
_DoubleClickDelay = ms;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMouseFrame(const CRect &rect)
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
_MouseFrame = rect;
|
||||
}
|
||||
|
||||
//======================================================
|
||||
void CDIMouse::setMessagesMode(TMessageMode mode)
|
||||
{
|
||||
nlassert(mode < MessageModeLast);
|
||||
_MessageMode = mode;
|
||||
_FirstX = _FirstY = true;
|
||||
|
||||
// Enable win32 mouse message only if hardware mouse in normal mode
|
||||
if (_WE)
|
||||
_WE->enableMouseEvents(_Hardware && (_MessageMode == NormalMode));
|
||||
}
|
||||
|
||||
|
||||
} // NLMISC
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,167 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef NL_DI_MOUSE_DEVICE_H
|
||||
#define NL_DI_MOUSE_DEVICE_H
|
||||
|
||||
#include "nel/misc/types_nl.h"
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
||||
|
||||
#include "nel/misc/rect.h"
|
||||
#include "nel/misc/di_event_emitter.h"
|
||||
#include "nel/misc/input_device_server.h"
|
||||
#include "nel/misc/mouse_device.h"
|
||||
#include <dinput.h>
|
||||
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
|
||||
//
|
||||
struct EDirectInputNoMouse : public EDirectInput
|
||||
{
|
||||
EDirectInputNoMouse() : EDirectInput("No mouse found") {}
|
||||
};
|
||||
|
||||
|
||||
class CDXEventEmitter;
|
||||
|
||||
|
||||
/**
|
||||
* Direct Input implementation of a mouse
|
||||
* \see CDIEventEmitter
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2002
|
||||
*/
|
||||
class CDIMouse : public IMouseDevice
|
||||
{
|
||||
public:
|
||||
enum { MaxNumMouseButtons = 3, NumMouseAxis = 3};
|
||||
public:
|
||||
///\name Object
|
||||
//@{
|
||||
virtual ~CDIMouse();
|
||||
/** Create a mouse device from a valid DirectInput8 pointer. This must then be deleted by the caller.
|
||||
* \return the interface or throw an exception if the creation failed
|
||||
*/
|
||||
static CDIMouse *createMouseDevice(IDirectInput8 *di8, HWND hwnd, CDIEventEmitter *diEventEmitter, bool hardware, class CWinEventEmitter *we) throw(EDirectInput);
|
||||
//@}
|
||||
|
||||
///\name Mouse params, inherited from IMouseDevice
|
||||
//@{
|
||||
void setMessagesMode(TMessageMode mode);
|
||||
TMessageMode getMessagesMode() const { return _MessageMode; }
|
||||
void setMouseMode(TAxis axis, TAxisMode axisMode);
|
||||
TAxisMode getMouseMode(TAxis axis) const;
|
||||
void setMouseSpeed(float speed);
|
||||
float getMouseSpeed() const;
|
||||
void setMouseAcceleration(uint speed);
|
||||
uint getMouseAcceleration() const;
|
||||
void setMouseFrame(const CRect &rect);
|
||||
const CRect &getMouseFrame() const;
|
||||
void setDoubleClickDelay(uint ms);
|
||||
uint getDoubleClickDelay() const;
|
||||
void setMousePos(float x, float y);
|
||||
void setFactors(float xFactor, float yFactor)
|
||||
{
|
||||
nlassert(_MessageMode == NormalMode);
|
||||
_XFactor = xFactor;
|
||||
_YFactor = yFactor;
|
||||
}
|
||||
float getXFactor() const { nlassert(_MessageMode == NormalMode); return _XFactor; }
|
||||
float getYFactor() const { nlassert(_MessageMode == NormalMode); return _YFactor; }
|
||||
void convertStdMouseMoveInMickeys(float &dx, float &dy) const;
|
||||
//@}
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
|
||||
virtual bool setBufferSize(uint size);
|
||||
virtual uint getBufferSize() const;
|
||||
//@}
|
||||
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
void setButton(uint button, bool pushed);
|
||||
bool getButton(uint button) const;
|
||||
//@}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
LPDIRECTINPUTDEVICE8 _Mouse;
|
||||
//
|
||||
bool _Hardware;
|
||||
//
|
||||
TMessageMode _MessageMode;
|
||||
//
|
||||
TAxisMode _MouseAxisMode[NumMouseAxis];
|
||||
sint64 _XMousePos, _YMousePos; // position encoded in fixed point 32 : 32. This allow wrapping and no loss of precision, when not in clamped mode
|
||||
// NB: this is sint64 because of max range reached with 16:16 when looping around x with great mouse speed
|
||||
bool _FirstX, _FirstY;
|
||||
float _MouseSpeed;
|
||||
uint _MouseAccel;
|
||||
CRect _MouseFrame;
|
||||
//
|
||||
bool _MouseButtons[MaxNumMouseButtons];
|
||||
uint32 _MouseButtonsLastClickDate;
|
||||
sint _LastMouseButtonClicked;
|
||||
uint _DoubleClickDelay;
|
||||
uint _MouseBufferSize;
|
||||
HWND _hWnd;
|
||||
//
|
||||
sint32 OldDIXPos, OldDIYPos, OldDIZPos; // old positions reported by direct input
|
||||
sint _XAcc, _YAcc; // accumulate move (needed because they are generated on a single axis for each DI event)
|
||||
float _XFactor, _YFactor;
|
||||
//
|
||||
CDIEventEmitter *_DIEventEmitter;
|
||||
// The windows emitter to enable / disble win32 mouse messages
|
||||
NLMISC::CRefPtr<CWinEventEmitter> _WE;
|
||||
// Does the button left and right are swapped ?
|
||||
bool _SwapButton;
|
||||
private:
|
||||
/// ctor
|
||||
CDIMouse();
|
||||
/// Clamp the mouse axis that need to be.
|
||||
void clampMouseAxis();
|
||||
/// Sum the mouse move and produce an event
|
||||
void updateMove(CEventServer *server);
|
||||
void processButton(uint button, bool pressed, CEventServer *server, uint32 date);
|
||||
TMouseButton buildMouseButtonFlags() const;
|
||||
TMouseButton buildMouseSingleButtonFlags(uint button);
|
||||
void onButtonClicked(uint button, CEventServer *server, uint32 date);
|
||||
///\name From IInputDevice
|
||||
//@{
|
||||
virtual void poll(CInputDeviceServer *dev);
|
||||
virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server);
|
||||
virtual void transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage);
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
} // NL3D
|
||||
|
||||
|
||||
#endif // NL_OS_WINDOWS
|
||||
|
||||
#endif // NL_DI_MOUSE_H
|
||||
|
||||
/* End of di_mouse.h */
|
@ -1,28 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
#include "nel/misc/game_device.h"
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC {
|
||||
|
||||
|
||||
|
||||
} // NLMISC
|
@ -1,33 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
#include "nel/misc/game_device_events.h"
|
||||
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
void dummyToAvoidStupidCompilerWarning_game_device_events_cpp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // NLMISC
|
@ -1,31 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
#include "nel/misc/input_device.h"
|
||||
|
||||
// remove stupid VC6 warnings
|
||||
void foo_input_device_cpp() {}
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
|
||||
|
||||
} // NLMISC
|
@ -1,109 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
|
||||
#include "nel/misc/input_device_server.h"
|
||||
#include "nel/misc/input_device.h"
|
||||
#include "nel/misc/debug.h"
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLMISC
|
||||
{
|
||||
//=======================================================================
|
||||
void CInputDeviceServer::registerDevice(IInputDevice *device)
|
||||
{
|
||||
nlassert(!isDevice(device));
|
||||
_Devices.push_back(device);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
void CInputDeviceServer::removeDevice(IInputDevice *device)
|
||||
{
|
||||
TDeviceCont::iterator it = std::find(_Devices.begin(), _Devices.end(), device);
|
||||
nlassert(it != _Devices.end());
|
||||
_Devices.erase(it);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
bool CInputDeviceServer::isDevice(IInputDevice *device) const
|
||||
{
|
||||
TDeviceCont::const_iterator it = std::find(_Devices.begin(), _Devices.end(), device);
|
||||
return it != _Devices.end();
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Predicate to compare vents dates
|
||||
struct CInputDeviceEventLess
|
||||
{
|
||||
bool operator()(const IInputDeviceEvent *lhs, const IInputDeviceEvent *rhs) const
|
||||
{
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
void CInputDeviceServer::poll(CEventServer *server)
|
||||
{
|
||||
nlassert(_Events.empty());
|
||||
TDeviceCont::iterator deviceIt;
|
||||
for (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt)
|
||||
{
|
||||
(*deviceIt)->begin(server);
|
||||
(*deviceIt)->poll(this);
|
||||
}
|
||||
// Sort the messages to get the right dates.
|
||||
std::sort(_Events.begin(), _Events.end(), CInputDeviceEventLess());
|
||||
// submit the result to the server
|
||||
IInputDevice *lastVisitedDevice = NULL;
|
||||
TEventCont::iterator eventIt;
|
||||
for (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt)
|
||||
{
|
||||
// see if this message is from a previous device then the last we visited.
|
||||
if (lastVisitedDevice && (*eventIt)->Emitter != lastVisitedDevice)
|
||||
{
|
||||
// yes, tells that a transition occured
|
||||
lastVisitedDevice->transitionOccured(server, *eventIt);
|
||||
lastVisitedDevice = (*eventIt)->Emitter;
|
||||
}
|
||||
nlassert((*eventIt)->Emitter != NULL);
|
||||
(*eventIt)->Emitter->submit(*eventIt, server);
|
||||
}
|
||||
//
|
||||
for (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt)
|
||||
{
|
||||
(*deviceIt)->transitionOccured(server, NULL);
|
||||
}
|
||||
// delete the messages
|
||||
for (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt)
|
||||
{
|
||||
delete *eventIt;
|
||||
}
|
||||
//
|
||||
_Events.clear();
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
void CInputDeviceServer::submitEvent(IInputDeviceEvent *deviceEvent)
|
||||
{
|
||||
_Events.push_back(deviceEvent);
|
||||
}
|
||||
|
||||
|
||||
} // NLMISC
|
@ -1,36 +0,0 @@
|
||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdmisc.h"
|
||||
|
||||
//#include "nel/3d/u_keyboard_device.h"
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NL3D {
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
/*UKeyboardDevice::UKeyboardDevice()
|
||||
{
|
||||
}*/
|
||||
|
||||
|
||||
} // NL3D
|
Loading…
Reference in New Issue