Skip to content

Commit 5febaca

Browse files
author
Michael Strauß
committed
8291502: Mouse or touch presses on a non-focusable region don't clear the focusVisible flag of the current focus owner
Reviewed-by: kcr, aghaisas
1 parent 8fa8919 commit 5febaca

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

modules/javafx.controls/src/test/java/test/com/sun/javafx/scene/control/infrastructure/MouseEventFirer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,9 @@ public final class MouseEventFirer {
6060
public MouseEventFirer(EventTarget target) {
6161
this.target = target;
6262

63+
// Use the alternative creation path for MouseEvent by default, see JDK-8253769
64+
this.alternative = true;
65+
6366
// Force the target node onto a stage so that it is accessible
6467
if (target instanceof Node) {
6568
Node n = (Node)target;

modules/javafx.graphics/src/main/java/javafx/scene/Scene.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,18 @@ private Scene(Parent root, double width, double height, Paint fill,
360360
setRoot(root);
361361
init(width, height);
362362
setFill(fill);
363+
364+
// Any mouse or touch press on the scene will clear the focusVisible flag of
365+
// the current focus owner, if there is one.
366+
EventHandler<InputEvent> pressedHandler = event -> {
367+
Node focusOwner = getFocusOwner();
368+
if (focusOwner != null) {
369+
getKeyHandler().setFocusVisible(focusOwner, false);
370+
}
371+
};
372+
373+
addEventFilter(MouseEvent.MOUSE_PRESSED, pressedHandler);
374+
addEventFilter(TouchEvent.TOUCH_PRESSED, pressedHandler);
363375
}
364376

365377
static {
@@ -4036,7 +4048,9 @@ private PickResult pickNode(PickRay pickRay) {
40364048
class KeyHandler {
40374049
boolean focusVisible;
40384050

4039-
private void setFocusOwner(final Node value) {
4051+
private void setFocusOwner(Node value, boolean focusVisible) {
4052+
this.focusVisible = focusVisible;
4053+
40404054
// Cancel IM composition if there is one in progress.
40414055
// This needs to be done before the focus owner is switched as it
40424056
// generates event that needs to be delivered to the old focus owner.
@@ -4053,6 +4067,7 @@ private void setFocusOwner(final Node value) {
40534067
}
40544068

40554069
private void setFocusVisible(Node node, boolean focusVisible) {
4070+
this.focusVisible = focusVisible;
40564071
node.focusVisible.set(focusVisible);
40574072
node.focusVisible.notifyListeners();
40584073
}
@@ -4100,11 +4115,10 @@ private void process(KeyEvent e) {
41004115

41014116
private void requestFocus(Node node, boolean focusVisible) {
41024117
if (node == null) {
4103-
setFocusOwner(null);
4118+
setFocusOwner(null, false);
41044119
} else if (node.isCanReceiveFocus()) {
41054120
if (node != getFocusOwner()) {
4106-
this.focusVisible = focusVisible;
4107-
setFocusOwner(node);
4121+
setFocusOwner(node, focusVisible);
41084122
} else {
41094123
setFocusVisible(node, focusVisible);
41104124
}

modules/javafx.graphics/src/test/java/test/javafx/scene/FocusTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import com.sun.javafx.scene.SceneHelper;
3030
import javafx.event.Event;
31+
import javafx.event.EventTarget;
3132
import javafx.scene.input.KeyCode;
3233
import javafx.scene.input.KeyEvent;
3334
import test.com.sun.javafx.pgstub.StubScene;
@@ -41,6 +42,7 @@
4142
import static org.junit.Assert.fail;
4243

4344
import java.util.ArrayList;
45+
import java.util.Collections;
4446
import java.util.List;
4547

4648
import javafx.scene.Group;
@@ -49,6 +51,11 @@
4951
import javafx.scene.Scene;
5052
import javafx.scene.SceneShim;
5153

54+
import javafx.scene.input.MouseButton;
55+
import javafx.scene.input.MouseEvent;
56+
import javafx.scene.input.PickResult;
57+
import javafx.scene.input.TouchEvent;
58+
import javafx.scene.input.TouchPoint;
5259
import javafx.scene.shape.Rectangle;
5360
import javafx.stage.Stage;
5461

@@ -775,6 +782,25 @@ private void fireTabKeyEvent(Node node) {
775782
Event.fireEvent(node, new KeyEvent(KeyEvent.KEY_RELEASED, null, null, KeyCode.TAB, false, false, false, false));
776783
}
777784

785+
private void fireMousePressedEvent(EventTarget target) {
786+
double x = 10, y = 10;
787+
PickResult pickResult = new PickResult(target, x, y);
788+
Event.fireEvent(target, new MouseEvent(
789+
MouseEvent.MOUSE_PRESSED, x, y, x, y, MouseButton.PRIMARY, 1,
790+
false, false, false, false,
791+
true, false, false,
792+
false, false, false, pickResult));
793+
}
794+
795+
private void fireTouchPressedEvent(EventTarget target) {
796+
double x = 10, y = 10;
797+
PickResult pickResult = new PickResult(scene, x, y);
798+
Event.fireEvent(target, new TouchEvent(
799+
TouchEvent.TOUCH_PRESSED,
800+
new TouchPoint(0, TouchPoint.State.PRESSED, x, y, x, y, target, pickResult),
801+
Collections.emptyList(), 0, false, false, false, false));
802+
}
803+
778804
/**
779805
* If a node acquires focus by calling {@link Node#requestFocus()}, it does not acquire visible focus.
780806
*/
@@ -848,6 +874,44 @@ private void fireTabKeyEvent(Node node) {
848874
assertNotFocusVisible(node2);
849875
}
850876

877+
/**
878+
* When any region of the window is clicked, the focus owner loses visible focus
879+
* even when the focus owner doesn't change.
880+
*/
881+
@Test public void testMousePressedClearsFocusVisible() {
882+
Node node1 = n(), node2 = n();
883+
Group g = new Group(node1, node2);
884+
scene.setRoot(g);
885+
fireTabKeyEvent(g);
886+
887+
assertIsFocused(scene, node1);
888+
assertIsFocusVisible(node1);
889+
890+
fireMousePressedEvent(scene);
891+
892+
assertIsFocused(scene, node1);
893+
assertNotFocusVisible(node1);
894+
}
895+
896+
/**
897+
* When any region of the window is touched, the focus owner loses visible focus
898+
* even when the focus owner doesn't change.
899+
*/
900+
@Test public void testTouchPressedClearsFocusVisible() {
901+
Node node1 = n(), node2 = n();
902+
Group g = new Group(node1, node2);
903+
scene.setRoot(g);
904+
fireTabKeyEvent(g);
905+
906+
assertIsFocused(scene, node1);
907+
assertIsFocusVisible(node1);
908+
909+
fireTouchPressedEvent(scene);
910+
911+
assertIsFocused(scene, node1);
912+
assertNotFocusVisible(node1);
913+
}
914+
851915
/**
852916
* When a node acquires focus, the focusWithin property is set on the node
853917
* and all of its parents.

0 commit comments

Comments
 (0)