Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-5314

Mnemonics (accelerators) not in Latin-1 do not work under Linux X11

    XMLWordPrintable

Details

    Description

      I create a button whose label has a mnemonic, let's say "E&xit". I translate the label into russian, using tr("E&xit"). "E&xit" becomes "&Выход". Now I expect that pressing Alt+В is going to activate the button, but it doesn't.

      Debugging has made me understand that QKeySequence for the mnemonic is created using my cyrilic character's unicode. However, QKeyMapper does not map that sequence to the pressed В. The reason is in:
      qkeymapper_x11.cpp:1200 (QKeyMapperPrivate::possibleKeysXKB)

      It uses XkbLookupKeySym to get KeySym from the native (X11) key code. It receives Latin1 keysym, when we expect russian character. I guess some changes should be made here.

      For example, I've made some changes at qkeymapper_x11.cpp:1200, replaced QKeyMapperPrivate::possibleKeysXKB with two methods, which resolved the issue. I'm not quite sure about not having broken something, but at least it is a possible solution.

      QList<int> QKeyMapperPrivate::possibleKeysXKBByBaseCode (QKeyEvent *event, KeySym baseKeySym, uint consumedModifiers)
      {
      #ifndef QT_NO_XKB
          const int xkeycode = event->nativeScanCode();
          const uint xmodifiers = event->nativeModifiers();
      
          QList<int> result;
      
          // translate sym -> code
          Qt::KeyboardModifiers baseModifiers = 0;
          int baseCode = -1;
          QByteArray chars;
          int count = 0;
          QString text = translateKeySym(baseKeySym, xmodifiers, baseCode, baseModifiers, chars, count);
          if (baseCode == -1) {
              if (text.isEmpty())
                  return QList<int>();
              baseCode = text.at(0).unicode();
          }
      
          if (baseCode && baseCode < 0xfffe)
              baseCode = QChar(baseCode).toUpper().unicode();
          result += (baseCode | baseModifiers);
      
          int pos1Bits[MaxBits];
          int num1Bits = 0;
      
          for (int i = 0; i < MaxBits; ++i) {
              if (consumedModifiers & (1 << i))
                  pos1Bits[num1Bits++] = i;
          }
      
          const int numPerms = (1 << num1Bits);
          // translate the key again using each permutation of consumedModifiers
          for (int i = 1; i < numPerms; ++i) {
              uint val = 0;
              for (int j = 0; j < num1Bits; ++j) {
                  if (i & (1 << j))
                      val |= (1 << pos1Bits[j]);
              }
      
              if ((xmodifiers & val) != val)
                  continue;
      
              KeySym sym;
              uint mods;
              if (!XkbLookupKeySym(X11->display, xkeycode, val, &mods, &sym))
                  continue;
      
              // translate sym -> code
              Qt::KeyboardModifiers modifiers = 0;
              int code = -1;
              chars.clear();
              count = 0;
              // mask out the modifiers needed to translate keycode
              text = translateKeySym(sym, xmodifiers & ~val, code, modifiers, chars, count);
              if (code == -1) {
                  if (text.isEmpty())
                      continue;
                  code = text.at(0).unicode();
              }
      
              if (code && code < 0xfffe)
                  code = QChar(code).toUpper().unicode();
              if (code == baseCode)
                  continue;
      
              result += (code | modifiers);
          }
      #if 0
          qDebug() << "possibleKeysXKB()" << hex << result;
      #endif
          return result;
      #else
          Q_UNUSED(event);
          return QList<int>();
      #endif // QT_NO_XKB
      }
      
      QList<int> QKeyMapperPrivate::possibleKeysXKB(QKeyEvent *event)
      {
      #ifndef QT_NO_XKB
          const int xkeycode = event->nativeScanCode();
          const uint xmodifiers = event->nativeModifiers();
      
          // first, translate key only using lock modifiers (there are no Qt equivalents for these, so we must
          // always use them when determining the baseKeySym)
          KeySym baseKeySym;
          uint consumedModifiers;
      
          QList<int> result;
      
          if (XkbLookupKeySym(X11->display, xkeycode, (xmodifiers & (LockMask | qt_num_lock_mask)),
                              &consumedModifiers, &baseKeySym))
            result += possibleKeysXKBByBaseCode (event, baseKeySym, consumedModifiers);
      
          if (event->nativeVirtualKey () != 0)
            result += possibleKeysXKBByBaseCode (event, event->nativeVirtualKey (), event->nativeModifiers ());
      
          return result.toSet ().toList ();
      #else
          Q_UNUSED(event);
          return QList<int>();
      #endif // QT_NO_XKB
      }
      

      Attachments

        Issue Links

          Activity

            People

              liaqi Liang Qi
              cerber Artur Brugeman
              Votes:
              21 Vote for this issue
              Watchers:
              21 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: