Skip to content

Commit 3aa0a24

Browse files
committed
Fix auto-complete popup on Windows
Focus behavior differences made the popup completely keyboard-inaccessible, which is pretty terrible. Fix this by explicitly requesting focus after opening. Also move all of the handlers to the popup, instead of just the JList, as it seems simpler and some of the handlers affect the entire popup, anyway.
1 parent deda0e0 commit 3aa0a24

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

src/main/java/edu/umich/soar/visualsoar/components/AutocompletePopup.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.awt.event.MouseAdapter;
1313
import java.awt.event.MouseEvent;
1414
import java.awt.event.MouseMotionAdapter;
15-
import java.util.List;
1615
import java.util.Set;
1716
import java.util.Vector;
1817
import java.util.function.Consumer;
@@ -22,6 +21,9 @@
2221
import javax.swing.JPopupMenu;
2322
import javax.swing.JScrollPane;
2423
import javax.swing.ListSelectionModel;
24+
import javax.swing.SwingUtilities;
25+
import javax.swing.event.PopupMenuEvent;
26+
import javax.swing.event.PopupMenuListener;
2527
import javax.swing.text.BadLocationException;
2628
import javax.swing.text.JTextComponent;
2729

@@ -42,7 +44,7 @@ public class AutocompletePopup extends JPopupMenu {
4244
/**
4345
* @param parent text component where completion will be performed
4446
* @param position position to perform completion at
45-
* @param onCompletion
47+
* @param onCompletion to pass the final selected completion string to
4648
*/
4749
public AutocompletePopup(
4850
@NotNull JTextComponent parent,
@@ -58,7 +60,7 @@ public AutocompletePopup(
5860
suggestionList.setVisibleRowCount(maxVisibleRows);
5961

6062
// single-click to accept selection
61-
suggestionList.addMouseListener(
63+
addMouseListener(
6264
new MouseAdapter() {
6365
@Override
6466
public void mouseClicked(MouseEvent e) {
@@ -67,7 +69,7 @@ public void mouseClicked(MouseEvent e) {
6769
});
6870

6971
// highlight item hovered over with mouse
70-
suggestionList.addMouseMotionListener(
72+
addMouseMotionListener(
7173
new MouseMotionAdapter() {
7274
@Override
7375
public void mouseMoved(MouseEvent e) {
@@ -78,7 +80,7 @@ public void mouseMoved(MouseEvent e) {
7880
}
7981
});
8082

81-
suggestionList.addKeyListener(
83+
addKeyListener(
8284
new KeyAdapter() {
8385
@Override
8486
public void keyPressed(KeyEvent e) {
@@ -92,6 +94,22 @@ public void keyTyped(KeyEvent e) {
9294
}
9395
});
9496

97+
// Ensure the suggestion list gains focus
98+
// Without this, on Windows the popup shows but the keyboard becomes unresponsive
99+
addPopupMenuListener(
100+
new PopupMenuListener() {
101+
@Override
102+
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
103+
SwingUtilities.invokeLater(() -> requestFocusInWindow());
104+
}
105+
106+
@Override
107+
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
108+
109+
@Override
110+
public void popupMenuCanceled(PopupMenuEvent e) {}
111+
});
112+
95113
// Calculate the preferred height based on the number of items
96114
int rowHeight = suggestionList.getFixedCellHeight();
97115
if (rowHeight == 0) {
@@ -147,12 +165,14 @@ private void handleKeyPressed(
147165
return;
148166
}
149167
// Close the popup if a meta key (Ctrl, Alt, Cmd) is pressed with another key, as this is likely
150-
// the invocation of some other shortcut such as undo/redo, and we would need more logic to handle
151-
// that gracefully
152-
if ((e.getModifiersEx() & (KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK)) != 0
153-
&& e.getKeyCode() != KeyEvent.VK_CONTROL
154-
&& e.getKeyCode() != KeyEvent.VK_ALT
155-
&& e.getKeyCode() != KeyEvent.VK_META) {
168+
// the invocation of some other shortcut such as undo/redo, and we would need more logic to
169+
// handle that gracefully
170+
if ((e.getModifiersEx()
171+
& (KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK))
172+
!= 0
173+
&& e.getKeyCode() != KeyEvent.VK_CONTROL
174+
&& e.getKeyCode() != KeyEvent.VK_ALT
175+
&& e.getKeyCode() != KeyEvent.VK_META) {
156176
setVisible(false);
157177
parent.dispatchEvent(e);
158178
return;

0 commit comments

Comments
 (0)