Class KeyboardFocusManager
- All Implemented Interfaces:
Serializable
- Direct Known Subclasses:
FocusManager
KeyboardFocusManager — who has focus, and
moving it on (D_focus_managers). Concrete, where the JDK's is abstract, so the statics
have something to hand out. The auto-advance idiom, from inside a
Document that has no back-reference to its own component:
Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (owner instanceof JTextComponent text && text.getDocument() == this) {
owner.transferFocus(); // → focusNextComponent(owner)
}
Real: the focus-owner and window queries, and single-step traversal.
WARNing (R_match_swing_errors sub-bucket (b)): key-event dispatch, focus cycle roots,
FocusTraversalPolicy as a pluggable object, the protected
setGlobal* mutators, and the vetoable-listener registry — the browser
owns key routing and Tab order.
Stateless facade; the state is per UI. Every method resolves
UI.getCurrent() at call time and reads
FocusTracker's per-UI pointer, so this process-wide
instance holds nothing UI-bound — which is what makes
static final FocusManager FM = FocusManager.getCurrentManager();
safe to write. Per-UI instances would turn that idiom into a cross-tab bug
the static-field sweep cannot catch, since a focus manager is not a
Component.
Bound properties are per UI, and only the four the getters can back.
The listener registry lives in the current UI's data rather than on this
process-wide facade — a PropertyChangeSupport field here would pool every
session's listeners on one list and deliver every tab's focus change to all of
them, the same cross-tab hazard the paragraph above rules out for state:
FocusManager.getCurrentManager().addPropertyChangeListener("focusOwner",
e -> log.info("focus: {} -> {}", e.getOldValue(), e.getNewValue()));
focusOwner, permanentFocusOwner, focusedWindow and
activeWindow fire off FocusTracker's pointer move —
the place the real transition happens, so what the event announces is what
getFocusOwner() answers a line later. defaultFocusTraversalPolicy
fires from its own setter. The remaining three JDK properties stay silent
because their getters would deny the transition, the reasoning
D_reverse_fanout_rows applied to JPopupMenu.setVisible:
currentFocusCycleRoot and the traversal-key sets have no state behind
them (tier 3 below), and setCurrentKeyboardFocusManager does not swap the
manager, so a managingFocus event would report a handover that did not
happen.
Vetoable properties are not honoured — addVetoableChangeListener(VetoableChangeListener)
still WARNs and registers nothing. The JDK vetoes before the change; here
the browser has already moved focus by the time the server hears about it, so a
veto could only be implemented as a focus-restoring effect, which is a different
thing from the notification R_decline_effect_only owes.
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intstatic final intstatic final intstatic final int -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidRegisters for every bound property of this manager, in the current UI:voidaddPropertyChangeListener(String propertyName, PropertyChangeListener listener) voidvoidaddVetoableChangeListener(String propertyName, VetoableChangeListener listener) voidDrops focus entirely: clears the server-side pointer and blurs the browser'sactiveElement, so the two stay in agreement.voidSame asclearFocusOwner().protected voiddequeueKeyEvents(long after, Component untilFocused) protected voiddiscardKeyEvents(Component component) booleandispatchEvent(AWTEvent event) booleandispatchKeyEvent(KeyEvent event) final voidvoiddownFocusCycle(Container container) protected voidenqueueKeyEvents(long after, Component untilFocused) protected voidfirePropertyChange(String propertyName, Object oldValue, Object newValue) Delivers to the current UI's listeners, or nowhere when none registered in this tab.protected voidfireVetoableChange(String propertyName, Object oldValue, Object newValue) final voidOperates on the current focus owner; no-op when nothing is focused.voidfocusNextComponent(Component component) Moves focus to the next focusable component aftercomponent, wrapping at the end; silently stays put when there is no other candidate (as the JDK does).final voidOperates on the current focus owner; no-op when nothing is focused.voidfocusPreviousComponent(Component component) Backward counterpart offocusNextComponent(Component).Same answer asgetFocusedWindow(): a browser tab has exactly one active window by construction, so the JDK's focused-vs-active distinction (which separates a focused owner-lessWindowfrom theFramethat activates with it) has nothing to distinguish here.static KeyboardFocusManagerThe shared stateless facade; nevernull.getDefaultFocusTraversalKeys(int id) Empty set, no WARN — the same honest answerComponent.getFocusTraversalKeys(int)gives: the browser owns the Tab key, so there are no server-side traversal keystrokes to report.The installed default policy, ornullwhen none was set — never a fabricated one, since there is no traversal engine whose behaviour a default would describe.TheWindowcontaining the focus owner — found by walking the emulator parent chain, so aJDialog,JWindoworJInternalFrameoverlay wins over the frame behind it.The emulator that owns browser focus in the current UI, ornullwhen focus sits outside our component tree (on<body>, or on a Vaadin component the app added outside vaadinx).protected Windowprotected Containerprotected Windowprotected Componentprotected ComponentSame answer asgetFocusOwner().getPropertyChangeListeners(String propertyName) getVetoableChangeListeners(String propertyName) booleanpostProcessKeyEvent(KeyEvent event) voidprocessKeyEvent(Component focusedComponent, KeyEvent event) final voidredispatchEvent(Component target, AWTEvent event) voidvoidremovePropertyChangeListener(String propertyName, PropertyChangeListener listener) voidvoidremoveVetoableChangeListener(String propertyName, VetoableChangeListener listener) static voidWARN and ignore.voidsetDefaultFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes) voidStores the policy; nothing dispatches on it (D_focus_managers tier 3).protected voidsetGlobalActiveWindow(Window window) voidsetGlobalCurrentFocusCycleRoot(Container container) protected voidsetGlobalFocusedWindow(Window window) protected voidsetGlobalFocusOwner(Component component) protected voidsetGlobalPermanentFocusOwner(Component component) final voidvoidupFocusCycle(Component component)
-
Field Details
-
FORWARD_TRAVERSAL_KEYS
public static final int FORWARD_TRAVERSAL_KEYS- See Also:
-
BACKWARD_TRAVERSAL_KEYS
public static final int BACKWARD_TRAVERSAL_KEYS- See Also:
-
UP_CYCLE_TRAVERSAL_KEYS
public static final int UP_CYCLE_TRAVERSAL_KEYS- See Also:
-
DOWN_CYCLE_TRAVERSAL_KEYS
public static final int DOWN_CYCLE_TRAVERSAL_KEYS- See Also:
-
-
Constructor Details
-
KeyboardFocusManager
public KeyboardFocusManager()
-
-
Method Details
-
getCurrentKeyboardFocusManager
The shared stateless facade; nevernull. -
setCurrentKeyboardFocusManager
WARN and ignore. A replacement manager's only overridable hooks are the ones this class WARNs on anyway (key dispatch, traversal policy), so honouring the swap would advertise more working behaviour than exists. Revisit if a real migrated app turns up subclassing a focus manager. -
getFocusOwner
The emulator that owns browser focus in the current UI, ornullwhen focus sits outside our component tree (on<body>, or on a Vaadin component the app added outside vaadinx).Resolved through
EHelper.emulatorFor(Component), so focus landing on the inner field of a composite peer answers with the emulator that owns the composite. -
getPermanentFocusOwner
Same answer asgetFocusOwner(). The JDK's split exists for temporary focus loss (a scrollbar drag, a native popup stealing focus and giving it back); the browser has no such concept, so every focus change we see is permanent. -
getFocusedWindow
TheWindowcontaining the focus owner — found by walking the emulator parent chain, so aJDialog,JWindoworJInternalFrameoverlay wins over the frame behind it.The walk needs no special case for the
@MainWindowframe: that frame peers on anSJPanelrather than a dialog (D_frame_strategy), but it is still aJFrameand therefore still aWindowemulator in the parent chain, so the walk finds it like any other.nullmeans nothing is focused, or the focus owner is not parented under a Window yet — the same answer the JDK gives. -
getActiveWindow
Same answer asgetFocusedWindow(): a browser tab has exactly one active window by construction, so the JDK's focused-vs-active distinction (which separates a focused owner-lessWindowfrom theFramethat activates with it) has nothing to distinguish here. -
clearFocusOwner
public void clearFocusOwner()Drops focus entirely: clears the server-side pointer and blurs the browser'sactiveElement, so the two stay in agreement. -
clearGlobalFocusOwner
public void clearGlobalFocusOwner()Same asclearFocusOwner(). The JDK's split is about which AppContext may clear whose focus owner — a distinction with no analogue in a single browser tab. -
focusNextComponent
Moves focus to the next focusable component aftercomponent, wrapping at the end; silently stays put when there is no other candidate (as the JDK does). The engine behindComponent.transferFocus().Order comes from the emulator tree, not the browser's Tab order — a depth-first pre-order walk from the top-level ancestor. The two diverge only where DOM order or an explicit
tabindexdisagrees with our child order, which R_layouts_close_enough's close-enough licence covers; a browser round trip for "next tabbable element" would agree by construction but be async and untestable browserless. -
focusPreviousComponent
Backward counterpart offocusNextComponent(Component). -
focusNextComponent
public final void focusNextComponent()Operates on the current focus owner; no-op when nothing is focused. -
focusPreviousComponent
public final void focusPreviousComponent()Operates on the current focus owner; no-op when nothing is focused. -
upFocusCycle
-
downFocusCycle
-
upFocusCycle
public final void upFocusCycle() -
downFocusCycle
public final void downFocusCycle() -
getCurrentFocusCycleRoot
-
setGlobalCurrentFocusCycleRoot
-
getGlobalCurrentFocusCycleRoot
-
getDefaultFocusTraversalPolicy
The installed default policy, ornullwhen none was set — never a fabricated one, since there is no traversal engine whose behaviour a default would describe. -
setDefaultFocusTraversalPolicy
Stores the policy; nothing dispatches on it (D_focus_managers tier 3). Safe to hold on this process-wide facade where per-UI state would not be — the JDK scopes this default per AppContext, i.e. per application, and a policy is a stateless strategy object rather than anything tab-bound.Fires
"defaultFocusTraversalPolicy"to the current UI's listeners, which is narrower than the value it announces: the field is process-wide, so another tab's listeners miss a change they can read back. Per-UI is the widest delivery a tab-scoped registry can offer, and the alternative — reaching into every session's listener list from one request thread — is the cross-tab hazard this class exists to avoid.- Throws:
IllegalArgumentException- ifpolicyisnull, as the JDK does
-
getDefaultFocusTraversalKeys
Empty set, no WARN — the same honest answerComponent.getFocusTraversalKeys(int)gives: the browser owns the Tab key, so there are no server-side traversal keystrokes to report. -
setDefaultFocusTraversalKeys
-
getGlobalFocusOwner
-
setGlobalFocusOwner
-
getGlobalPermanentFocusOwner
-
setGlobalPermanentFocusOwner
-
getGlobalFocusedWindow
-
setGlobalFocusedWindow
-
getGlobalActiveWindow
-
setGlobalActiveWindow
-
dispatchEvent
-
redispatchEvent
-
dispatchKeyEvent
-
postProcessKeyEvent
-
processKeyEvent
-
enqueueKeyEvents
-
dequeueKeyEvents
-
discardKeyEvents
-
addPropertyChangeListener
Registers for every bound property of this manager, in the current UI:FocusManager.getCurrentManager().addPropertyChangeListener("focusOwner", e -> statusBar.setText("focus: " + e.getNewValue()));Per UI, not process-wide. The JDK scopes these listeners per AppContext; a browser tab is the closest thing SB-Emulators has, so a listener registered from one tab never hears another's focus changes — the same call
FocusTrackermakes for the pointer itself. A registration made with no current UI is dropped with a WARN, since there is no tab to scope it to. -
addPropertyChangeListener
- See Also:
-
removePropertyChangeListener
-
removePropertyChangeListener
-
getPropertyChangeListeners
-
getPropertyChangeListeners
-
firePropertyChange
Delivers to the current UI's listeners, or nowhere when none registered in this tab.The
oldValue == newValueshort-circuit is the JDK's own, and is reference identity — a stricter filter than theequalsdedupePropertyChangeSupportthen applies, and the reason a hand-written(null, null)defeats both. -
addVetoableChangeListener
-
addVetoableChangeListener
-
removeVetoableChangeListener
-
removeVetoableChangeListener
-
getVetoableChangeListeners
-
getVetoableChangeListeners
-
fireVetoableChange
protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue) throws PropertyVetoException - Throws:
PropertyVetoException
-