Skip to content

Commit

Permalink
Refactor|libgui|Client: Mouse and keyboard input routing
Browse files Browse the repository at this point in the history
ClientWindow now listens to the input notifications from its Canvas
and submits appropriate input events. Canvas was further isolated
from concrete implementation of mouse trapping (which will be done
by an input driver).
  • Loading branch information
skyjake committed Apr 6, 2013
1 parent a1d38b0 commit adca39d
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 86 deletions.
4 changes: 1 addition & 3 deletions doomsday/client/include/ui/clientwindow.h
Expand Up @@ -42,8 +42,7 @@
*/
class ClientWindow : public de::PersistentCanvasWindow,
DENG2_OBSERVES(de::Canvas, GLInit),
DENG2_OBSERVES(de::Canvas, GLResize),
DENG2_OBSERVES(de::Canvas, FocusChange)
DENG2_OBSERVES(de::Canvas, GLResize)
{
Q_OBJECT

Expand Down Expand Up @@ -105,7 +104,6 @@ class ClientWindow : public de::PersistentCanvasWindow,
void canvasGLInit(de::Canvas &);
void canvasGLDraw(de::Canvas &);
void canvasGLResized(de::Canvas &);
void canvasFocusChanged(de::Canvas &, bool hasFocus);

static ClientWindow &main();

Expand Down
2 changes: 2 additions & 0 deletions doomsday/client/include/ui/sys_input.h
Expand Up @@ -51,6 +51,8 @@ enum {
IMB_RIGHT,
IMB_MWHEELUP, // virtual button
IMB_MWHEELDOWN, // virtual button
IMB_EXTRA1,
IMB_EXTRA2,
// ...other buttons...
IMB_MWHEELLEFT = 14, // virtual button
IMB_MWHEELRIGHT = 15, // virtual button
Expand Down
124 changes: 97 additions & 27 deletions doomsday/client/src/ui/clientwindow.cpp
Expand Up @@ -36,6 +36,7 @@
#include "ui/sys_input.h"
#include "ui/legacywidget.h"
#include "ui/busywidget.h"
#include "ui/mouse_qt.h"

#include "dd_main.h"
#include "con_main.h"
Expand Down Expand Up @@ -106,7 +107,14 @@ using namespace de;

static String const LEGACY_WIDGET_NAME = "legacy";

DENG2_PIMPL(ClientWindow)
DENG2_PIMPL(ClientWindow),
DENG2_OBSERVES(KeyEventSource, KeyEvent),
DENG2_OBSERVES(MouseEventSource, MouseStateChange),
#ifndef WIN32
DENG2_OBSERVES(MouseEventSource, MouseAxisEvent),
DENG2_OBSERVES(MouseEventSource, MouseButtonEvent),
#endif
DENG2_OBSERVES(Canvas, FocusChange)
{
bool needMainInit;
bool needRecreateCanvas;
Expand Down Expand Up @@ -142,6 +150,23 @@ DENG2_PIMPL(ClientWindow)
.setLeftTop (busyRoot.viewLeft(), busyRoot.viewTop())
.setRightBottom(busyRoot.viewRight(), busyRoot.viewBottom());
busyRoot.add(busy);

/// @todo The decision whether to receive input notifications from the
/// canvas is really a concern for the input drivers.

// Listen to input.
self.canvas().audienceForKeyEvent += this;
self.canvas().audienceForMouseStateChange += this;

#ifndef WIN32 // On Windows, DirectInput bypasses the mouse input from Canvas.
self.canvas().audienceForMouseAxisEvent += this;
self.canvas().audienceForMouseButtonEvent += this;
#endif
}

~Instance()
{
self.canvas().audienceForFocusChange -= this;
}

void setMode(Mode const &newMode)
Expand Down Expand Up @@ -171,7 +196,7 @@ DENG2_PIMPL(ClientWindow)
self.canvas().trapMouse();
}

self.canvas().audienceForFocusChange += self;
self.canvas().audienceForFocusChange += this;

#ifdef WIN32
if(self.isFullScreen())
Expand All @@ -183,6 +208,76 @@ DENG2_PIMPL(ClientWindow)

DD_FinishInitializationAfterWindowReady();
}

void keyEvent(KeyEventSource::KeyState state, int ddKey, int nativeCode, String const &text)
{
/**
* @todo Input drivers need to support Unicode text; for now we have to
* submit as Latin1.
*/
Keyboard_Submit(state == KeyEventSource::Pressed? IKE_DOWN : IKE_UP,
ddKey, nativeCode, text.toLatin1());
}

void mouseStateChanged(MouseEventSource::State state)
{
Mouse_Trap(state == MouseEventSource::Trapped);
}

#ifndef WIN32
void mouseAxisEvent(MouseEventSource::Axis axis, Vector2i const &value)
{
switch(axis)
{
case MouseEventSource::Motion:
Mouse_Qt_SubmitMotion(IMA_POINTER, value.x, value.y);
break;

case MouseEventSource::Wheel:
Mouse_Qt_SubmitMotion(IMA_WHEEL, value.x, value.y);
break;

default:
break;
}
}

void mouseButtonEvent(MouseEventSource::Button button, MouseEventSource::ButtonState state)
{
Mouse_Qt_SubmitButton(
button == MouseEventSource::Left? IMB_LEFT :
button == MouseEventSource::Middle? IMB_MIDDLE :
button == MouseEventSource::Right? IMB_RIGHT :
button == MouseEventSource::XButton1? IMB_EXTRA1 :
button == MouseEventSource::XButton2? IMB_EXTRA2 : IMB_MAXBUTTONS,
state == MouseEventSource::Pressed);
}
#endif // !WIN32

void canvasFocusChanged(Canvas &canvas, bool hasFocus)
{
LOG_DEBUG("canvasFocusChanged focus:%b fullscreen:%b hidden:%b minimized:%b")
<< hasFocus << self.isFullScreen() << self.isHidden() << self.isMinimized();

if(!hasFocus)
{
DD_ClearEvents();
I_ResetAllDevices();
canvas.trapMouse(false);
}
else if(self.isFullScreen())
{
// Trap the mouse again in fullscreen mode.
canvas.trapMouse();
}

// Generate an event about this.
ddevent_t ev;
ev.type = E_FOCUS;
ev.focus.gained = hasFocus;
ev.focus.inWindow = 1; /// @todo Ask WindowSystem for an identifier number.
DD_PostEvent(&ev);
}
};

ClientWindow::ClientWindow(String const &id)
Expand Down Expand Up @@ -274,31 +369,6 @@ void ClientWindow::canvasGLResized(Canvas &canvas)
d->busyRoot.setViewSize(size);
}

void ClientWindow::canvasFocusChanged(Canvas &canvas, bool hasFocus)
{
LOG_DEBUG("canvasFocusChanged focus:%b fullscreen:%b hidden:%b minimized:%b")
<< hasFocus << isFullScreen() << isHidden() << isMinimized();

if(!hasFocus)
{
DD_ClearEvents();
I_ResetAllDevices();
canvas.trapMouse(false);
}
else if(isFullScreen())
{
// Trap the mouse again in fullscreen mode.
canvas.trapMouse();
}

// Generate an event about this.
ddevent_t ev;
ev.type = E_FOCUS;
ev.focus.gained = hasFocus;
ev.focus.inWindow = 1; /// @todo Ask WindowSystem for an identifier number.
DD_PostEvent(&ev);
}

bool ClientWindow::setDefaultGLFormat() // static
{
LOG_AS("DefaultGLFormat");
Expand Down
53 changes: 53 additions & 0 deletions doomsday/client/src/ui/mouse_qt.cpp
Expand Up @@ -29,9 +29,11 @@
#include "ui/mouse_qt.h"
#include <string.h>

#include <QApplication>
#include <QWidget>
#include <QPoint>
#include <QCursor>
#include <de/Canvas>

typedef struct clicker_s {
int down; // Count for down events.
Expand All @@ -42,13 +44,15 @@ typedef struct clicker_s {
static struct { int dx, dy; } mouseDelta[IMA_MAXAXES];
static clicker_t mouseClickers[IMB_MAXBUTTONS];
static bool mouseTrapped = false;
static bool cursorHidden = false;
static QPoint prevMousePos;

static int Mouse_Qt_Init(void)
{
memset(&mouseDelta, 0, sizeof(mouseDelta));
memset(&mouseClickers, 0, sizeof(mouseClickers));
mouseTrapped = false;
cursorHidden = false;
prevMousePos = QPoint();
return true;
}
Expand Down Expand Up @@ -112,10 +116,59 @@ static void Mouse_Qt_GetState(mousestate_t *state)
}
}

static void Mouse_Qt_ShowCursor(bool yes)
{
de::Canvas &canvas = WindowSystem::main().canvas();

LOG_DEBUG("%s cursor (presently visible? %b)")
<< (yes? "showing" : "hiding") << !cursorHidden;

if(!yes && !cursorHidden)
{
cursorHidden = true;
canvas.setCursor(QCursor(Qt::BlankCursor));
qApp->setOverrideCursor(QCursor(Qt::BlankCursor));
}
else if(yes && cursorHidden)
{
cursorHidden = false;
qApp->restoreOverrideCursor();
canvas.setCursor(QCursor(Qt::ArrowCursor)); // Default cursor.
}
}

static void Mouse_Qt_InitTrap()
{
de::Canvas &canvas = WindowSystem::main().canvas();

QCursor::setPos(canvas.mapToGlobal(canvas.rect().center()));
canvas.grabMouse();

Mouse_Qt_ShowCursor(false);
}

static void Mouse_Qt_DeinitTrap()
{
WindowSystem::main().canvas().releaseMouse();

Mouse_Qt_ShowCursor(true);
}

static void Mouse_Qt_Trap(boolean enabled)
{
if(mouseTrapped == enabled) return;

mouseTrapped = enabled;
prevMousePos = QPoint();

if(enabled)
{
Mouse_Qt_InitTrap();
}
else
{
Mouse_Qt_DeinitTrap();
}
}

void Mouse_Qt_SubmitButton(int button, boolean isDown)
Expand Down
5 changes: 0 additions & 5 deletions doomsday/libgui/include/de/gui/canvas.h
Expand Up @@ -126,11 +126,6 @@ class Canvas : public QGLWidget, public KeyEventSource, public MouseEventSource
*/
bool isMouseTrapped() const;

/**
* Determines if the mouse cursor is currently visible or not.
*/
bool isCursorVisible() const;

/**
* Replaces the current audiences of this canvas with another canvas's
* audiences.
Expand Down

0 comments on commit adca39d

Please sign in to comment.