Как Java отправляет KeyEvents?

Я прочитал определенное руководство по привязкам клавиш несколько раз, но кэш моего мозга кажется недостаточно большим, чтобы вместить сложные процессы.

Я отлаживал проблему привязки клавиш (оказалось, что использовал неправильное условие JComponent.WHEN_*) и наткнулся на краткий и веселый javadoc для пакета private javax.swing.KeyboardManager (к сожалению) анонимным инженером Java.

У меня такой вопрос: за исключением KeyEventDispatcher, который проверяется в самом начале, есть ли в описании что-нибудь пропущенное и/или ошибочное?

Класс KeyboardManager используется для помощи в диспетчеризации действий клавиатуры для действий стиля WHEN_IN_FOCUSED_WINDOW. Действия с другими условиями обрабатываются непосредственно в JComponent.

Вот описание симантики [так в оригинале] того, как должна работать диспетчеризация клавиатуры, по крайней мере [так в оригинале], как я это понимаю.

KeyEvents отправляются в сфокусированный компонент. Диспетчер фокуса первым приступает к обработке этого события. Если менеджер фокуса этого не хочет, то JComponent вызывает super.processKeyEvent(), что дает слушателям возможность обработать событие.

Если ни один из слушателей не «потребляет» событие, то привязки клавиш получают выстрел. Вот тут-то и начинается самое интересное. Во-первых, KeyStokes [так в оригинале], определенные с условием WHEN_FOCUSED, получают шанс. Если ни один из них не хочет события, тогда компонент проходит, хотя его [sic] родители искали действия типа WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.

Если его еще никто не забрал, то он попадает сюда. Затем мы ищем компоненты, зарегистрированные для событий WHEN_IN_FOCUSED_WINDOW, и запускаем их. Обратите внимание, что если ни один из них не найден, мы передаем событие в строки меню и позволяем им взломать его. Они обрабатываются по-разному.

Наконец, мы проверяем, смотрим ли мы на внутреннюю рамку. Если да, и никто не хотел этого события, то мы переходим к создателю InternalFrame и смотрим, хочет ли кто-нибудь это событие (и так далее, и тому подобное).


(ОБНОВЛЕНИЕ) Если вы когда-нибудь задумывались об этом смелом предупреждении в руководстве по привязкам клавиш:

Поскольку порядок поиска компонентов непредсказуем, избегайте дублирования привязок WHEN_IN_FOCUSED_WINDOW!

Это из-за этого сегмента в KeyboardManager#fireKeyboardAction:

     Object tmp = keyMap.get(ks);
     if (tmp == null) {
       // don't do anything
     } else if ( tmp instanceof JComponent) {
           ...
     } else if ( tmp instanceof Vector) { //more than one comp registered for this
         Vector v = (Vector)tmp;
             // There is no well defined order for WHEN_IN_FOCUSED_WINDOW
             // bindings, but we give precedence to those bindings just
             // added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW
             // bindings are accessed before those of the JRootPane (they
             // both have a WHEN_IN_FOCUSED_WINDOW binding for enter).
             for (int counter = v.size() - 1; counter >= 0; counter--) {
         JComponent c = (JComponent)v.elementAt(counter);
         //System.out.println("Trying collision: " + c + " vector = "+ v.size());
         if ( c.isShowing() && c.isEnabled() ) { // don't want to give these out
             fireBinding(c, ks, e, pressed);
         if (e.isConsumed())
             return true;
         }
     }

Таким образом, порядок поиска на самом деле предсказуем, но, очевидно, зависит от конкретной реализации, поэтому лучше не на него вообще полагаться. Держите его непредсказуемым.

(Javadoc и код взяты из jdk1.6.0_b105 для WinXP.)


person Geoffrey Zheng    schedule 14.10.2010    source источник
comment
Это хороший анализ обработки KeyEvent... но я не знаю, действительно ли это вопрос, на который можно ответить.   -  person BoffinBrain    schedule 08.05.2011
comment
@BoffinbraiN: я надеялся, что кто-то с несколькими десятками значков свинга скажет что-то вроде того, насколько мне известно, это правильно :)   -  person Geoffrey Zheng    schedule 09.05.2011
comment
Да, это определенно было бы предпочтительнее! Но я думаю, что для чего-то такого глубокого это действительно зависит от реализации, и вы изучили эту реализацию гораздо тщательнее, чем это когда-либо будет делать большинство прилежных программистов. ;) Конечно, лучше не ставить свой код в зависимость от этой конкретной детали.   -  person BoffinBrain    schedule 09.05.2011
comment
Вероятно, было бы лучше, если бы вы разбили это на вопрос и ответ самому себе. Затем вы можете принять свой ответ или позволить людям проголосовать за него.   -  person Brad Mace    schedule 18.06.2011
comment
+1 за «мозговой кеш». ;-)   -  person MC Emperor    schedule 29.01.2013


Ответы (1)


Нам нужно начать отладку с Component.dispatchEventImpl.
Простое чтение исходных комментариев к методу должно дать вам идеальное представление о том, как происходят события в Swing (вы также можете начать на один уровень выше с EventQueue.pumpEventsForHeirarchy).

Для ясности приведу выдержку из кода:

  1. Установить метку времени и модификаторы текущего события.; Предварительные диспетчеры. Сделайте все необходимое перенацеливание/изменение порядка здесь, прежде чем мы уведомим AWTEventListeners.
  2. Разрешите Toolkit передать это событие в AWTEventListeners.
  3. Если никто не воспользовался ключевым событием, разрешите KeyboardFocusManager обработать его.
  4. Разрешить методам ввода обрабатывать событие
  5. Предварительно обработайте любые специальные события перед доставкой
  6. Доставить событие для обычной обработки
  7. Специальная обработка для 4061116 : Перехват браузера для закрытия модальных диалогов. :)
  8. Разрешить узлу обработать событие. За исключением KeyEvents, они будут обрабатываться пиром после всех KeyEventPostProcessors (см. DefaultKeyboardFocusManager.dispatchKeyEvent())

Теперь вы можете сопоставить приведенный выше поток с вашим описанием, чтобы определить, правильно оно или нет. Но дело в том, что вы действительно не должны зависеть от javadocs частных классов, причина в том, что разработчики обычно не заботятся об обновлении комментариев частных классов при изменении кода, поэтому документы могут устареть.

person Suraj Chandran    schedule 18.06.2011