1414import java .util .HashSet ;
1515
1616/**
17- * A class to process {@link KeyEvent}s dispatched to a {@link FlutterView}.
17+ * A class to process {@link KeyEvent}s dispatched to a {@link FlutterView}, either from a hardware
18+ * keyboard or an IME event.
1819 *
19- * <p>A class that sends Android key events to the currently registered {@link PrimaryResponder}s,
20- * and re-dispatches those not handled by the primary responders.
20+ * <p>A class that sends Android {@link KeyEvent} to the currently registered {@link
21+ * PrimaryResponder}s, and re-dispatches those not handled by the primary responders.
2122 *
2223 * <p>Flutter uses asynchronous event handling to avoid blocking the UI thread, but Android requires
2324 * that events are handled synchronously. So, when a key event is received by Flutter, it tells
2627 * framework, and if the framework responds that it has not handled the event, then this class
2728 * synthesizes a new event to send to Android, without handling it this time.
2829 *
29- * <p>A new {@link KeyEvent} sent to a {@link KeyboardManager} may be processed by 3 different types
30- * of "responder"s:
30+ * <p>A new {@link KeyEvent} sent to a {@link KeyboardManager} can be propagated to 3 different
31+ * types of "responder"s:
3132 *
3233 * <ul>
33- * <li>{@link PrimaryResponder}s: the {@link KeyboardManager} calls the {@link
34- * PrimaryResponder#handleEvent(KeyEvent, OnKeyEventHandledCallback)} method on the currently
35- * registered {@link PrimaryResponder}s. When each {@link PrimaryResponder} has decided wether
36- * to handle the key event, it must call the supplied {@link OnKeyEventHandledCallback}
34+ * <li>{@link PrimaryResponder}s: An immutable list of key responders in a {@link KeyboardManager}
35+ * that each implements the {@link PrimaryResponder} interface. a {@link PrimaryResponder} is
36+ * capable of handling {@link KeyEvent}s asynchronously.
37+ * <p>When a new {@link KeyEvent} is received, {@link KeyboardManager} calls the {@link
38+ * PrimaryResponder#handleEvent(KeyEvent, OnKeyEventHandledCallback)} method on its {@link
39+ * PrimaryResponder}s. Each {@link PrimaryResponder} must call the supplied {@link
40+ * OnKeyEventHandledCallback} exactly once, when it has decided wether to handle the key event
3741 * callback. More than one {@link PrimaryResponder} is allowed to reply true and handle the
3842 * same {@link KeyEvent}.
43+ * <p>Typically a {@link KeyboardManager} uses a {@link KeyChannelResponder} as its only
44+ * {@link PrimaryResponder}.
3945 * <li>{@link TextInputPlugin}: if every {@link PrimaryResponder} has replied false to a {@link
40- * KeyEvent}, the {@link KeyEvent} will be sent to the currently focused editable text field
41- * in {@link TextInputPlugin}, if any.
46+ * KeyEvent}, or if the {@link KeyboardManager} has zero {@link PrimaryResponder}s, the {@link
47+ * KeyEvent} will be sent to the currently focused editable text field in {@link
48+ * TextInputPlugin}, if any.
4249 * <li><b>"Redispatch"</b>: if there's no currently focused text field in {@link TextInputPlugin},
4350 * or the text field does not handle the {@link KeyEvent} either, the {@link KeyEvent} will be
4451 * sent back to the top of the activity's view hierachy, allowing the {@link KeyEvent} to be
@@ -56,6 +63,27 @@ public class KeyboardManager {
5663 this .primaryResponders = primaryResponders ;
5764 }
5865
66+ /**
67+ * Constructor for {@link KeyboardManager} that uses a {@link KeyChannelResponder} as its only
68+ * {@link PrimaryResponder}.
69+ *
70+ * <p>The view is used as the destination to send the synthesized key to. This means that the the
71+ * next thing in the focus chain will get the event when the {@link KeyChannelResponder} returns
72+ * false from onKeyDown/onKeyUp.
73+ *
74+ * <p>It is possible that that in the middle of the async round trip, the focus chain could
75+ * change, and instead of the native widget that was "next" when the event was fired getting the
76+ * event, it may be the next widget when the event is synthesized that gets it. In practice, this
77+ * shouldn't be a huge problem, as this is an unlikely occurrence to happen without user input,
78+ * and it may actually be desired behavior, but it is possible.
79+ *
80+ * @param view takes the activity to use for re-dispatching of events that were not handled by the
81+ * framework.
82+ * @param textInputPlugin a plugin, which, if set, is given key events before the framework is,
83+ * and if it has a valid input connection and is accepting text, then it will handle the event
84+ * and the framework will not receive it.
85+ * @param keyEventChannel the event channel to listen to for new key events.
86+ */
5987 public KeyboardManager (
6088 View view , @ NonNull TextInputPlugin textInputPlugin , KeyEventChannel keyEventChannel ) {
6189 this (
@@ -67,12 +95,14 @@ public KeyboardManager(
6795 /**
6896 * The interface for responding to a {@link KeyEvent} asynchronously.
6997 *
70- * <p>Implementers of this interface should be added to a {@link KeyboardManager} using the {@link
71- * KeyboardManager#addPrimaryResponder(PrimaryResponder)}, in order to receive key events.
98+ * <p>Implementers of this interface should be owned by a {@link KeyboardManager}, in order to
99+ * receive key events.
72100 *
73101 * <p>After receiving a {@link KeyEvent}, the {@link PrimaryResponder} must call the supplied
74- * {@link OnKeyEventHandledCallback} to inform the {@link KeyboardManager} whether it is capable
75- * of handling the {@link KeyEvent}.
102+ * {@link OnKeyEventHandledCallback} exactly once, to inform the {@link KeyboardManager} whether
103+ * it wishes to handle the {@link KeyEvent}. The {@link KeyEvent} will not be propagated to the
104+ * {@link TextInputPlugin} or be redispatched to the view hierachy if the key responder answered
105+ * yes.
76106 *
77107 * <p>If a {@link PrimaryResponder} fails to call the {@link OnKeyEventHandledCallback} callback,
78108 * the {@link KeyEvent} will never be sent to the {@link TextInputPlugin}, and the {@link
@@ -88,7 +118,7 @@ interface OnKeyEventHandledCallback {
88118 *
89119 * @param keyEvent the new {@link KeyEvent} this {@link PrimaryResponder} may be interested in.
90120 * @param onKeyEventHandledCallback the method to call when this {@link PrimaryResponder} has
91- * decided whether to handle {@link keyEvent}.
121+ * decided whether to handle the {@link keyEvent}.
92122 */
93123 void handleEvent (
94124 @ NonNull KeyEvent keyEvent , @ NonNull OnKeyEventHandledCallback onKeyEventHandledCallback );
0 commit comments