Fixed: #972 Do not reset mouse position to implement FreeLook (IDriver::InterfaceVersion = 0x66)

This commit is contained in:
rti 2010-06-11 15:04:10 +02:00
parent d74bf9a642
commit 610a04982f
16 changed files with 260 additions and 129 deletions

View file

@ -413,6 +413,12 @@ public:
// //
virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable); virtual NLMISC::IKeyboardDevice *enableLowLevelKeyboard(bool enable);
virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager(); virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager();
/**
* wrapper for IEventEmitter::emulateMouseRawMode()
*/
virtual void emulateMouseRawMode(bool enable);
virtual uint getDoubleClickDelay(bool hardwareMouse); virtual uint getDoubleClickDelay(bool hardwareMouse);
/// show cursor if b is true, or hide it if b is false /// show cursor if b is true, or hide it if b is false

View file

@ -571,6 +571,11 @@ public:
*/ */
virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager() = 0; virtual NLMISC::IInputDeviceManager *getLowLevelInputDeviceManager() = 0;
/**
* wrapper for IEventEmitter::emulateMouseRawMode()
*/
virtual void emulateMouseRawMode(bool enable) = 0;
// get delay used for mouse double click // get delay used for mouse double click
virtual uint getDoubleClickDelay(bool hardwareMouse) = 0; virtual uint getDoubleClickDelay(bool hardwareMouse) = 0;

View file

@ -50,6 +50,18 @@ public:
*/ */
virtual void submitEvents(CEventServer & server, bool allWindows) = 0; virtual void submitEvents(CEventServer & server, bool allWindows) = 0;
/**
* Instruct the event emitter to send CGDMouseMove instead of CEventMouseMove.
*
* On windows, the mouse device can be set into RawMode. Using this mode,
* CGDMouseMove events (only containing the raw movement delta) are emitted
* instead of the normal CEventMouseMove events (containing the mouse position).
*
* On Linux and Mac OS X, there is no MouseDevice implementation, all the
* events are created by the event emitter. So the event emitter has to
* emulate the mouse raw mode.
*/
virtual void emulateMouseRawMode(bool) = 0;
}; };

View file

@ -99,6 +99,9 @@ public:
* Return true if the message must be trapped, false if DefWindowProc must be called afterwards * Return true if the message must be trapped, false if DefWindowProc must be called afterwards
*/ */
bool processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server=NULL); bool processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server=NULL);
void emulateMouseRawMode(bool enable);
private: private:
CWinEventServer _InternalServer; CWinEventServer _InternalServer;
HWND _HWnd; HWND _HWnd;

View file

@ -34,7 +34,7 @@ namespace NL3D
{ {
// *************************************************************************** // ***************************************************************************
const uint32 IDriver::InterfaceVersion = 0x65; // Added nlWindow patch. const uint32 IDriver::InterfaceVersion = 0x66; // added IEventEmitter::emulateMouseRawMode(bool)
// *************************************************************************** // ***************************************************************************
IDriver::IDriver() : _SyncTexDrvInfos( "IDriver::_SyncTexDrvInfos" ) IDriver::IDriver() : _SyncTexDrvInfos( "IDriver::_SyncTexDrvInfos" )

View file

@ -89,6 +89,9 @@ void release();
void submitEvents(NLMISC::CEventServer& server, void submitEvents(NLMISC::CEventServer& server,
bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter); bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter);
/// mac specific stuff while calling CCocoaEventEmitter::emulateMouseRawMode()
void emulateMouseRawMode(bool enable);
}} }}
#endif #endif

View file

@ -19,6 +19,7 @@
#include "cocoa_adapter.h" #include "cocoa_adapter.h"
#include "nel/misc/events.h" #include "nel/misc/events.h"
#include "nel/misc/game_device_events.h"
#include "nel/3d/driver.h" #include "nel/3d/driver.h"
#include "cocoa_event_emitter.h" #include "cocoa_event_emitter.h"
@ -38,6 +39,8 @@ static NSAutoreleasePool* g_pool = nil;
static CocoaWindow* g_window = nil; static CocoaWindow* g_window = nil;
static CocoaOpenGLView* g_glview = nil; static CocoaOpenGLView* g_glview = nil;
static NSOpenGLContext* g_glctx = nil; static NSOpenGLContext* g_glctx = nil;
static bool g_emulateRawMode = false;
#define UGLY_BACKBUFFER_SIZE_WORKAROUND #define UGLY_BACKBUFFER_SIZE_WORKAROUND
@ -78,6 +81,10 @@ bool setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable)
TODO use show and resizable flags TODO use show and resizable flags
*/ */
/*
TODO add menu, on quit send EventDestroyWindowId
*/
// create a cocoa window with the size provided by the mode parameter // create a cocoa window with the size provided by the mode parameter
g_window = [[CocoaWindow alloc] g_window = [[CocoaWindow alloc]
initWithContentRect:NSMakeRect(0, 0, mode.Width, mode.Height) initWithContentRect:NSMakeRect(0, 0, mode.Width, mode.Height)
@ -130,7 +137,7 @@ bool setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable)
// enable mouse move events, NeL wants them // enable mouse move events, NeL wants them
[g_window setAcceptsMouseMovedEvents:YES]; [g_window setAcceptsMouseMovedEvents:YES];
// there are no overlapping subview, so we can use the magical optimization! // there are no overlapping subviews, so we can use the magical optimization!
[g_window useOptimizedDrawing:YES]; [g_window useOptimizedDrawing:YES];
// create a opengl context for the view // create a opengl context for the view
@ -139,7 +146,7 @@ bool setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable)
if(!g_glctx) if(!g_glctx)
nlerror("cannot create context"); nlerror("cannot create context");
// make the views opengl context the currrent one // make the view's opengl context the currrent one
[g_glctx makeCurrentContext]; [g_glctx makeCurrentContext];
// put the window to the front and make it the key window // put the window to the front and make it the key window
@ -178,9 +185,6 @@ bool setMode(const GfxMode& mode)
// leave fullscreen mode, enter windowed mode // leave fullscreen mode, enter windowed mode
if(mode.Windowed && [g_glview isInFullScreenMode]) if(mode.Windowed && [g_glview isInFullScreenMode])
{ {
// pull the view back from fullscreen restoring window options
[g_glview exitFullScreenModeWithOptions:nil];
// disable manual setting of back buffer size, cocoa handles this // disable manual setting of back buffer size, cocoa handles this
// automatically as soon as the view gets resized // automatically as soon as the view gets resized
CGLError error = CGLDisable((CGLContextObj)[g_glctx CGLContextObj], CGLError error = CGLDisable((CGLContextObj)[g_glctx CGLContextObj],
@ -189,6 +193,9 @@ bool setMode(const GfxMode& mode)
if(error != kCGLNoError) if(error != kCGLNoError)
nlerror("cannot disable kCGLCESurfaceBackingSize (%s)", nlerror("cannot disable kCGLCESurfaceBackingSize (%s)",
CGLErrorString(error)); CGLErrorString(error));
// pull the view back from fullscreen restoring window options
[g_glview exitFullScreenModeWithOptions:nil];
} }
// enter fullscreen, leave windowed mode // enter fullscreen, leave windowed mode
@ -205,20 +212,21 @@ bool setMode(const GfxMode& mode)
// put the view in fullscreen mode, hiding the dock but enabling the menubar // put the view in fullscreen mode, hiding the dock but enabling the menubar
// to pop up if the mouse hits the top screen border. // to pop up if the mouse hits the top screen border.
// NOTE: withOptions:nil disables <CMD>+<Tab> application switching! // NOTE: withOptions:nil disables <CMD>+<Tab> application switching!
/*
TODO check if simply using NSView enterFullScreenMode is a good idea.
the context can be set to full screen as well, performance differences?
*/
[g_glview enterFullScreenMode:[NSScreen mainScreen] withOptions: [g_glview enterFullScreenMode:[NSScreen mainScreen] withOptions:
[NSDictionary dictionaryWithObjectsAndKeys: [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: [NSNumber numberWithInt:
NSApplicationPresentationHideDock | NSApplicationPresentationHideDock |
NSApplicationPresentationAutoHideMenuBar], NSApplicationPresentationAutoHideMenuBar],
NSFullScreenModeApplicationPresentationOptions, nil]]; NSFullScreenModeApplicationPresentationOptions, nil]];
/*
TODO check if simply using NSView enterFullScreenMode is a good idea.
the context can be set to full screen as well, performance differences?
*/
} }
#ifdef UGLY_BACKBUFFER_SIZE_WORKAROUND #ifdef UGLY_BACKBUFFER_SIZE_WORKAROUND
// due to the back buffer size reading problem, just store the size // due to a back buffer size reading problem, just store the size
g_bufferSize[0] = mode.Width; g_bufferSize[0] = mode.Width;
g_bufferSize[1] = mode.Height; g_bufferSize[1] = mode.Height;
#endif #endif
@ -240,13 +248,18 @@ void getWindowSize(uint32 &width, uint32 &height)
// not the one from the window. // not the one from the window.
#ifdef UGLY_BACKBUFFER_SIZE_WORKAROUND #ifdef UGLY_BACKBUFFER_SIZE_WORKAROUND
// in fullscreen mode
if([g_glview isInFullScreenMode]) if([g_glview isInFullScreenMode])
{ {
// use the size stored in setMode()
width = g_bufferSize[0]; width = g_bufferSize[0];
height = g_bufferSize[1]; height = g_bufferSize[1];
} }
// in windowed mode
else else
{ {
// use the size of the view
NSRect rect = [g_glview frame]; NSRect rect = [g_glview frame];
width = rect.size.width; width = rect.size.width;
height = rect.size.height; height = rect.size.height;
@ -264,7 +277,7 @@ void getWindowSize(uint32 &width, uint32 &height)
nlerror("cannot check kCGLCESurfaceBackingSize state (%s)", nlerror("cannot check kCGLCESurfaceBackingSize state (%s)",
CGLErrorString(error)); CGLErrorString(error));
// if in fullscreen mode // if in fullscreen mode (only in fullscreen back buffer sizing is used)
if(surfaceBackingSizeSet) if(surfaceBackingSizeSet)
{ {
/* /*
@ -341,20 +354,13 @@ void swapBuffers()
void setCapture(bool b) void setCapture(bool b)
{ {
/* // no need to capture
TODO implement capture cursor, no need to fake using pull back to 0.5 / 0.5
set a flag and then act accordingly in event loop?
// no screen bounds...
void CGGetLastMouseDelta(CGMouseDelta* deltaX, CGMouseDelta* deltaY);
*/
nlwarning("not implemented");
} }
void showCursor(bool b) void showCursor(bool b)
{ {
// Mac OS manages a show/hide counter for the cursor, so hiding the cursor // Mac OS manages a show/hide counter for the cursor, so hiding the cursor
// twice requires two calls to show to make the cursor visible again. // twice requires two calls to "show" to make the cursor visible again.
// Since other platforms seem to not do this, the functionality is masked here // Since other platforms seem to not do this, the functionality is masked here
// by only calling hide if the cursor is visible and only calling show if // by only calling hide if the cursor is visible and only calling show if
// the cursor was hidden. // the cursor was hidden.
@ -379,6 +385,10 @@ void showCursor(bool b)
void setMousePos(float x, float y) void setMousePos(float x, float y)
{ {
/*
TODO FIXME for windows placed on non primary monitor
*/
// CG wants absolute coordinates related to screen top left // CG wants absolute coordinates related to screen top left
CGFloat fromScreenLeft = 0.0; CGFloat fromScreenLeft = 0.0;
CGFloat fromScreenTop = 0.0; CGFloat fromScreenTop = 0.0;
@ -571,7 +581,7 @@ NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags)
bool isTextKeyEvent(NSEvent* event) bool isTextKeyEvent(NSEvent* event)
{ {
// if there are no characters provided with this event, is is not a text event // if there are no characters provided with this event, it is not a text event
if([[event characters] length] == 0) if([[event characters] length] == 0)
return false; return false;
@ -621,6 +631,11 @@ bool isTextKeyEvent(NSEvent* event)
return false; return false;
} }
void emulateMouseRawMode(bool enable)
{
g_emulateRawMode = enable;
}
void submitEvents(NLMISC::CEventServer& server, void submitEvents(NLMISC::CEventServer& server,
bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter) bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter)
{ {
@ -641,8 +656,6 @@ void submitEvents(NLMISC::CEventServer& server,
if(!event) if(!event)
break; break;
// NSLog(@"%@", event);
// get the views size // get the views size
NSRect rect = [g_glview frame]; NSRect rect = [g_glview frame];
@ -651,7 +664,7 @@ void submitEvents(NLMISC::CEventServer& server,
float mouseX = event.locationInWindow.x / (float)rect.size.width; float mouseX = event.locationInWindow.x / (float)rect.size.width;
float mouseY = event.locationInWindow.y / (float)rect.size.height; float mouseY = event.locationInWindow.y / (float)rect.size.height;
// if the mouse event was placed on the window's titlebar, ignore it // if the mouse event was placed on the window's titlebar, don't tell NeL :)
if(mouseY > 1.0 && event.type != NSKeyDown && event.type != NSKeyUp) if(mouseY > 1.0 && event.type != NSKeyDown && event.type != NSKeyUp)
{ {
[g_app sendEvent:event]; [g_app sendEvent:event];
@ -662,58 +675,106 @@ void submitEvents(NLMISC::CEventServer& server,
switch(event.type) switch(event.type)
{ {
case NSLeftMouseDown: case NSLeftMouseDown:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseDown( server.postEvent(new NLMISC::CEventMouseDown(
mouseX, mouseY, NLMISC::leftButton /* modifiers */, eventEmitter)); mouseX, mouseY, NLMISC::leftButton /* modifiers */, eventEmitter));
}
break; break;
case NSLeftMouseUp: case NSLeftMouseUp:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseUp( server.postEvent(new NLMISC::CEventMouseUp(
mouseX, mouseY, NLMISC::leftButton /* modifiers */, eventEmitter)); mouseX, mouseY, NLMISC::leftButton /* modifiers */, eventEmitter));
break; break;
}
case NSRightMouseDown: case NSRightMouseDown:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseDown( server.postEvent(new NLMISC::CEventMouseDown(
mouseX, mouseY, NLMISC::rightButton /* modifiers */, eventEmitter)); mouseX, mouseY, NLMISC::rightButton /* modifiers */, eventEmitter));
break; break;
}
case NSRightMouseUp: case NSRightMouseUp:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseUp( server.postEvent(new NLMISC::CEventMouseUp(
mouseX, mouseY, NLMISC::rightButton /* modifiers */, eventEmitter)); mouseX, mouseY, NLMISC::rightButton /* modifiers */, eventEmitter));
break; break;
}
case NSMouseMoved: case NSMouseMoved:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseMove( NLMISC::CEvent* nelEvent;
mouseX, mouseY, (NLMISC::TMouseButton)0 /* modifiers */, eventEmitter));
break;
case NSLeftMouseDragged:
/*
TODO modifiers with mouse events
*/
// nldebug("mouse left drag %f %f", mouseX, mouseY);
server.postEvent(new NLMISC::CEventMouseMove( // when emulating raw mode, send the delta in a CGDMouseMove event
mouseX, mouseY, NLMISC::leftButton /* modifiers */, eventEmitter)); if(g_emulateRawMode)
nelEvent = new NLMISC::CGDMouseMove(
eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY);
// normally send position in a CEventMouseMove
else
nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY,
(NLMISC::TMouseButton)0 /* modifiers */, eventEmitter);
server.postEvent(nelEvent);
break; break;
case NSRightMouseDragged:break; }
case NSLeftMouseDragged:
{
/* /*
TODO modifiers with mouse events TODO modifiers with mouse events
*/ */
server.postEvent(new NLMISC::CEventMouseMove( NLMISC::CEvent* nelEvent;
mouseX, mouseY, NLMISC::rightButton /* modifiers */, eventEmitter));
// when emulating raw mode, send the delta in a CGDMouseMove event
if(g_emulateRawMode)
nelEvent = new NLMISC::CGDMouseMove(
eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY);
// normally send position in a CEventMouseMove
else
nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY,
NLMISC::leftButton /* modifiers */, eventEmitter);
server.postEvent(nelEvent);
break;
}
case NSRightMouseDragged:
{
/*
TODO modifiers with mouse events
*/
NLMISC::CEvent* nelEvent;
// when emulating raw mode, send the delta in a CGDMouseMove event
if(g_emulateRawMode)
nelEvent = new NLMISC::CGDMouseMove(
eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY);
// normally send position in a CEventMouseMove
else
nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY,
NLMISC::rightButton /* modifiers */, eventEmitter);
server.postEvent(nelEvent);
break;
}
case NSMouseEntered:break; case NSMouseEntered:break;
case NSMouseExited:break; case NSMouseExited:break;
case NSKeyDown: case NSKeyDown:
{
// push the key press event to the event server // push the key press event to the event server
server.postEvent(new NLMISC::CEventKeyDown( server.postEvent(new NLMISC::CEventKeyDown(
virtualKeycodeToNelKey([event keyCode]), virtualKeycodeToNelKey([event keyCode]),
@ -736,13 +797,16 @@ void submitEvents(NLMISC::CEventServer& server,
eventEmitter)); eventEmitter));
} }
break; break;
}
case NSKeyUp: case NSKeyUp:
{
// push the key release event to the event server // push the key release event to the event server
server.postEvent(new NLMISC::CEventKeyUp( server.postEvent(new NLMISC::CEventKeyUp(
virtualKeycodeToNelKey([event keyCode]), virtualKeycodeToNelKey([event keyCode]),
modifierFlagsToNelKeyButton([event modifierFlags]), modifierFlagsToNelKeyButton([event modifierFlags]),
eventEmitter)); eventEmitter));
break; break;
}
case NSFlagsChanged:break; case NSFlagsChanged:break;
case NSAppKitDefined:break; case NSAppKitDefined:break;
case NSSystemDefined:break; case NSSystemDefined:break;
@ -762,10 +826,12 @@ void submitEvents(NLMISC::CEventServer& server,
case NSEventTypeBeginGesture:break; case NSEventTypeBeginGesture:break;
case NSEventTypeEndGesture:break; case NSEventTypeEndGesture:break;
default: default:
{
nlwarning("Unknown event type. dropping."); nlwarning("Unknown event type. dropping.");
// NSLog(@"%@", event); // NSLog(@"%@", event);
break; break;
} }
}
[g_app sendEvent:event]; [g_app sendEvent:event];
[g_app updateWindows]; [g_app updateWindows];

View file

@ -27,4 +27,10 @@ void CCocoaEventEmitter::submitEvents(CEventServer & server, bool allWindows)
NL3D::MAC::submitEvents(server, allWindows, this); NL3D::MAC::submitEvents(server, allWindows, this);
} }
void CCocoaEventEmitter::emulateMouseRawMode(bool enable)
{
// just forwarding to our cocoa adapter
NL3D::MAC::emulateMouseRawMode(enable);
}
} }

View file

@ -26,6 +26,7 @@ class CCocoaEventEmitter : public IEventEmitter
{ {
public: public:
virtual void submitEvents(CEventServer & server, bool allWindows); virtual void submitEvents(CEventServer & server, bool allWindows);
virtual void emulateMouseRawMode(bool enable);
}; };
} }

View file

@ -29,7 +29,7 @@
namespace NLMISC { namespace NLMISC {
CUnixEventEmitter::CUnixEventEmitter ():_dpy(NULL), _win(0), _PreviousKey(KeyNOKEY) CUnixEventEmitter::CUnixEventEmitter ():_dpy(NULL), _win(0), _PreviousKey(KeyNOKEY), _emulateRawMode(false)
{ {
_im = 0; _im = 0;
_ic = 0; _ic = 0;
@ -83,6 +83,19 @@ void CUnixEventEmitter::submitEvents(CEventServer & server, bool allWindows)
} }
} }
void CUnixEventEmitter::emulateMouseRawMode(bool enable)
{
_emulateRawMode = enable;
if(_emulateRawMode)
{
XWindowAttributes xwa;
XGetWindowAttributes(_dpy, _win, &xwa);
XWarpPointer(_dpy, None, _win, None, None, None, None,
(xwa.width / 2), (xwa.height / 2));
}
}
#ifndef AltMask #ifndef AltMask
# ifdef NL_OS_MAC # ifdef NL_OS_MAC
# define AltMask (8192) # define AltMask (8192)
@ -120,6 +133,9 @@ TKey getKeyFromKeycode (uint keycode)
switch (keycode) switch (keycode)
{ {
#ifdef NL_OS_MAC #ifdef NL_OS_MAC
/*
TODO use key mapping from driver/opengl/mac/cocoa_adapter.mm
*/
case 0x12: return Key1; case 0x12: return Key1;
case 0x13: return Key2; case 0x13: return Key2;
case 0x14: return Key3; case 0x14: return Key3;
@ -316,6 +332,9 @@ TKey getKeyFromKeySym (KeySym keysym)
void CUnixEventEmitter::processMessage (XEvent &event, CEventServer &server) void CUnixEventEmitter::processMessage (XEvent &event, CEventServer &server)
{ {
XWindowAttributes xwa;
XGetWindowAttributes (_dpy, _win, &xwa);
switch (event.type) switch (event.type)
{ {
Case(ReparentNotify) Case(ReparentNotify)
@ -325,8 +344,6 @@ void CUnixEventEmitter::processMessage (XEvent &event, CEventServer &server)
Case(ButtonPress) Case(ButtonPress)
{ {
//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y); //nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
XWindowAttributes xwa;
XGetWindowAttributes (_dpy, _win, &xwa);
float fX = (float) event.xbutton.x / (float) xwa.width; float fX = (float) event.xbutton.x / (float) xwa.width;
float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height; float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
TMouseButton button=getMouseButton(event.xbutton.state); TMouseButton button=getMouseButton(event.xbutton.state);
@ -353,8 +370,6 @@ void CUnixEventEmitter::processMessage (XEvent &event, CEventServer &server)
Case(ButtonRelease) Case(ButtonRelease)
{ {
//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y); //nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
XWindowAttributes xwa;
XGetWindowAttributes (_dpy, _win, &xwa);
float fX = (float) event.xbutton.x / (float) xwa.width; float fX = (float) event.xbutton.x / (float) xwa.width;
float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height; float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
switch(event.xbutton.button) switch(event.xbutton.button)
@ -373,13 +388,36 @@ void CUnixEventEmitter::processMessage (XEvent &event, CEventServer &server)
} }
Case(MotionNotify) Case(MotionNotify)
{ {
XWindowAttributes xwa; TMouseButton button=getMouseButton (event.xbutton.state);
XGetWindowAttributes (_dpy, _win, &xwa);
// if raw mode should be emulated
if(_emulateRawMode)
{
// when we just wrapped back the pointer to 0.5 / 0.5, ignore event
if(event.xbutton.x == xwa.width / 2 && event.xbutton.y == xwa.height / 2)
break;
// post a CGDMouseMove with the movement delta to the event server
server.postEvent(
new CGDMouseMove(this, NULL /* no mouse device */,
event.xbutton.x - (xwa.width / 2),
(xwa.height / 2) - event.xbutton.y));
// move the pointer back to the center of the window
XWarpPointer(_dpy, None, _win, None, None, None, None,
(xwa.width / 2), (xwa.height / 2));
}
// if in normal mouse mode
else
{
// get the relative mouse position
float fX = (float) event.xbutton.x / (float) xwa.width; float fX = (float) event.xbutton.x / (float) xwa.width;
float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height; float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
if ((fX == 0.5f) && (fY == 0.5f)) break;
TMouseButton button=getMouseButton (event.xbutton.state); // post a normal mouse move event to the event server
server.postEvent (new CEventMouseMove (fX, fY, button, this)); server.postEvent (new CEventMouseMove (fX, fY, button, this));
}
break; break;
} }
Case(KeyPress) Case(KeyPress)

View file

@ -22,6 +22,7 @@
#include "nel/misc/types_nl.h" #include "nel/misc/types_nl.h"
#include "nel/misc/event_emitter.h" #include "nel/misc/event_emitter.h"
#include "nel/misc/events.h" #include "nel/misc/events.h"
#include "nel/misc/game_device_events.h"
#ifdef NL_OS_UNIX #ifdef NL_OS_UNIX
@ -54,6 +55,8 @@ public:
*/ */
virtual void submitEvents(CEventServer & server, bool allWindows); virtual void submitEvents(CEventServer & server, bool allWindows);
virtual void emulateMouseRawMode(bool);
public: public:
void processMessage (XEvent &event, CEventServer &server); void processMessage (XEvent &event, CEventServer &server);
@ -65,6 +68,7 @@ private:
TKey _PreviousKey; TKey _PreviousKey;
XIM _im; XIM _im;
XIC _ic; XIC _ic;
bool _emulateRawMode;
}; };

View file

@ -34,6 +34,7 @@
#include "nel/3d/water_pool_manager.h" #include "nel/3d/water_pool_manager.h"
#include "nel/3d/u_camera.h" #include "nel/3d/u_camera.h"
#include "nel/misc/hierarchical_timer.h" #include "nel/misc/hierarchical_timer.h"
#include "nel/misc/event_emitter.h"
using namespace NLMISC; using namespace NLMISC;
@ -1594,6 +1595,11 @@ NLMISC::IKeyboardDevice *CDriverUser::enableLowLevelKeyboard(bool enable)
return _Driver->enableLowLevelKeyboard(enable); return _Driver->enableLowLevelKeyboard(enable);
} }
void CDriverUser::emulateMouseRawMode(bool enable)
{
_Driver->getEventEmitter()->emulateMouseRawMode(enable);
}
uint CDriverUser::getDoubleClickDelay(bool hardwareMouse) uint CDriverUser::getDoubleClickDelay(bool hardwareMouse)
{ {
NL3D_HAUTO_UI_DRIVER; NL3D_HAUTO_UI_DRIVER;

View file

@ -52,6 +52,13 @@ void CWinEventEmitter::submitEvents(CEventServer & server, bool allWindows)
_InternalServer.pump (allWindows); _InternalServer.pump (allWindows);
} }
/*------------------------------------------------------------------*\
emulateMouseRawMode()
\*------------------------------------------------------------------*/
void CWinEventEmitter::emulateMouseRawMode(bool enable)
{
nlerror("no raw mode emulation on windows, the CDIMouse has a real raw mode");
}
/*------------------------------------------------------------------*\ /*------------------------------------------------------------------*\
processMessage() processMessage()

View file

@ -145,16 +145,11 @@ void CEventsListener::operator()(const CEvent& event)
// Event from the Mouse (ANGLE) // Event from the Mouse (ANGLE)
if(event == EventGDMouseMove) if(event == EventGDMouseMove)
{ {
#ifdef NL_OS_WINDOWS
CGDMouseMove* mouseEvent=(CGDMouseMove*)&event; CGDMouseMove* mouseEvent=(CGDMouseMove*)&event;
// Mouse acceleration // Mouse acceleration
sint dX = mouseEvent->X; sint dX = mouseEvent->X;
sint dY = ClientCfg.FreeLookInverted ? -mouseEvent->Y : mouseEvent->Y; sint dY = ClientCfg.FreeLookInverted ? -mouseEvent->Y : mouseEvent->Y;
updateFreeLookPos((float) dX, (float) dY); updateFreeLookPos((float) dX, (float) dY);
#else
// just to make sure that there is no game device implementation un unix
nlerror("not expecting EventGDMouseMove on unix");
#endif
} }
// Event from the Mouse (MOVE) // Event from the Mouse (MOVE)
else if(event == EventMouseMoveId) else if(event == EventMouseMoveId)

View file

@ -198,20 +198,24 @@ void UpdateMouse ()
// Raw mode // Raw mode
if (MouseDevice) if (MouseDevice)
{ {
MouseDevice->setMessagesMode(IMouseDevice::RawMode); MouseDevice->setMessagesMode(IMouseDevice::RawMode);
MouseDevice->setMouseAcceleration(ClientCfg.FreeLookAcceleration); MouseDevice->setMouseAcceleration(ClientCfg.FreeLookAcceleration);
} }
else
{
// no mouse device implementation on X11 and Cocoa, emulate raw mode
Driver->emulateMouseRawMode(true);
}
} }
else else
{
// Set the mouse properties
if (MouseDevice)
{ {
// Get the driver size // Get the driver size
uint32 width, height; uint32 width, height;
Driver->getWindowSize(width, height); Driver->getWindowSize(width, height);
// Set the mouse properties
if (MouseDevice)
{
MouseDevice->setMessagesMode(IMouseDevice::NormalMode); MouseDevice->setMessagesMode(IMouseDevice::NormalMode);
MouseDevice->setMouseMode(IMouseDevice::XAxis, IMouseDevice::Clamped); MouseDevice->setMouseMode(IMouseDevice::XAxis, IMouseDevice::Clamped);
MouseDevice->setMouseMode(IMouseDevice::YAxis, IMouseDevice::Clamped); MouseDevice->setMouseMode(IMouseDevice::YAxis, IMouseDevice::Clamped);
@ -221,6 +225,11 @@ void UpdateMouse ()
MouseDevice->setMouseSpeed(MouseCursorSpeed); MouseDevice->setMouseSpeed(MouseCursorSpeed);
MouseDevice->setMouseAcceleration(MouseCursorAcceleration); MouseDevice->setMouseAcceleration(MouseCursorAcceleration);
} }
else
{
// no mouse device implementation on X11 and Cocoa, emulate raw mode
Driver->emulateMouseRawMode(false);
}
} }
if (!IsSystemCursorCaptured()) if (!IsSystemCursorCaptured())
{ {
@ -249,13 +258,6 @@ void SetMouseFreeLook ()
} }
UpdateMouse (); UpdateMouse ();
} }
#ifdef NL_OS_UNIX
// on X11 and cocoa the mouse needs to get pulled into the middle each update,
// else the cursor would reach the border of the window / desktop
// and freelook would hang
Driver->setMousePos(0.5f, 0.5f);
#endif
} }
//********************************************************************************* //*********************************************************************************
@ -404,6 +406,9 @@ bool IsSystemCursorCaptured()
#ifdef NL_OS_WINDOWS #ifdef NL_OS_WINDOWS
return GetCapture() == Driver->getDisplay(); return GetCapture() == Driver->getDisplay();
#else #else
/*
TODO there should be a way to ask the driver if capturing is on or off
*/
return MouseCapture; return MouseCapture;
#endif #endif
} }

View file

@ -427,72 +427,46 @@ void CUserControls::getMouseAngleMove(float &dx, float &dy)
dx = 0.0f; dx = 0.0f;
dy = 0.0f; dy = 0.0f;
// The mouse may still "StandardMove" ie through a CEventMouseMove // The mouse may still "StandardMove" ie through a CEventMouseMove
// This can happens cause DirectInputDisabled, or because of the "Rotation Anti-Lag system" // This can happens cause DirectInputDisabled, or because of the
// which start to rotate before the mouse is hid and message mode passed to RawMode // "Rotation Anti-Lag system" which start to rotate before the mouse is hid
// and message mode passed to RawMode
// //
// If we are not on Windows; on X11 there is always StandardMove/CEventMouseMove. // On X11 and Cocoa, there is no MouseDevice, do it without.
// Currently, there is only a direct input IMouseDevice, not available on X11.
#ifdef NL_OS_WINDOWS
extern IMouseDevice *MouseDevice; extern IMouseDevice *MouseDevice;
if (MouseDevice)
{ // if the mouse position changed
if( EventsListener.getMousePosX() != _LastFrameMousePosX || if( EventsListener.getMousePosX() != _LastFrameMousePosX ||
EventsListener.getMousePosY() != _LastFrameMousePosY ) EventsListener.getMousePosY() != _LastFrameMousePosY )
{ {
// get the mouse movement delta
float dmpx= EventsListener.getMousePosX() - _LastFrameMousePosX; float dmpx= EventsListener.getMousePosX() - _LastFrameMousePosX;
float dmpy= EventsListener.getMousePosY() - _LastFrameMousePosY; float dmpy= EventsListener.getMousePosY() - _LastFrameMousePosY;
// simulate mickeys mode
MouseDevice->convertStdMouseMoveInMickeys(dmpx, dmpy);
if(ClientCfg.FreeLookInverted) dmpy = -dmpy;
// update free look
EventsListener.updateFreeLookPos(dmpx, dmpy);
}
}
#else
// On X11 and Mac, do the thing without IMouseDevice implementation
if( EventsListener.getMousePosX() != _LastFrameMousePosX ||
EventsListener.getMousePosY() != _LastFrameMousePosY )
{
float dmpx, dmpy;
// On X11 and Cocoa in free look mode, the mouse is pulled back to (0.5, 0.5) // simulate mickeys mode if there is a mouse device
// every update to prevent reaching a border and get stuck. if (MouseDevice)
if(IsMouseFreeLook()) MouseDevice->convertStdMouseMoveInMickeys(dmpx, dmpy);
{
/*
TODO on X11, use setCapture to not fake it, capture on mac?
*/
dmpx = EventsListener.getMousePosX() - 0.5;
dmpy = EventsListener.getMousePosY() - 0.5;
}
else else
{ {
dmpx = EventsListener.getMousePosX() - _LastFrameMousePosX; dmpx *= (float)Driver->getWindowWidth();
dmpy = EventsListener.getMousePosY() - _LastFrameMousePosY; dmpy *= (float)Driver->getWindowHeight();
} }
// TODO: read desktop mouse speed value on X11 and Cocoa // handle inverted mouse, if enabled
// implement X11MouseDevice/CocoaMouseDevice?
dmpx *= 450.0f;
dmpy *= 450.0f;
if(ClientCfg.FreeLookInverted) dmpy = -dmpy; if(ClientCfg.FreeLookInverted) dmpy = -dmpy;
// update free look // update free look
EventsListener.updateFreeLookPos(dmpx, dmpy); EventsListener.updateFreeLookPos(dmpx, dmpy);
} }
#endif
// If the mouse move on the axis X, with a CGDMouseMove // If the mouse move on the axis X, with a CGDMouseMove
if(EventsListener.isMouseAngleX()) if(EventsListener.isMouseAngleX())
dx = -EventsListener.getMouseAngleX (); dx = -EventsListener.getMouseAngleX ();
// If the mouse move on the axis Y, with a CGDMouseMove // If the mouse move on the axis Y, with a CGDMouseMove
if(EventsListener.isMouseAngleY()) if(EventsListener.isMouseAngleY())
dy = EventsListener.getMouseAngleY (); dy = EventsListener.getMouseAngleY ();
} }