43
43
44
44
import org .junit .jupiter .api .AfterAll ;
45
45
import org .junit .jupiter .api .Assertions ;
46
+ import org .junit .jupiter .api .Assumptions ;
46
47
import org .junit .jupiter .api .BeforeAll ;
47
48
import org .junit .jupiter .api .Test ;
48
49
49
50
import com .sun .javafx .PlatformUtil ;
50
51
51
52
import test .util .Util ;
52
53
53
- // When a key equivalent is sent it may be processed by
54
- // JavaFX and also trigger a menu item if the system menu
55
- // bar is in use.
56
54
public class MenuDoubleShortcutTest {
57
55
58
56
static CountDownLatch startupLatch = new CountDownLatch (1 );
@@ -62,13 +60,13 @@ public class MenuDoubleShortcutTest {
62
60
static private final int delayMilliseconds = 100 ;
63
61
64
62
private enum TestResult {
63
+ // We provide an explanation of what happened. Since we only see this
64
+ // explanation on failure it is worded accordingly.
65
65
IGNORED ("Key press event triggered no actions" ),
66
- FIREDTWICE ("Key press event consumed by scene also fired menu bar item" ),
67
- FIREDMENUITEM ("Key press event fired menu bar item instead of scene" ),
66
+ FIREDTWICE ("Key press event fired scene action and also a menu bar item" ),
67
+ FIREDMENUITEM ("Key press event fired menu bar item instead of scene action " ),
68
68
FIREDSCENE ("Key press event fired scene action instead of menu bar item" );
69
69
70
- // We provide an explanation of what happened. Since we only see this
71
- // explanation on failure it is worded accordingly.
72
70
private String explanation ;
73
71
TestResult (String e ) {
74
72
explanation = e ;
@@ -82,46 +80,59 @@ public String errorExplanation() {
82
80
// KeyCode.A will be added to the menu bar and the scene
83
81
// KeyCode.B will be added to the menu bar only
84
82
// KeyCode.C will be added to the scene only.
85
-
83
+ private static final KeyCode menuBarAndSceneKeyCode = KeyCode .A ;
84
+ private static final KeyCode menuBarOnlyKeyCode = KeyCode .B ;
85
+ private static final KeyCode sceneOnlyKeyCode = KeyCode .C ;
86
+ private static final KeyCode noAcceleratorKeyCode = KeyCode .D ;
87
+
88
+ private static final KeyCombination menuBarAndSceneAccelerator = new KeyCodeCombination (menuBarAndSceneKeyCode , KeyCombination .SHORTCUT_DOWN );
89
+ private static final KeyCombination menuBarOnlyAccelerator = new KeyCodeCombination (menuBarOnlyKeyCode , KeyCombination .SHORTCUT_DOWN );
90
+ private static final KeyCombination sceneOnlyAccelerator = new KeyCodeCombination (sceneOnlyKeyCode , KeyCombination .SHORTCUT_DOWN );
91
+
92
+ // On Mac the scene should process the event and it should
93
+ // not trigger a system menu bar item.
94
+ //
95
+ // https://bugs.openjdk.org/browse/JDK-8087863
96
+ // https://bugs.openjdk.org/browse/JDK-8088897
86
97
@ Test
87
- void sceneComesBeforeMenuBar () {
88
- // Assumptions.assumeTrue(PlatformUtil.isMac());
89
-
90
- // KeyCode.A is in the menu bar and scene
91
- testApp .testKey (KeyCode .A );
98
+ void macSceneComesBeforeMenuBar () {
99
+ Assumptions .assumeTrue (PlatformUtil .isMac ());
100
+ testApp .testKey (menuBarAndSceneKeyCode );
92
101
Util .sleep (delayMilliseconds );
93
102
TestResult result = testApp .testResult ();
94
103
Assertions .assertEquals (TestResult .FIREDSCENE , result , result .errorExplanation ());
95
104
}
96
105
106
+ // On platforms other than Mac the menu bar should process the event
107
+ // and the scene should not.
97
108
@ Test
98
- void acceleratorOnlyInMenuBar () {
99
- // Assumptions.assumeTrue(PlatformUtil.isMac());
109
+ void nonMacMenuBarComesBeforeScene () {
110
+ Assumptions .assumeFalse (PlatformUtil .isMac ());
111
+ testApp .testKey (menuBarAndSceneKeyCode );
112
+ Util .sleep (delayMilliseconds );
113
+ TestResult result = testApp .testResult ();
114
+ Assertions .assertEquals (TestResult .FIREDMENUITEM , result , result .errorExplanation ());
115
+ }
100
116
101
- // KeyCode.B is only in the menu bar.
102
- testApp .testKey (KeyCode .B );
117
+ @ Test
118
+ void acceleratorOnlyInMenuBar () {
119
+ testApp .testKey (menuBarOnlyKeyCode );
103
120
Util .sleep (delayMilliseconds );
104
121
TestResult result = testApp .testResult ();
105
122
Assertions .assertEquals (TestResult .FIREDMENUITEM , result , result .errorExplanation ());
106
123
}
107
124
108
125
@ Test
109
126
void acceleratorOnlyInScene () {
110
- // Assumptions.assumeTrue(PlatformUtil.isMac());
111
-
112
- // KeyCode.C is only in the scene.
113
- testApp .testKey (KeyCode .C );
127
+ testApp .testKey (sceneOnlyKeyCode );
114
128
Util .sleep (delayMilliseconds );
115
129
TestResult result = testApp .testResult ();
116
130
Assertions .assertEquals (TestResult .FIREDSCENE , result , result .errorExplanation ());
117
131
}
118
132
119
133
@ Test
120
134
void acceleratorAbsent () {
121
- // Assumptions.assumeTrue(PlatformUtil.isMac());
122
-
123
- // KeyCode.D is not registered as an accelerator
124
- testApp .testKey (KeyCode .D );
135
+ testApp .testKey (noAcceleratorKeyCode );
125
136
Util .sleep (delayMilliseconds );
126
137
TestResult result = testApp .testResult ();
127
138
Assertions .assertEquals (TestResult .IGNORED , result , result .errorExplanation ());
@@ -143,7 +154,7 @@ public static class TestApp extends Application {
143
154
private boolean menuBarItemFired = false ;
144
155
145
156
private MenuItem createMenuItem (KeyCombination accelerator ) {
146
- MenuItem menuItem = new MenuItem ("Cmd+A menu item" );
157
+ MenuItem menuItem = new MenuItem (accelerator . getName () + " menu item" );
147
158
menuItem .setAccelerator (accelerator );
148
159
menuItem .setOnAction (e -> {
149
160
menuBarItemFired = true ;
@@ -163,42 +174,38 @@ public void start(Stage primaryStage) {
163
174
MenuBar menuBar = new MenuBar ();
164
175
menuBar .setUseSystemMenuBar (true );
165
176
166
- // KeyCode.A will be added to the menu bar and the scene
167
- // KeyCode.B will be added to the menu bar only
168
- // KeyCode.C will be added to the scene only.
169
- KeyCombination acceleratorA = new KeyCodeCombination (KeyCode .A , KeyCombination .SHORTCUT_DOWN );
170
- KeyCombination acceleratorB = new KeyCodeCombination (KeyCode .B , KeyCombination .SHORTCUT_DOWN );
171
- KeyCombination acceleratorC = new KeyCodeCombination (KeyCode .C , KeyCombination .SHORTCUT_DOWN );
172
-
173
177
Menu menu = new Menu ("Top menu" );
174
- menu .getItems ().add (createMenuItem (acceleratorA ));
175
- menu .getItems ().add (createMenuItem (acceleratorB ));
178
+ menu .getItems ().add (createMenuItem (menuBarAndSceneAccelerator ));
179
+ menu .getItems ().add (createMenuItem (menuBarOnlyAccelerator ));
176
180
menuBar .getMenus ().add (menu );
177
181
178
182
Scene scene = new Scene (new VBox (menuBar , label ), 200 , 200 );
179
- scene .getAccelerators ().put (acceleratorA , () -> {
183
+ scene .getAccelerators ().put (menuBarAndSceneAccelerator , () -> {
180
184
sceneAcceleratorFired = true ;
181
185
});
182
- scene .getAccelerators ().put (acceleratorC , () -> {
186
+ scene .getAccelerators ().put (sceneOnlyAccelerator , () -> {
183
187
sceneAcceleratorFired = true ;
184
188
});
185
189
186
190
stage .setScene (scene );
187
- stage .setOnShown (e -> { startupLatch .countDown (); });
191
+ stage .setOnShown (e -> {
192
+ Platform .runLater (() -> {
193
+ startupLatch .countDown ();
194
+ });
195
+ });
188
196
stage .show ();
189
197
}
190
198
191
199
public void testKey (KeyCode code ) {
192
200
sceneAcceleratorFired = false ;
193
201
menuBarItemFired = false ;
194
202
Platform .runLater (() -> {
195
- // Need to ensure Cmd is present so this is handled
196
- // as a key equivalent.
203
+ KeyCode shortcutCode = (PlatformUtil .isMac () ? KeyCode .COMMAND : KeyCode .CONTROL );
197
204
Robot robot = new Robot ();
198
- robot .keyPress (KeyCode . COMMAND );
205
+ robot .keyPress (shortcutCode );
199
206
robot .keyPress (code );
200
207
robot .keyRelease (code );
201
- robot .keyRelease (KeyCode . COMMAND );
208
+ robot .keyRelease (shortcutCode );
202
209
});
203
210
}
204
211
0 commit comments