diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index 7759337bb..20efb21eb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -27,6 +27,9 @@ import javafx.beans.WeakInvalidationListener; import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; import javafx.beans.value.*; +import javafx.event.Event; +import javafx.event.EventDispatcher; +import javafx.event.EventType; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Cursor; @@ -86,6 +89,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -234,6 +238,21 @@ public final class FXUtils { }); } + @SuppressWarnings("unchecked") + public static void ignoreEvent(Node node, EventType type, Predicate filter) { + EventDispatcher oldDispatcher = node.getEventDispatcher(); + node.setEventDispatcher((event, tail) -> { + EventType t = event.getEventType(); + while (t != null && t != type) + t = t.getSuperType(); + if (t == type && filter.test((T) event)) { + return tail.dispatchEvent(event); + } else { + return oldDispatcher.dispatchEvent(event, tail); + } + }); + } + public static void setupCellValueFactory(JFXTreeTableColumn column, Function> mapper) { column.setCellValueFactory(param -> { if (column.validateValue(param)) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index 8a94ab970..754ad121c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -29,6 +29,8 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.ListCell; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.*; import javafx.util.Duration; import org.jackhuang.hmcl.download.DownloadProvider; @@ -66,6 +68,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.wrap; import static org.jackhuang.hmcl.util.logging.Logger.LOG; @@ -150,6 +153,9 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres list.getStyleClass().add("jfx-list-view-float"); VBox.setVgrow(list, Priority.ALWAYS); + // ListViewBehavior would consume ESC pressed event, preventing us from handling it, so we ignore it here + ignoreEvent(list, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE); + centrePane.getContent().setAll(checkPane, list); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java index 4baa9f316..dc6241f23 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java @@ -27,6 +27,8 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.SelectionMode; import javafx.scene.control.SkinBase; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Region; @@ -38,6 +40,7 @@ import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.util.StringUtils; +import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -110,6 +113,9 @@ class DatapackListPageSkin extends SkinBase { listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); Bindings.bindContent(listView.getItems(), skinnable.getItems()); + // ListViewBehavior would consume ESC pressed event, preventing us from handling it, so we ignore it here + ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE); + center.setContent(listView); root.setCenter(center); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java index dffe893a3..e1fe3ae8f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadListPage.java @@ -36,6 +36,8 @@ import javafx.scene.control.Label; import javafx.scene.control.Skin; import javafx.scene.control.SkinBase; import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.*; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.mod.RemoteMod; @@ -64,6 +66,7 @@ import java.util.Locale; import java.util.Optional; import java.util.stream.Collectors; +import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.FXUtils.stringConverter; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor; @@ -493,6 +496,9 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP RemoteMod selectedItem = listView.getSelectionModel().getSelectedItem(); Controllers.navigate(new DownloadPage(getSkinnable(), selectedItem, getSkinnable().getProfileVersion(), getSkinnable().callback)); }); + + // ListViewBehavior would consume ESC pressed event, preventing us from handling it, so we ignore it here + ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE); listView.setCellFactory(x -> new FloatListCell(listView) { TwoLineListItem content = new TwoLineListItem(); ImageView imageView = new ImageView(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 61674d3ed..66d3d6e1d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -31,6 +31,8 @@ import javafx.scene.control.SelectionMode; import javafx.scene.control.SkinBase; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; @@ -70,6 +72,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton2; import static org.jackhuang.hmcl.util.Lang.mapOf; @@ -170,6 +173,16 @@ class ModListPageSkin extends SkinBase { changeToolbar(toolbarSelecting); }); root.getContent().add(toolbarPane); + + // Clear selection when pressing ESC + root.addEventHandler(KeyEvent.KEY_PRESSED, e -> { + if (e.getCode() == KeyCode.ESCAPE) { + if (listView.getSelectionModel().getSelectedItem() != null) { + listView.getSelectionModel().clearSelection(); + e.consume(); + } + } + }); } { @@ -196,6 +209,10 @@ class ModListPageSkin extends SkinBase { } }); + // ListViewBehavior would consume ESC pressed event, preventing us from handling it + // So we ignore it here + ignoreEvent(listView, KeyEvent.KEY_PRESSED, e -> e.getCode() == KeyCode.ESCAPE); + center.setContent(listView); root.getContent().add(center); }