diff --git a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/SpinnerBehavior.java b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/SpinnerBehavior.java index fed927a8af2..bc8248203a9 100644 --- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/SpinnerBehavior.java +++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/SpinnerBehavior.java @@ -31,14 +31,12 @@ import javafx.scene.control.Spinner; import javafx.scene.control.SpinnerValueFactory; import com.sun.javafx.scene.control.inputmap.InputMap; +import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.util.Duration; import java.util.List; -import static javafx.scene.input.KeyCode.*; -import static com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping; - public class SpinnerBehavior extends BehaviorBase> { // this specifies how long the mouse has to be pressed on a button @@ -69,7 +67,20 @@ public class SpinnerBehavior extends BehaviorBase> { } }; + private final EventHandler spinnerKeyHandler = e -> { + boolean arrowsAreVertical = arrowsAreVertical(); + KeyCode increment = arrowsAreVertical ? KeyCode.UP : KeyCode.RIGHT; + KeyCode decrement = arrowsAreVertical ? KeyCode.DOWN : KeyCode.LEFT; + if (e.getCode() == increment) { + increment(1); + e.consume(); + } + else if (e.getCode() == decrement) { + decrement(1); + e.consume(); + } + }; /*************************************************************************** * * @@ -84,24 +95,16 @@ public SpinnerBehavior(Spinner spinner) { // InputMap installed on the control, if it is non-null, allowing us to pick up any user-specified mappings) spinnerInputMap = createInputMap(); - // then spinner-specific mappings for key and mouse input - addDefaultMapping(spinnerInputMap, - new KeyMapping(UP, KeyEvent.KEY_PRESSED, e -> { - if (arrowsAreVertical()) increment(1); else FocusTraversalInputMap.traverseUp(e); - }), - new KeyMapping(RIGHT, KeyEvent.KEY_PRESSED, e -> { - if (! arrowsAreVertical()) increment(1); else FocusTraversalInputMap.traverseRight(e); - }), - new KeyMapping(LEFT, KeyEvent.KEY_PRESSED, e -> { - if (! arrowsAreVertical()) decrement(1); else FocusTraversalInputMap.traverseLeft(e); - }), - new KeyMapping(DOWN, KeyEvent.KEY_PRESSED, e -> { - if (arrowsAreVertical()) decrement(1); else FocusTraversalInputMap.traverseDown(e); - }) - ); + spinner.addEventFilter(KeyEvent.KEY_PRESSED, spinnerKeyHandler); } + @Override + public void dispose() { + getNode().removeEventFilter(KeyEvent.KEY_PRESSED, spinnerKeyHandler); + + super.dispose(); + } /*************************************************************************** * * diff --git a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/SpinnerSkin.java b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/SpinnerSkin.java index 3cff164b9ac..e0e6a084280 100644 --- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/SpinnerSkin.java +++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/SpinnerSkin.java @@ -27,6 +27,7 @@ import java.util.List; import javafx.css.PseudoClass; +import javafx.event.Event; import javafx.geometry.HPos; import javafx.geometry.VPos; import javafx.scene.AccessibleAction; @@ -41,6 +42,7 @@ import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; +import com.sun.javafx.event.EventDispatchChainImpl; import com.sun.javafx.scene.ParentHelper; import com.sun.javafx.scene.control.FakeFocusTextField; import com.sun.javafx.scene.control.ListenerHelper; @@ -177,40 +179,22 @@ public void executeAccessibleAction(AccessibleAction action, Object... parameter ((FakeFocusTextField)textField).setFakeFocus(control.isFocused()); }); - lh.addEventFilter(control, KeyEvent.ANY, (ke) -> { - if (control.isEditable()) { - // This prevents a stack overflow from our rebroadcasting of the - // event to the textfield that occurs in the final else statement - // of the conditions below. - if (ke.getTarget().equals(textField)) return; - - // Fix for RT-38527 which led to a stack overflow - if (ke.getCode() == KeyCode.ESCAPE) return; - - // This and the additional check of isIncDecKeyEvent in - // textField's event filter fix JDK-8185937. - if (isIncDecKeyEvent(ke)) return; - - // Fix for the regression noted in a comment in RT-29885. - // This forwards the event down into the TextField when - // the key event is actually received by the Spinner. - textField.fireEvent(ke.copyFor(textField, textField)); - - if (ke.getCode() == KeyCode.ENTER) return; - - ke.consume(); - } - }); - - // This event filter is to enable keyboard events being delivered to the - // spinner when the user has mouse clicked into the TextField area of the - // Spinner control. Without this the up/down/left/right arrow keys don't - // work when you click inside the TextField area (but they do in the case - // of tabbing in). - lh.addEventFilter(textField, KeyEvent.ANY, (ke) -> { - if (! control.isEditable() || isIncDecKeyEvent(ke)) { - control.fireEvent(ke.copyFor(control, control)); - ke.consume(); + // Forwards all key events arriving at the control level to the internal + // text field, if the control is editable. This forwarding is limited to the + // text field only, and so the forwarded event will NOT traverse the entire + // scene graph. The originating event is only consumed if the forwarded + // event was consumed. + lh.addEventFilter(control, KeyEvent.ANY, e -> { + // Note: due to a bug, we check if the event is consumed here. The behavior + // will consume the appropriate arrow keys, but the event is STILL delivered to this + // filter at the same level. Without the consume check, the TextField will act + // on arrow keys, moving the cursor unexpectedly. + if (!e.isConsumed() && control.isEditable()) { + Event event = textField.getEventDispatcher().dispatchEvent(e.copyFor(textField, textField), new EventDispatchChainImpl()); + + if (event == null || event.isConsumed()) { + e.consume(); // consume original trigger event + } } }); diff --git a/modules/javafx.controls/src/test/java/test/javafx/scene/control/SpinnerTest.java b/modules/javafx.controls/src/test/java/test/javafx/scene/control/SpinnerTest.java index 842b4c15965..cb7d39e0d45 100644 --- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/SpinnerTest.java +++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/SpinnerTest.java @@ -1603,8 +1603,6 @@ public void test_jdk_8150946_testCommit_invalid_wrongType() { stage.setWidth(200); stage.setHeight(200); - intSpinner.setEditable(true); - Button defaultButton = new Button("OK"); defaultButton.setOnAction(arg0 -> { enterDefaultPass = true; }); defaultButton.setDefaultButton(true);