void wxMultiColumnListCtrl::OnKey(wxKeyEvent& event)
{
    if (event.GetEventType() == wxEVT_KEY_UP)
    {
        if (event.GetKeyCode() == GetModifierKey())
        {
            // The window will close, don't select the item under mouse pointer
            m_ptMouse.x = m_ptMouse.y = -2;
            SendCloseEvent();
        }
        event.Skip();
        return;
    }

    if (event.GetKeyCode() == WXK_ESCAPE || event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER)
    {
        // The window will close, don't select the item under mouse pointer
        m_ptMouse.x = m_ptMouse.y = -2;

        if (event.GetKeyCode() == WXK_ESCAPE)
            m_items.SetSelection(-1);

        SendCloseEvent();
    }
    else if (event.GetKeyCode() == WXK_TAB || event.GetKeyCode() == GetExtraNavigationKey())
    {
        if (event.ShiftDown())
        {
            m_items.SetSelection(m_items.GetSelection() - 1);
            if (m_items.GetSelection() < 0)
                m_items.SetSelection(m_items.GetItemCount() - 1);

            AdvanceToNextSelectableItem(-1);
        }
        else
        {
            m_items.SetSelection(m_items.GetSelection() + 1);
            if (m_items.GetSelection() >= m_items.GetItemCount())
                m_items.SetSelection(0);

            AdvanceToNextSelectableItem(1);
        }

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_NUMPAD_DOWN)
    {
        m_items.SetSelection(m_items.GetSelection() + 1);
        if (m_items.GetSelection() >= m_items.GetItemCount())
            m_items.SetSelection(0);

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_NUMPAD_UP)
    {
        m_items.SetSelection(m_items.GetSelection() - 1);
        if (m_items.GetSelection() < 0)
            m_items.SetSelection(m_items.GetItemCount() - 1);

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_HOME || event.GetKeyCode() == WXK_NUMPAD_HOME)
    {
        m_items.SetSelection(0);

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_END || event.GetKeyCode() == WXK_NUMPAD_END)
    {
        m_items.SetSelection(m_items.GetItemCount() - 1);

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_NUMPAD_LEFT)
    {
        wxSwitcherItem& item = m_items.GetItem(m_items.GetSelection());

        int row = item.GetRowPos();
        int newCol = item.GetColPos() - 1;
        if (newCol < 0)
            newCol = (m_items.GetColumnCount() - 1);

        // Find the first item from the end whose row matches and whose column is equal or lower
        int i;
        for (i = m_items.GetItemCount()-1; i >= 0; i--)
        {
            wxSwitcherItem& item2 = m_items.GetItem(i);
            if (item2.GetColPos() == newCol && item2.GetRowPos() <= row)
            {
                m_items.SetSelection(i);
                break;
            }
        }

        AdvanceToNextSelectableItem(-1);

        GenerateSelectionEvent();

        Refresh();
    }
    else if (event.GetKeyCode() == WXK_RIGHT || event.GetKeyCode() == WXK_NUMPAD_RIGHT)
    {
        wxSwitcherItem& item = m_items.GetItem(m_items.GetSelection());

        int row = item.GetRowPos();
        int newCol = item.GetColPos() + 1;
        if (newCol >= m_items.GetColumnCount())
            newCol = 0;

        // Find the first item from the end whose row matches and whose column is equal or lower
        int i;
        for (i = m_items.GetItemCount()-1; i >= 0; i--)
        {
            wxSwitcherItem& item2 = m_items.GetItem(i);
            if (item2.GetColPos() == newCol && item2.GetRowPos() <= row)
            {
                m_items.SetSelection(i);
                break;
            }
        }

        AdvanceToNextSelectableItem(1);

        GenerateSelectionEvent();

        Refresh();
    }
    else
        event.Skip();
}
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);
}