Ejemplo n.º 1
0
/* static */ PRUint32
KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
{
    guint keyval = aGdkKeyEvent->keyval;

    // First, try to handle alphanumeric input, not listed in nsKeycodes:
    // most likely, more letters will be getting typed in than things in
    // the key list, so we will look through these first.

    // since X has different key symbols for upper and lowercase letters and
    // mozilla does not, convert gdk's to mozilla's
    if (keyval >= GDK_a && keyval <= GDK_z) {
        return keyval - GDK_a + NS_VK_A;
    }
    if (keyval >= GDK_A && keyval <= GDK_Z) {
        return keyval - GDK_A + NS_VK_A;
    }

    // numbers
    if (keyval >= GDK_0 && keyval <= GDK_9) {
        return keyval - GDK_0 + NS_VK_0;
    }

    // keypad numbers
    if (keyval >= GDK_KP_0 && keyval <= GDK_KP_9) {
        return keyval - GDK_KP_0 + NS_VK_NUMPAD0;
    }

    // If the keyval indicates it's a modifier key, we should use unshifted
    // key's modifier keyval.
    if (GetModifierForGDKKeyval(keyval)) {
        KeymapWrapper* keymapWrapper = GetInstance();
        GdkKeymapKey key;
        key.keycode = aGdkKeyEvent->hardware_keycode;
        key.group = aGdkKeyEvent->group;
        key.level = 0;
        guint unshiftedKeyval =
            gdk_keymap_lookup_key(keymapWrapper->mGdkKeymap, &key);
        // But if the unshifted keyval isn't a modifier key, we shouldn't use
        // it.  E.g., Japanese keyboard layout's Shift + Eisu-Toggle key is
        // CapsLock.  This is an actual rare case, Windows uses different
        // keycode for a physical key for different shift key state.
        if (GetModifierForGDKKeyval(unshiftedKeyval)) {
            keyval = unshiftedKeyval;
        }
    }

    // map Sun Keyboard special keysyms
    for (PRUint32 i = 0; i < ArrayLength(kSunKeyPairs); i++) {
        if (kSunKeyPairs[i].GDKKeyval == keyval) {
            return kSunKeyPairs[i].DOMKeyCode;
        }
    }

    // misc other things
    for (PRUint32 i = 0; i < ArrayLength(kKeyPairs); i++) {
        if (kKeyPairs[i].GDKKeyval == keyval) {
            return kKeyPairs[i].DOMKeyCode;
        }
    }

    // function keys
    if (keyval >= GDK_F1 && keyval <= GDK_F24) {
        return keyval - GDK_F1 + NS_VK_F1;
    }

    return 0;
}
Ejemplo n.º 2
0
/* static */ PRUint32
KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent)
{
    // If the keyval indicates it's a modifier key, we should use unshifted
    // key's modifier keyval.
    guint keyval = aGdkKeyEvent->keyval;
    if (GetModifierForGDKKeyval(keyval)) {
        // But if the keyval without modifiers isn't a modifier key, we
        // shouldn't use it.  E.g., Japanese keyboard layout's
        // Shift + Eisu-Toggle key is CapsLock.  This is an actual rare case,
        // Windows uses different keycode for a physical key for different
        // shift key state.
        guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
        if (GetModifierForGDKKeyval(keyvalWithoutModifier)) {
            keyval = keyvalWithoutModifier;
        }
        return GetDOMKeyCodeFromKeyPairs(keyval);
    }

    // If the key isn't printable, let's look at the key pairs.
    PRUint32 charCode = GetCharCodeFor(aGdkKeyEvent);
    if (!charCode) {
        // Always use unshifted keycode for the non-printable key.
        // XXX It might be better to decide DOM keycode from all keyvals of
        //     the hardware keycode.  However, I think that it's too excessive.
        guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent);
        PRUint32 DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier);
        if (!DOMKeyCode) {
            // If the unshifted keyval couldn't be mapped to a DOM keycode,
            // we should fallback to legacy logic, so, we should recompute with
            // the keyval with aGdkKeyEvent.
            DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval);
        }
        return DOMKeyCode;
    }

    // printable numpad keys should be resolved here.
    switch (keyval) {
        case GDK_KP_Multiply:  return NS_VK_MULTIPLY;
        case GDK_KP_Add:       return NS_VK_ADD;
        case GDK_KP_Separator: return NS_VK_SEPARATOR;
        case GDK_KP_Subtract:  return NS_VK_SUBTRACT;
        case GDK_KP_Decimal:   return NS_VK_DECIMAL;
        case GDK_KP_Divide:    return NS_VK_DIVIDE;
        case GDK_KP_0:         return NS_VK_NUMPAD0;
        case GDK_KP_1:         return NS_VK_NUMPAD1;
        case GDK_KP_2:         return NS_VK_NUMPAD2;
        case GDK_KP_3:         return NS_VK_NUMPAD3;
        case GDK_KP_4:         return NS_VK_NUMPAD4;
        case GDK_KP_5:         return NS_VK_NUMPAD5;
        case GDK_KP_6:         return NS_VK_NUMPAD6;
        case GDK_KP_7:         return NS_VK_NUMPAD7;
        case GDK_KP_8:         return NS_VK_NUMPAD8;
        case GDK_KP_9:         return NS_VK_NUMPAD9;
    }

    KeymapWrapper* keymapWrapper = GetInstance();

    // Ignore all modifier state except NumLock.
    guint baseState =
        (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK));

    // Basically, we should use unmodified character for deciding our keyCode.
    PRUint32 unmodifiedChar =
        keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState,
                                      aGdkKeyEvent->group);
    if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) {
        // If the unmodified character is an ASCII alphabet or an ASCII
        // numeric, it's the best hint for deciding our keyCode.
        return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar);
    }

    // If the unmodified character is not an ASCII character, that means we
    // couldn't find the hint. We should reset it.
    if (unmodifiedChar > 0x7F) {
        unmodifiedChar = 0;
    }

    // Retry with shifted keycode.
    guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT));
    PRUint32 shiftedChar =
        keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
                                      aGdkKeyEvent->group);
    if (IsBasicLatinLetterOrNumeral(shiftedChar)) {
        // A shifted character can be an ASCII alphabet on Hebrew keyboard
        // layout. And also shifted character can be an ASCII numeric on
        // AZERTY keyboad layout.  Then, it's a good hint for deciding our
        // keyCode.
        return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar);
    }

    // If the shifted unmodified character isn't an ASCII character, we should
    // discard it too.
    if (shiftedChar > 0x7F) {
        shiftedChar = 0;
    }

    // If current keyboard layout isn't ASCII alphabet inputtable layout,
    // look for ASCII alphabet inputtable keyboard layout.  If the key
    // inputs an ASCII alphabet or an ASCII numeric, we should use it
    // for deciding our keyCode.
    // Note that it's important not to use alternative keyboard layout for ASCII
    // alphabet inputabble keyboard layout because the keycode for the key with
    // alternative keyboard layout may conflict with another key on current
    // keyboard layout.
    if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) {
        gint minGroup = keymapWrapper->GetFirstLatinGroup();
        if (minGroup >= 0) {
            PRUint32 unmodCharLatin =
                keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState,
                                              minGroup);
            if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) {
                // If the unmodified character is an ASCII alphabet or
                // an ASCII numeric, we should use it for the keyCode.
                return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin);
            }
            PRUint32 shiftedCharLatin =
                keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState,
                                              minGroup);
            if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) {
                // If the shifted character is an ASCII alphabet or an ASCII
                // numeric, we should use it for the keyCode.
                return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin);
            }
        }
    }

    // If unmodified character is in ASCII range, use it.  Otherwise, use
    // shifted character.
    if (!unmodifiedChar && !shiftedChar) {
        return 0;
    }
    return WidgetUtils::ComputeKeyCodeFromChar(
                unmodifiedChar ? unmodifiedChar : shiftedChar);
}
Ejemplo n.º 3
0
void
KeymapWrapper::InitBySystemSettings()
{
    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
      ("KeymapWrapper(%p): InitBySystemSettings, mGdkKeymap=%p",
       this, mGdkKeymap));

    Display* display =
        gdk_x11_display_get_xdisplay(gdk_display_get_default());

    int min_keycode = 0;
    int max_keycode = 0;
    XDisplayKeycodes(display, &min_keycode, &max_keycode);

    int keysyms_per_keycode = 0;
    KeySym* xkeymap = XGetKeyboardMapping(display, min_keycode,
                                          max_keycode - min_keycode + 1,
                                          &keysyms_per_keycode);
    if (!xkeymap) {
        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
            ("KeymapWrapper(%p): InitBySystemSettings, "
             "Failed due to null xkeymap", this));
        return;
    }

    XModifierKeymap* xmodmap = XGetModifierMapping(display);
    if (!xmodmap) {
        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
            ("KeymapWrapper(%p): InitBySystemSettings, "
             "Failed due to null xmodmap", this));
        XFree(xkeymap);
        return;
    }
    PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
        ("KeymapWrapper(%p): InitBySystemSettings, min_keycode=%d, "
         "max_keycode=%d, keysyms_per_keycode=%d, max_keypermod=%d",
         this, min_keycode, max_keycode, keysyms_per_keycode,
         xmodmap->max_keypermod));

    // The modifiermap member of the XModifierKeymap structure contains 8 sets
    // of max_keypermod KeyCodes, one for each modifier in the order Shift,
    // Lock, Control, Mod1, Mod2, Mod3, Mod4, and Mod5.
    // Only nonzero KeyCodes have meaning in each set, and zero KeyCodes are
    // ignored.

    // Note that two or more modifiers may use one modifier flag.  E.g.,
    // on Ubuntu 10.10, Alt and Meta share the Mod1 in default settings.
    // And also Super and Hyper share the Mod4. In such cases, we need to
    // decide which modifier flag means one of DOM modifiers.

    // mod[0] is Modifier introduced by Mod1.
    Modifier mod[5];
    int32_t foundLevel[5];
    for (uint32_t i = 0; i < ArrayLength(mod); i++) {
        mod[i] = NOT_MODIFIER;
        foundLevel[i] = INT32_MAX;
    }
    const uint32_t map_size = 8 * xmodmap->max_keypermod;
    for (uint32_t i = 0; i < map_size; i++) {
        KeyCode keycode = xmodmap->modifiermap[i];
        PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
            ("KeymapWrapper(%p): InitBySystemSettings, "
             "  i=%d, keycode=0x%08X",
             this, i, keycode));
        if (!keycode || keycode < min_keycode || keycode > max_keycode) {
            continue;
        }

        ModifierKey* modifierKey = GetModifierKey(keycode);
        if (!modifierKey) {
            modifierKey = mModifierKeys.AppendElement(ModifierKey(keycode));
        }

        const KeySym* syms =
            xkeymap + (keycode - min_keycode) * keysyms_per_keycode;
        const uint32_t bit = i / xmodmap->max_keypermod;
        modifierKey->mMask |= 1 << bit;

        // We need to know the meaning of Mod1, Mod2, Mod3, Mod4 and Mod5.
        // Let's skip if current map is for others.
        if (bit < 3) {
            continue;
        }

        const int32_t modIndex = bit - 3;
        for (int32_t j = 0; j < keysyms_per_keycode; j++) {
            Modifier modifier = GetModifierForGDKKeyval(syms[j]);
            PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
                ("KeymapWrapper(%p): InitBySystemSettings, "
                 "    Mod%d, j=%d, syms[j]=%s(0x%X), modifier=%s",
                 this, modIndex + 1, j, gdk_keyval_name(syms[j]), syms[j],
                 GetModifierName(modifier)));

            switch (modifier) {
                case NOT_MODIFIER:
                    // Don't overwrite the stored information with
                    // NOT_MODIFIER.
                    break;
                case CAPS_LOCK:
                case SHIFT:
                case CTRL:
                    // Ignore the modifiers defined in GDK spec. They shouldn't
                    // be mapped to Mod1-5 because they must not work on native
                    // GTK applications.
                    break;
                default:
                    // If new modifier is found in higher level than stored
                    // value, we don't need to overwrite it.
                    if (j > foundLevel[modIndex]) {
                        break;
                    }
                    // If new modifier is more important than stored value,
                    // we should overwrite it with new modifier.
                    if (j == foundLevel[modIndex]) {
                        mod[modIndex] = std::min(modifier, mod[modIndex]);
                        break;
                    }
                    foundLevel[modIndex] = j;
                    mod[modIndex] = modifier;
                    break;
            }
        }
    }

    for (uint32_t i = 0; i < COUNT_OF_MODIFIER_INDEX; i++) {
        Modifier modifier;
        switch (i) {
            case INDEX_NUM_LOCK:
                modifier = NUM_LOCK;
                break;
            case INDEX_SCROLL_LOCK:
                modifier = SCROLL_LOCK;
                break;
            case INDEX_ALT:
                modifier = ALT;
                break;
            case INDEX_META:
                modifier = META;
                break;
            case INDEX_SUPER:
                modifier = SUPER;
                break;
            case INDEX_HYPER:
                modifier = HYPER;
                break;
            case INDEX_LEVEL3:
                modifier = LEVEL3;
                break;
            case INDEX_LEVEL5:
                modifier = LEVEL5;
                break;
            default:
                MOZ_CRASH("All indexes must be handled here");
        }
        for (uint32_t j = 0; j < ArrayLength(mod); j++) {
            if (modifier == mod[j]) {
                mModifierMasks[i] |= 1 << (j + 3);
            }
        }
    }

    XFreeModifiermap(xmodmap);
    XFree(xkeymap);
}