1
0
Fork 0

GraphicsWindowQt5: improved keyboard + modifiers

This fixes many kinds of input weirdness, caused by ‘stuck’ modifiers
being set internally, and causing input bindings to be excluded.
This commit is contained in:
James Turner 2017-06-10 15:49:32 +01:00
parent b2cc191bc6
commit 9031182583
2 changed files with 91 additions and 66 deletions

View file

@ -42,7 +42,7 @@ public:
QtKeyboardMap()
{
mKeyMap[Qt::Key_Escape ] = osgGA::GUIEventAdapter::KEY_Escape;
mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete;
mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete;
mKeyMap[Qt::Key_Home ] = osgGA::GUIEventAdapter::KEY_Home;
mKeyMap[Qt::Key_Enter ] = osgGA::GUIEventAdapter::KEY_KP_Enter;
mKeyMap[Qt::Key_End ] = osgGA::GUIEventAdapter::KEY_End;
@ -57,10 +57,22 @@ public:
mKeyMap[Qt::Key_Tab ] = osgGA::GUIEventAdapter::KEY_Tab;
mKeyMap[Qt::Key_Space ] = osgGA::GUIEventAdapter::KEY_Space;
mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete;
mKeyMap[Qt::Key_Alt ] = osgGA::GUIEventAdapter::KEY_Alt_L;
mKeyMap[Qt::Key_Shift ] = osgGA::GUIEventAdapter::KEY_Shift_L;
mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Control_L;
mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Meta_L;
mKeyMap[Qt::Key_Alt ] = osgGA::GUIEventAdapter::KEY_Alt_L;
mKeyMap[Qt::Key_Shift ] = osgGA::GUIEventAdapter::KEY_Shift_L;
#if defined(Q_OS_MACOS)
// undo the Qt-mac remapping
mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Control_L;
mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Meta_L;
#else
mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Control_L;
mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Meta_L;
#endif
mKeyMap[Qt::Key_Super_L ] = osgGA::GUIEventAdapter::KEY_Super_L;
mKeyMap[Qt::Key_Super_R ] = osgGA::GUIEventAdapter::KEY_Super_R;
mKeyMap[Qt::Key_Hyper_L ] = osgGA::GUIEventAdapter::KEY_Hyper_L;
mKeyMap[Qt::Key_Hyper_R ] = osgGA::GUIEventAdapter::KEY_Hyper_R;
mKeyMap[Qt::Key_F1 ] = osgGA::GUIEventAdapter::KEY_F1;
mKeyMap[Qt::Key_F2 ] = osgGA::GUIEventAdapter::KEY_F2;
@ -83,22 +95,7 @@ public:
mKeyMap[Qt::Key_F19 ] = osgGA::GUIEventAdapter::KEY_F19;
mKeyMap[Qt::Key_F20 ] = osgGA::GUIEventAdapter::KEY_F20;
mKeyMap[Qt::Key_hyphen ] = '-';
mKeyMap[Qt::Key_Equal ] = '=';
mKeyMap[Qt::Key_division ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
mKeyMap[Qt::Key_multiply ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
mKeyMap[Qt::Key_Minus ] = '-';
mKeyMap[Qt::Key_Plus ] = '+';
//mKeyMap[Qt::Key_H ] = osgGA::GUIEventAdapter::KEY_KP_Home;
//mKeyMap[Qt::Key_ ] = osgGA::GUIEventAdapter::KEY_KP_Up;
//mKeyMap[92 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
//mKeyMap[86 ] = osgGA::GUIEventAdapter::KEY_KP_Left;
//mKeyMap[87 ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
//mKeyMap[88 ] = osgGA::GUIEventAdapter::KEY_KP_Right;
//mKeyMap[83 ] = osgGA::GUIEventAdapter::KEY_KP_End;
//mKeyMap[84 ] = osgGA::GUIEventAdapter::KEY_KP_Down;
//mKeyMap[85 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
mKeyMap[Qt::Key_Insert ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
//mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
}
@ -109,16 +106,32 @@ public:
int remapKey(QKeyEvent* event)
{
const QChar unicodePoint = event->text().isEmpty() ? QChar() : event->text().at(0);
KeyMap::iterator itr = mKeyMap.find(event->key());
if (itr == mKeyMap.end())
{
return int(*(event->text().toLatin1().data()));
if (itr == mKeyMap.end()) {
if (unicodePoint.isNull()) {
// this happens for Ctrl modifiers on A-Z (at least). Keyboard.xml relies on the
// old ASCII mappings of these values, so we need to synthesise those here
// since Qt won't do it.
const auto k = event->key();
if ((k >= Qt::Key_A) && (k <= Qt::Key_Z)) {
return 1 + (k - Qt::Key_A); // offset into the ASCII control code range
} else {
qWarning() << Q_FUNC_INFO << "misssing mapping for key";
}
}
#if 0
qDebug() << "key" << event->key() << ", mods" << event->modifiers() << "Unicode:" << unicodePoint << ", ASCII:"
<< unicodePoint.toLatin1() << "(" << (int)unicodePoint.toLatin1() << "), raw text:" << event->text();
#endif
return int(unicodePoint.toLatin1());
}
else
return itr->second;
return itr->second;
}
private:
private:
typedef std::map<unsigned int, int> KeyMap;
KeyMap mKeyMap;
};
@ -143,12 +156,12 @@ void GLWindow::onScreenChanged()
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
_devicePixelRatio = screen()->devicePixelRatio();
#endif
if (_isPrimaryWindow) {
// allow PUI and Canvas to be scaled
fgSetDouble("/sim/rendering/gui-pixel-ratio", _devicePixelRatio);
}
syncGeometryWithOSG();
}
@ -156,10 +169,10 @@ void GLWindow::syncGeometryWithOSG()
{
const int w = width();
const int h = height();
int scaled_width = static_cast<int>(w *_devicePixelRatio);
int scaled_height = static_cast<int>(h*_devicePixelRatio);
if (_gw) {
_gw->resized( x(), y(), scaled_width, scaled_height);
_gw->getEventQueue()->windowResize( x(), y(), scaled_width, scaled_height );
@ -189,7 +202,7 @@ bool GLWindow::event( QEvent* event )
if (event->type() == QEvent::WindowStateChange) {
// keep full-screen state in sync
const bool isFullscreen = (windowState() == Qt::WindowFullScreen);
if (_isPrimaryWindow) {
fgSetBool("/sim/startup/fullscreen", isFullscreen);
}
@ -214,7 +227,7 @@ void GLWindow::processUpdateEvent()
if (_gw->_viewer.lock(v)) {
v->frame();
}
// see discussion of QWindow::requestUpdate to see
// why this is good behaviour
if (_gw->_continousUpdate) {
@ -223,14 +236,29 @@ void GLWindow::processUpdateEvent()
}
void GLWindow::setKeyboardModifiers( QInputEvent* event )
static void setOSGModifier(int& modifiers, unsigned int bits, bool set)
{
int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
unsigned int mask = 0;
if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
_gw->getEventQueue()->getCurrentEventState()->setModKeyMask( mask );
if (set) {
modifiers |= bits;
} else {
modifiers &= ~bits;
}
}
void GLWindow::setKeyboardModifiers(const Qt::KeyboardModifiers qtMods)
{
auto es = _gw->getEventQueue()->getCurrentEventState();
auto modifiers = es->getModKeyMask();
#if defined(Q_OS_MACOS)
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_CTRL, qtMods & Qt::MetaModifier);
#else
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_CTRL, qtMods & Qt::ControlModifier);
#endif
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_ALT, qtMods & Qt::AltModifier);
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_SHIFT, qtMods & Qt::ShiftModifier);
_gw->getEventQueue()->getCurrentEventState()->setModKeyMask(modifiers);
}
void GLWindow::resizeEvent( QResizeEvent* event )
@ -247,7 +275,7 @@ void GLWindow::moveEvent( QMoveEvent* event )
void GLWindow::keyPressEvent( QKeyEvent* event )
{
setKeyboardModifiers( event );
setKeyboardModifiers( event->modifiers() );
int value = s_QtKeyboardMap.remapKey( event );
_gw->getEventQueue()->keyPress( value );
@ -259,13 +287,10 @@ void GLWindow::keyPressEvent( QKeyEvent* event )
void GLWindow::keyReleaseEvent( QKeyEvent* event )
{
if( event->isAutoRepeat() )
{
if (event->isAutoRepeat()) {
event->ignore();
}
else
{
setKeyboardModifiers( event );
} else {
setKeyboardModifiers(event->modifiers() );
int value = s_QtKeyboardMap.remapKey( event );
_gw->getEventQueue()->keyRelease( value );
}
@ -287,7 +312,7 @@ void GLWindow::mousePressEvent( QMouseEvent* event )
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
@ -302,7 +327,7 @@ void GLWindow::mouseReleaseEvent( QMouseEvent* event )
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseButtonRelease( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
@ -317,19 +342,19 @@ void GLWindow::mouseDoubleClickEvent( QMouseEvent* event )
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers( event );
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseDoubleButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
void GLWindow::mouseMoveEvent( QMouseEvent* event )
{
setKeyboardModifiers( event );
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseMotion( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio );
}
void GLWindow::wheelEvent( QWheelEvent* event )
{
setKeyboardModifiers( event );
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseScroll(
event->orientation() == Qt::Vertical ?
(event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
@ -354,17 +379,17 @@ bool GraphicsWindowQt5::init( Qt::WindowFlags f )
WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
assert(!_window);
_ownsWidget = true;
// WindowFlags
Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint;
if ( _traits->windowDecoration ) {
flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
flags |= Qt::WindowFullscreenButtonHint;
// TODO - check if this is desirable or not on Windows+Linux
//flags |= Qt::MaximizeUsingFullscreenGeometryHint;
}
// create window
_window.reset(new GLWindow);
_window->setFlags(flags);
@ -372,7 +397,7 @@ bool GraphicsWindowQt5::init( Qt::WindowFlags f )
_window->setFormat(traits2qSurfaceFormat(_traits.get()));
_window->create();
_window->setTitle( _traits->windowName.c_str() );
// to get OS-dependant default positioning of the window (which is desirable),
// we must take care to only set the position if explicitly requested.
// hence we set X & Y to these marker values by default.
@ -380,7 +405,7 @@ bool GraphicsWindowQt5::init( Qt::WindowFlags f )
if ((_traits->x != std::numeric_limits<int>::max()) && (_traits->y != std::numeric_limits<int>::max())) {
_window->setPosition( _traits->x, _traits->y );
}
QSize sz(_traits->width, _traits->height);
if ( !_traits->supportsResize ) {
_window->setMinimumSize( sz );
@ -388,7 +413,7 @@ bool GraphicsWindowQt5::init( Qt::WindowFlags f )
} else {
_window->resize( sz );
}
if (windowData->createFullscreen) {
// this doesn't seem to actually work, so we
// check the flag again in realizeImplementation()
@ -399,7 +424,7 @@ bool GraphicsWindowQt5::init( Qt::WindowFlags f )
if (_window->_isPrimaryWindow) {
fgSetDouble("/sim/rendering/gui-pixel-ratio", _window->_devicePixelRatio);
}
_window->setGraphicsWindow( this );
useCursor( _traits->useCursor );
@ -619,12 +644,12 @@ bool GraphicsWindowQt5::realizeImplementation()
} else {
_window->show();
}
#if (OPENSCENEGRAPH_MAJOR_VERSION == 3) && (OPENSCENEGRAPH_MINOR_VERSION >= 4)
// make sure the event queue has the correct window rectangle size and input range
getEventQueue()->syncWindowRectangleWithGraphicsContext();
#endif
_realized = true;
return true;
}
@ -640,7 +665,7 @@ void GraphicsWindowQt5::closeImplementation()
_window->close();
_window.reset();
}
_context.reset();
_realized = false;
}
@ -714,7 +739,7 @@ bool GraphicsWindowQt5::checkEvents()
_sendResizeOnEventCheck = false;
_window->syncGeometryWithOSG();
}
// todo - only if not running inside QApplication::exec; can we check this?
QCoreApplication::processEvents(QEventLoop::AllEvents);
@ -764,8 +789,6 @@ public:
Qt5WindowingSystem()
{
OSG_INFO << "QtWindowingSystemInterface()" << std::endl;
}
~Qt5WindowingSystem()

View file

@ -62,7 +62,7 @@ public:
inline bool getForwardKeyEvents() const { return _forwardKeyEvents; }
virtual void setForwardKeyEvents( bool f ) { _forwardKeyEvents = f; }
void setKeyboardModifiers( QInputEvent* event );
void setKeyboardModifiers(const Qt::KeyboardModifiers qtMods);
virtual void keyPressEvent( QKeyEvent* event );
virtual void keyReleaseEvent( QKeyEvent* event );
@ -87,6 +87,8 @@ private slots:
protected:
void syncGeometryWithOSG();
void updateEventQueueModifiers(QKeyEvent* event);
friend class GraphicsWindowQt5;
GraphicsWindowQt5* _gw = nullptr; // back-pointer