Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8207759: VK_ENTER not consumed by TextField when default Button exists #15

Closed
wants to merge 3 commits into from

Conversation

kleopatra
Copy link
Collaborator

@kleopatra kleopatra commented Oct 16, 2019

This is a fix for https://bugs.openjdk.java.net/browse/JDK-8207759

The issue is that default/cancel button on a scene are triggered even though a onKeyPressed handler for ENTER/CANCEL consumes the keyEvent. See the bug for details on both cause and fix.

There are additional/changed tests to verify the fix. All old tests are passing.

Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed

Issue

JDK-8207759: VK_ENTER not consumed by TextField when default Button exists

Approvers

  • Ajit Ghaisas (aghaisas - Reviewer)
  • Kevin Rushforth (kcr - Reviewer)

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 16, 2019

👋 Welcome back fastegal! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request (refresh this page to view it).

@openjdk openjdk bot added the rfr Ready for review label Oct 16, 2019
@mlbridge
Copy link

mlbridge bot commented Oct 16, 2019

Webrevs

@kevinrushforth
Copy link
Member

@aghaisas can you review this as well?

@kevinrushforth
Copy link
Member

This will need two reviewers.

Copy link
Collaborator

@aghaisas aghaisas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look OK apart from one doubt I have listed.

@openjdk openjdk bot removed the rfr Ready for review label Dec 16, 2019
@openjdk
Copy link

openjdk bot commented Dec 16, 2019

@kleopatra This change can now be integrated. The commit message will be:

8207759: VK_ENTER not consumed by TextField when default Button exists

Reviewed-by: aghaisas, kcr
  • If you would like to add a summary, use the /summary command.
  • To list additional contributors, use the /contributor command.

Since the source branch of this PR was last updated there have been 53 commits pushed to the master branch:

  • fc539b5: 8223296: NullPointerException in GlassScene.java at line 325
  • 71ca899: 8220722: ProgressBarSkin: adds strong listener to control's width property
  • 07af89a: 8221334: TableViewSkin: must initialize flow's cellCount in constructor
  • 4ddf554: 8234916: [macos 10.15] Garbled text running with native-image
  • 46338d0: 8232524: SynchronizedObservableMap cannot be be protected for copying/iterating
  • a68347c: 8235150: IosApplication does not pass the required object in _leaveNestedEventLoopImpl
  • 1c27fbd: 8210955: DOMTest::testEventListenerCascade fails
  • 2d4096a: 8235151: Nonexistent notifyQuit method referred from iOS GlassHelper.m
  • 98035cb: 8211308: Support HTTP/2 in WebView
  • 6892fa1: 8232064: Switch FX build to use JDK 13.0.1 as boot JDK
  • 1d670f1: 8200224: Multiple press event when JFXPanel gains focus
  • 83eb0a7: 8193445: JavaFX CSS is applied redundantly leading to significant performance degradation
  • 798afbc: 8230610: Upgrade GStreamer to version 1.16.1
  • 126896d: 8234704: Fix attribution in libxslt.md
  • 4d3c723: 8234593: Mark LeakTest.testGarbageCollectability as unstable
  • 5a39824: 8234056: Upgrade to libxslt 1.1.34
  • 8bea7b7: 8229472: Deprecate for removal JavaBeanXxxPropertyBuilders constructors
  • aad1720: 8233420: Upgrade to gcc 8.3 on Linux
  • 42040c4: 8232063: Upgrade gradle to version 6.0
  • aab07a4: 8234239: [TEST_BUG] Reenable few ignored web tests
  • 95ad601: 8233421: Upgrade to Visual Studio 2017 version 15.9.16
  • 3e0557a: 8234303: [TEST_BUG] Correct ignore tag in graphics unit tests
  • e37cb37: 8234150: Address ignored tests in ComboBoxTest, LabeledTest, HyperLinkTest and TextInputControlTest
  • 4f496d4: 8234194: [TEST_BUG] Reenable few graphics unit tests
  • 927fc8a: 8234174: Change IDEA VCS mapping to Git
  • 3d0cb49: 8234189: [TEST_BUG] Remove ignored and invalid graphics unit tests
  • dc01309: 8234110: SwingFXUtilsTest is unsuitable for unit test framework
  • 5b96ee4: 8231188: Update SQLite to version 3.30.1
  • d46dcae: 8233338: FX javadoc headings are out of sequence
  • 94bcf3f: 8231692: Test Infrastructure: enhance KeyEventFirer to inject keyEvents into scene
  • 286d1b5: 8230492: font-family not set in HTMLEditor if font name has a number in it
  • f74f3af: 8233040: ComboBoxPopupControl: remove eventFilter for F4
  • a1cc4ab: 8232210: Update Mesa 3-D Headers to version 19.2.1
  • dca8df4: 8232943: Gesture support is not initialized on iOS
  • 5a70b0c: 8189092: ArrayIndexOutOfBoundsException on Linux in getCachedGlyph
  • ac71396: 8232929: Duplicate symbols when building static libraries
  • ab6ea3b: 8232158: [macOS] Fallback to command line tools if xcode is missing
  • 2ae171a: 8232687: No static JNI loader for libprism-sw
  • a09a0fa: 8232522: FX: Update copyright year in docs, readme files to 2020
  • 582d999: Merge
  • b6e53f4: 8218640: Update ICU4C to version 64.2
  • bada612: Merge
  • 64aaeb8: 8226754: FX build fails using gradle 5.6+ or 6
  • a4bc22d: Merge
  • 2593dea: Merge
  • 9df20c5: Merge
  • a1aa38a: Merge
  • 0ff02bb: Merge
  • a433bf2: Merge
  • 561153d: Merge
  • 75d439e: Merge
  • 758252f: Merge
  • 35e0cae: 8227402: Improve XSLT processing

Since there are no conflicts, your changes will automatically be rebased on top of the above commits when integrating. If you prefer to do this manually, please merge master into your branch first.

As you do not have Committer status in this project, an existing Committer must agree to sponsor your change. Possible candidates are the reviewers of this PR (@aghaisas, @kevinrushforth) but any other Committer may sponsor as well.

  • To flag this PR as ready for integration with the above commit message, type /integrate in a new comment. (Afterwards, your sponsor types /sponsor in a new comment to perform the integration).

@openjdk openjdk bot added the ready Ready to be integrated label Dec 16, 2019
@kleopatra
Copy link
Collaborator Author

kleopatra commented Dec 16, 2019 via email

@kevinrushforth
Copy link
Member

Right, this still needs one more review (I hope to get to it today).

The bot doesn't know whether all criteria have been met. It can't, for example, know whether there are outstanding comments from some reviewers that need to be addressed. Nor does it know which PRs need two reviewers (or sometimes a third if there is a specific person we would like to review it), which ones need a CSR, etc.

So having it state authoritatively that the PR is ready to integrate is a bit misleading in this case. This is documented in the Code Review section of the CONTRIBUTING doc:

NOTE: while the Skara tooling will indicate that the PR is ready to integrate once the first reviewer with a "Reviewer" role in the project has approved it, this may or may not be sufficient depending on the type of fix. For example, you must wait for a second approval for enhancements or high-impact bug fixes.

I wonder if there is a way to improve this?

@kleopatra
Copy link
Collaborator Author

/integrate

@openjdk openjdk bot added the sponsor Ready to sponsor label Dec 17, 2019
@openjdk
Copy link

openjdk bot commented Dec 17, 2019

@kleopatra
Your change (at version 7c10ad1) is now ready to be sponsored by a Committer.

@aghaisas
Copy link
Collaborator

/sponsor

@openjdk openjdk bot closed this Dec 17, 2019
@openjdk openjdk bot added integrated Pull request has been integrated and removed sponsor Ready to sponsor ready Ready to be integrated labels Dec 17, 2019
@openjdk
Copy link

openjdk bot commented Dec 17, 2019

@aghaisas @kleopatra The following commits have been pushed to master since your change was applied:

  • fc539b5: 8223296: NullPointerException in GlassScene.java at line 325
  • 71ca899: 8220722: ProgressBarSkin: adds strong listener to control's width property
  • 07af89a: 8221334: TableViewSkin: must initialize flow's cellCount in constructor
  • 4ddf554: 8234916: [macos 10.15] Garbled text running with native-image
  • 46338d0: 8232524: SynchronizedObservableMap cannot be be protected for copying/iterating
  • a68347c: 8235150: IosApplication does not pass the required object in _leaveNestedEventLoopImpl
  • 1c27fbd: 8210955: DOMTest::testEventListenerCascade fails
  • 2d4096a: 8235151: Nonexistent notifyQuit method referred from iOS GlassHelper.m
  • 98035cb: 8211308: Support HTTP/2 in WebView
  • 6892fa1: 8232064: Switch FX build to use JDK 13.0.1 as boot JDK
  • 1d670f1: 8200224: Multiple press event when JFXPanel gains focus
  • 83eb0a7: 8193445: JavaFX CSS is applied redundantly leading to significant performance degradation
  • 798afbc: 8230610: Upgrade GStreamer to version 1.16.1
  • 126896d: 8234704: Fix attribution in libxslt.md
  • 4d3c723: 8234593: Mark LeakTest.testGarbageCollectability as unstable
  • 5a39824: 8234056: Upgrade to libxslt 1.1.34
  • 8bea7b7: 8229472: Deprecate for removal JavaBeanXxxPropertyBuilders constructors
  • aad1720: 8233420: Upgrade to gcc 8.3 on Linux
  • 42040c4: 8232063: Upgrade gradle to version 6.0
  • aab07a4: 8234239: [TEST_BUG] Reenable few ignored web tests
  • 95ad601: 8233421: Upgrade to Visual Studio 2017 version 15.9.16
  • 3e0557a: 8234303: [TEST_BUG] Correct ignore tag in graphics unit tests
  • e37cb37: 8234150: Address ignored tests in ComboBoxTest, LabeledTest, HyperLinkTest and TextInputControlTest
  • 4f496d4: 8234194: [TEST_BUG] Reenable few graphics unit tests
  • 927fc8a: 8234174: Change IDEA VCS mapping to Git
  • 3d0cb49: 8234189: [TEST_BUG] Remove ignored and invalid graphics unit tests
  • dc01309: 8234110: SwingFXUtilsTest is unsuitable for unit test framework
  • 5b96ee4: 8231188: Update SQLite to version 3.30.1
  • d46dcae: 8233338: FX javadoc headings are out of sequence
  • 94bcf3f: 8231692: Test Infrastructure: enhance KeyEventFirer to inject keyEvents into scene
  • 286d1b5: 8230492: font-family not set in HTMLEditor if font name has a number in it
  • f74f3af: 8233040: ComboBoxPopupControl: remove eventFilter for F4
  • a1cc4ab: 8232210: Update Mesa 3-D Headers to version 19.2.1
  • dca8df4: 8232943: Gesture support is not initialized on iOS
  • 5a70b0c: 8189092: ArrayIndexOutOfBoundsException on Linux in getCachedGlyph
  • ac71396: 8232929: Duplicate symbols when building static libraries
  • ab6ea3b: 8232158: [macOS] Fallback to command line tools if xcode is missing
  • 2ae171a: 8232687: No static JNI loader for libprism-sw
  • a09a0fa: 8232522: FX: Update copyright year in docs, readme files to 2020
  • 582d999: Merge
  • b6e53f4: 8218640: Update ICU4C to version 64.2
  • bada612: Merge
  • 64aaeb8: 8226754: FX build fails using gradle 5.6+ or 6
  • a4bc22d: Merge
  • 2593dea: Merge
  • 9df20c5: Merge
  • a1aa38a: Merge
  • 0ff02bb: Merge
  • a433bf2: Merge
  • 561153d: Merge
  • 75d439e: Merge
  • 758252f: Merge
  • 35e0cae: 8227402: Improve XSLT processing

Your commit was automatically rebased without conflicts.

Pushed as commit d2d44b4.

@kleopatra kleopatra deleted the bug-fix-JDK-8207759 branch May 5, 2020 09:06
kevinrushforth pushed a commit to kevinrushforth/jfx that referenced this pull request Feb 24, 2023
Comment on lines +188 to 190
if (onAction != null || actionEvent.isConsumed()) {
event.consume();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kleopatra @kevinrushforth @aghaisas

Shouldn't this be an && ? Now having an empty setOnAction that doesn't consume anything (but just logs for example) will affect the operation of this control.

Copy link
Contributor

@andy-goryachev-oracle andy-goryachev-oracle Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, it's a bug.
#1523

Copy link
Collaborator Author

@kleopatra kleopatra Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hjohn @kevinrushforth @aghaisas

hmm .. it's been a while but you might be on to something.

Let's recap:

  • the first issue to get fixed was JDK-8207774: the problem was that the isConsumed always was false (due to creating the actionEvent for passing around was done by the constructor that led to immediate copying, setting consumed to false)
  • the next issue was this: the problem was that actively refiring the keyEvent on parent led to a nested eventDispatch, confusing every collaborator. That was fixed by removing the refire altogether and consuming the keyEvent if handled by the textField's action/Listeners (that's the plainly reverted logic above)
  • both before and after the fixes the state "handled" can be reached by the mere existence of an onAction handler on the textField, consuming or not

And that's still wrong, as you correctly - IMO - noted. The expectation formulated as a test (c&p and adjusted from TextFieldTest)

/**
 * ENTER must be forwarded if action
 * not consumed the action.
 *
 * Here we test that key handlers on parent are notified.
 */
@Test
public void testEnterWithNotConsumingActionParentHandler() {
    initStage();
    root.getChildren().add(txtField);
    txtField.setOnAction(e -> {}); // do nothing handler
    List<KeyEvent> keys = new ArrayList<>();

    root.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
        keys.add(e);
    });
    stage.show();
    KeyEventFirer keyboard = new KeyEventFirer(txtField);
    keyboard.doKeyPress(ENTER);
    assertEquals("key handler must be notified", 1, keys.size());
}

We can't reach that by replacing the || by && (would introduce a regression, as failing tests indicate) but .. maybe by entirely removing the not/null check of onAction: the fired actionEvent will be passed to the singleton handler (along with any added via addXX) anyway, so it doesn't really make sense (with the first issue fixed)

Now the method looks like and all tests including the new one above (and hopefully the analogous twins of XXConsuming -> XXNotConsuming, didn't try, being lazy ;):

@Override protected void fire(KeyEvent event) {
    TextField textField = getNode();
    EventHandler<ActionEvent> onAction = textField.getOnAction();
    // JDK-8207774
    // use textField as target to prevent immediate copy in dispatch
    ActionEvent actionEvent = new ActionEvent(textField, textField);

    textField.commitValue();
    textField.fireEvent(actionEvent);
    // JDK-8207759 
    // mapping must not auto-consume 
   // instead consume here if handled by action or handlers
    if (actionEvent.isConsumed()) {
        event.consume();
    }
}

What do you think? My code brain is a bit rusty, so might have missed something.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kleopatra Your explanation makes sense to me. Thank you for taking the time to write it up.

If so, the proposed fix, including adjusting the comment, would be:

--- a/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java
+++ b/modules/javafx.controls/src/main/java/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java
@@ -162,9 +162,8 @@ public class TextFieldBehavior extends TextInputControlBehavior<TextField> {

         textField.commitValue();
         textField.fireEvent(actionEvent);
-        // fix of JDK-8207759: reverted logic
-        // mapping not auto-consume and consume if handled by action
-        if (onAction != null || actionEvent.isConsumed()) {
+        // Consume the original event if the copied actionEvent was consumed.
+        if (actionEvent.isConsumed()) {
             event.consume();
         }
     }

Copy link
Collaborator

@hjohn hjohn Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, && would be insufficient as there is another way to add action handlers. I didn't really see that, although the fix I had in mind was to eliminate the onAction variable completely (it is unused in your fix as well), so probably would have ended up at the correct result :)

I can roll this into a small PR if you wish.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, checking the isConsumed flag will only work if the action is consumed by a handler registered directly with the TextField. If there's a filter or handler attached to some other part of the scene graph a copy of the event will be made and consumed and actionEvent.isConsumed() will return false. A more complete fix is to replace textField.fireEvent with a call to EventUtil.fireEvent and check for a null return value.

If I understand this thread correctly if a KeyEvent generates an ActionEvent the KeyEvent should only be consumed if the ActionEvent is. If so the behavior should be consistent across TextFields and the controls that manage TextFields internally (Spinner, ComboBox, and DatePicker). I'm already working on a test for Escape key handling for this set of controls (for Escape the issue is whether a formatter is attached or not). I'm willing to write up a similar test for Enter handling for the same set of controls. I just need to make sure I understand exactly what behavior is expected.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, checking the isConsumed flag will only work if the action is consumed by a handler registered directly with the TextField. If there's a filter or handler attached to some other part of the scene graph a copy of the event will be made and consumed and actionEvent.isConsumed() will return false. A more complete fix is to replace textField.fireEvent with a call to EventUtil.fireEvent and check for a null return value.

It seems that an earlier check I did to see if events are copied wasn't done correctly. Indeed events are copied at every filter/handler. That does seem excessive. It also makes the public Node#fireEvent a bit useless for proper event propagation for normal users that don't have access to EventUtil.

I checked the events that are copied, and it is basically making the copy to adjust the source (target remains constant). That's really odd; I'd expect the source to remain the same as well (ie. the Scene or Window, not the "previous" filter/handler Node level), especially as it is documented as:

/**
 * The object on which the Event initially occurred.
 *
 * @return the object on which the Event initially occurred
 */
public Object getSource() {
    return source;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the events that are copied, and it is basically making the copy to adjust the source (target remains constant). That's really odd; I'd expect the source to remain the same as well (ie. the Scene or Window, not the "previous" filter/handler Node level), especially as it is documented as:

I haven't walked through this in AWT (there are only so many hours in the day) but I believe the AWT source corresponds to the JavaFX target i.e. the object the event was fired against. JavaFX repurposes source as the object the handler or filter was registered on. JavaFX shouldn't be pointing at the AWT documentation since it doesn't match the JavaFX implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integrated Pull request has been integrated
Development

Successfully merging this pull request may close these issues.

6 participants