[vtkusers] GetKeySym and GetKeyCode for QVTKRenderWindowInteractor

David Gobbi david.gobbi at gmail.com
Fri Aug 29 14:24:34 EDT 2014


Hi Greg,

Originally the keysyms in VTK only worked on UNIX and Linux (i.e. only
for the vtkXRenderWindowInteractor).  But I needed them on other
operating systems, so I looked up the documentation for all the other
OS's and created the appropriate lookup tables to convert the raw
keycodes for those OS's into keysyms.  E.g. here is the one for Win32:

http://vtk.org/gitweb?p=VTK.git;a=blob;f=Rendering/OpenGL/vtkWin32RenderWindowInteractor.cxx;h=43c278ba#l277

So of course, the same approach should be possible for Qt.  If Qt
doesn't provide the keysyms directly, then make a python "dict" that
maps Qt's key codes into keysyms.

In fact, I can even give you some code that does "roughly" what you
need.  For my own apps, I convert Qt key codes into my own "cbKey"
codes.  These aren't the same as keysyms, but the concept is
identical.  Here is my C++ code (in python, this should be even
easier):

---------------------------------

bool cbQtWidget::convertQtKeyEvent(QKeyEvent *qe)
{
  // For conversion of certain keys to cbKey constants.
  static const cbKey::EnumType asciiToKey[] = {
    cbKey::Space, cbKey::Exclam, cbKey::QuoteDbl, cbKey::NumberSign,
    cbKey::Dollar, cbKey::Percent, cbKey::Ampersand, cbKey::QuoteRight,
    cbKey::ParenLeft, cbKey::ParenRight, cbKey::Asterisk, cbKey::Plus,
    cbKey::Comma, cbKey::Minus, cbKey::Period, cbKey::Slash,
    cbKey::Zero, cbKey::One, cbKey::Two, cbKey::Three,
    cbKey::Four, cbKey::Five, cbKey::Six, cbKey::Seven,
    cbKey::Eight, cbKey::Nine, cbKey::Colon, cbKey::Semicolon,
    cbKey::Less, cbKey::Equal, cbKey::Greater, cbKey::Question,
    cbKey::At, cbKey::A, cbKey::B, cbKey::C,
    cbKey::D, cbKey::E, cbKey::F, cbKey::G,
    cbKey::H, cbKey::I, cbKey::J, cbKey::K,
    cbKey::L, cbKey::M, cbKey::N, cbKey::O,
    cbKey::P, cbKey::Q, cbKey::R, cbKey::S,
    cbKey::T, cbKey::U, cbKey::V, cbKey::W,
    cbKey::X, cbKey::Y, cbKey::Z, cbKey::BracketLeft,
    cbKey::Backslash, cbKey::BracketRight, cbKey::AsciiCircum,
    cbKey::Underscore,
    cbKey::QuoteLeft, cbKey::A, cbKey::B, cbKey::C,
    cbKey::D, cbKey::E, cbKey::F, cbKey::G,
    cbKey::H, cbKey::I, cbKey::J, cbKey::K,
    cbKey::L, cbKey::M, cbKey::N, cbKey::O,
    cbKey::P, cbKey::Q, cbKey::R, cbKey::S,
    cbKey::T, cbKey::U, cbKey::V, cbKey::W,
    cbKey::X, cbKey::Y, cbKey::Z, cbKey::BraceLeft,
    cbKey::Bar, cbKey::BraceRight, cbKey::AsciiTilde,
  };

  cbEventType type;
  switch (qe->type()) {
    case QEvent::KeyPress: type = cbEventType::KeyPress; break;
    case QEvent::KeyRelease: type = cbEventType::KeyRelease; break;
    default: return false;
  }

  saveQtKeyboardModifiers(qe->modifiers());

  cbKey key;
  if (qe->key() >= ' ' && qe->key() <= '~') {
    key = asciiToKey[qe->key() - ' '];
  }
  else switch(qe->key()) {
    case Qt::Key_Alt: key = cbKey::Alt; break;
    case Qt::Key_AltGr: key = cbKey::AltGraph; break;
    case Qt::Key_CapsLock: key = cbKey::CapsLock; break;
    case Qt::Key_Control: key = cbKey::Control; break;
    case Qt::Key_Meta: key = cbKey::Meta; break;
    case Qt::Key_NumLock: key = cbKey::NumLock; break;
    case Qt::Key_Shift: key = cbKey::Shift; break;
    case Qt::Key_Enter: key = cbKey::Enter; break;
    case Qt::Key_Tab: key = cbKey::Tab; break;
    case Qt::Key_Down: key = cbKey::ArrowDown; break;
    case Qt::Key_Left: key = cbKey::ArrowLeft; break;
    case Qt::Key_Right: key = cbKey::ArrowRight; break;
    case Qt::Key_Up: key = cbKey::ArrowUp; break;
    case Qt::Key_End: key = cbKey::End; break;
    case Qt::Key_Home: key = cbKey::Home; break;
    case Qt::Key_PageDown: key = cbKey::PageDown; break;
    case Qt::Key_PageUp: key = cbKey::PageUp; break;
    case Qt::Key_Backspace: key = cbKey::Backspace; break;
    case Qt::Key_Clear: key = cbKey::Clear; break;
    case Qt::Key_Copy: key = cbKey::Copy; break;
    case Qt::Key_Cut: key = cbKey::Cut; break;
    case Qt::Key_Delete: key = cbKey::Delete; break;
    case Qt::Key_Insert: key = cbKey::Insert; break;
    case Qt::Key_Paste: key = cbKey::Paste; break;
    case Qt::Key_Cancel: key = cbKey::Cancel; break;
    case Qt::Key_Menu: key = cbKey::ContextMenu; break;
    case Qt::Key_Escape: key = cbKey::Escape; break;
    case Qt::Key_Help: key = cbKey::Help; break;
    case Qt::Key_Pause: key = cbKey::Pause; break;
    case Qt::Key_Play: key = cbKey::Play; break;
    case Qt::Key_ScrollLock: key = cbKey::ScrollLock; break;
    case Qt::Key_ZoomIn: key = cbKey::ZoomIn; break;
    case Qt::Key_ZoomOut: key = cbKey::ZoomOut; break;
    case Qt::Key_Camera: key = cbKey::Camera; break;
    case Qt::Key_Eject: key = cbKey::Eject; break;
    case Qt::Key_LogOff: key = cbKey::LogOff; break;
    case Qt::Key_PowerOff: key = cbKey::PowerOff; break;
    case Qt::Key_Print: key = cbKey::PrintScreen; break;
    case Qt::Key_Hibernate: key = cbKey::Hibernate; break;
    case Qt::Key_Standby: key = cbKey::Standby; break;
    case Qt::Key_WakeUp: key = cbKey::WakeUp; break;
    case Qt::Key_F1: key = cbKey::F1; break;
    case Qt::Key_F2: key = cbKey::F2; break;
    case Qt::Key_F3: key = cbKey::F3; break;
    case Qt::Key_F4: key = cbKey::F4; break;
    case Qt::Key_F5: key = cbKey::F5; break;
    case Qt::Key_F6: key = cbKey::F6; break;
    case Qt::Key_F7: key = cbKey::F7; break;
    case Qt::Key_F8: key = cbKey::F8; break;
    case Qt::Key_F9: key = cbKey::F9; break;
    case Qt::Key_F10: key = cbKey::F10; break;
    case Qt::Key_F11: key = cbKey::F11; break;
    case Qt::Key_F12: key = cbKey::F12; break;
    default: key = cbKey::Any; break;
  }

  QByteArray text = qe->text().toUtf8();

  cbKeyEvent e(
    type,
    cbEventXY(m_XY[0], m_XY[1]),
    cbGlobalXY(m_GlobalXY[0], m_GlobalXY[1]),
    key, text.data(),
    m_Modifiers);

  m_ViewFrame->ProcessEvent(&e);
  return e.GetProcessed();
}

 - David







On Fri, Aug 29, 2014 at 11:59 AM, Greg Schussman
<greg.schussman at gmail.com> wrote:
> Hi, David.
>
> Thanks for the speedy reply.
>
> On looking closer, it appears to me that Qt doesn't exactly provide keysym
> strings.  there is a .text() function, but that's already being used for
> key. Using it for keysym as well, would work for the 'a' to 'z' keys, but
> not for keys such as 'Escape'.
>
> Now, I see a qt_key_to_key_sym(Qt::Key) function defined in
> GUISupport/Qt/QVTKInteractorAdapter.cxx.  This appears to do exactly what we
> want (converting a Qt key to a vtk keysym), but I'm not clear on how to call
> it from python.
>
> If you can provide a hint to get me unstuck here, I'd be happy to provide
> that patch.
>
> Thanks again.
>
> Greg
>
>
>
> On Thu, Aug 28, 2014 at 3:14 PM, David Gobbi <david.gobbi at gmail.com> wrote:
>>
>> Hi Greg,
>>
>> I looked through QVTKRenderWindowInteractor.py and discovered
>> this in its keyPressEvent() method:
>>
>>   self._Iren.SetEventInformationFlipY(self.__saveX, self.__saveY,
>>         ctrl, shift, key, 0, None)
>>
>> Compare this with the arguments that the method expects
>> (in vtkRenderWindowInteractor.h):
>>
>>   void SetEventInformationFlipY(int x, int y, int ctrl, int shift,
>>         char keycode, int repeatcount, const char* keysym)
>>
>> As you can see, the author of this class was a bit lazy and passed
>> None as the keysym, instead of getting the keysym from Qt and
>> then passing it through to VTK.  But to be fair, this code was written
>> twelve years ago and maybe keysyms weren't the highest priority.
>>
>> If you can patch QVTKRenderWindowInteractor.py so that it passes
>> the keysym strings from Qt to "self._Iren", then I can add your patch
>> to the VTK master.
>>
>>  - David
>>
>>
>> On Thu, Aug 28, 2014 at 3:49 PM, Greg Schussman
>> <greg.schussman at gmail.com> wrote:
>> > Oops.
>> >
>> > I forgot to mention that I'm using python-2.6, vtk-5.10.1, and qt-4.6.1.
>> >
>> > Greg
>> >
>> >
>> >
>> > On Thu, Aug 28, 2014 at 2:14 PM, Greg Schussman
>> > <greg.schussman at gmail.com>
>> > wrote:
>> >>
>> >> Hi.
>> >>
>> >> I've got a working python vtk demo that uses a
>> >> vtkRenderWindowInteractor,
>> >> with the style set to vtkInteractorStyleTrackballCamera.  I run into a
>> >> problem when I try to embed this in Qt.
>> >>
>> >> I use interactor.AddObserver('KeyPressEvent', key_handler) to see key
>> >> presses and act on them.
>> >>
>> >> In my key_handler function, I query the interactor (passed in as an
>> >> argument to key_handler) about which key was pressed.
>> >>
>> >> In my working example:
>> >>
>> >> when I press 'b',
>> >> interactor.GetKeyCode() gives 'b', and
>> >> interactor.GetKeySym() give 'b'.
>> >>
>> >> when I press esc,
>> >> interactor.GetKeyCode() gives an unprintable character, and
>> >> interactor.GetKeySym() gives 'Escape'.
>> >>
>> >> In my non-working Qt example, I use QVTKRenderWindowInteractor(frame)
>> >> instead (copied from the VTK/Examples/Python/Widgets/EmbedPyQt
>> >> example).
>> >>
>> >> now, when I press 'b',
>> >> interactor.GetKeyCode() gives 'b', and
>> >> interactor.GetKeySym() gives None.
>> >>
>> >> when I press esc,
>> >> interactor.GetKeyCode() gives an unprintable character, and
>> >> interactor.GetKeySym() gives None.
>> >>
>> >> So, originally, I used GetKeySym(), but when switching to the
>> >> QVTKRenderWindowInteractor, that stopped working (always returning
>> >> None).
>> >> I'm concerned about possible inconsistencies from one linux machine to
>> >> another when using GetKeyCode, so I'm reluctant to use it.
>> >>
>> >> What should I do here?  Is there any reason why the
>> >> QTVTKRenderWindowInteractor would be giving None for the KeySym?
>> >>
>> >> For what it's worth, my demo code runs both with regular vtk and
>> >> embedded
>> >> in pyqt, and the mouse interaction is fine, and the '3' option does
>> >> toggle
>> >> stereo in both cases.  But for some reason my observer can see the key
>> >> with
>> >> GetKeySym in regular vtk mode, but not in embedded pyqt mode.
>> >>
>> >> Thanks in advance for any help or suggestions.
>> >>
>> >> Greg
>
>


More information about the vtkusers mailing list