diff --git a/HMCL/src/main/java/com/jfoenix/skins/JFXRadioButtonSkin.java b/HMCL/src/main/java/com/jfoenix/skins/JFXRadioButtonSkin.java index 229b434fa..8e7a1f73e 100644 --- a/HMCL/src/main/java/com/jfoenix/skins/JFXRadioButtonSkin.java +++ b/HMCL/src/main/java/com/jfoenix/skins/JFXRadioButtonSkin.java @@ -12,6 +12,7 @@ import javafx.animation.Interpolator; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; +import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.VPos; @@ -23,6 +24,7 @@ import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.text.Text; import javafx.util.Duration; +import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.animation.AnimationUtils; public class JFXRadioButtonSkin extends RadioButtonSkin { @@ -58,7 +60,12 @@ public class JFXRadioButtonSkin extends RadioButtonSkin { AnchorPane.setRightAnchor(this.rippler, this.labelOffset); this.updateChildren(); - control.focusedProperty().addListener((o, oldVal, newVal) -> { + ReadOnlyBooleanProperty focusVisibleProperty = FXUtils.focusVisibleProperty(control); + if (focusVisibleProperty == null) { + focusVisibleProperty = control.focusedProperty(); + } + + focusVisibleProperty.addListener((o, oldVal, newVal) -> { if (newVal) { if (!this.getSkinnable().isPressed()) { this.rippler.showOverlay(); @@ -66,7 +73,6 @@ public class JFXRadioButtonSkin extends RadioButtonSkin { } else { this.rippler.hideOverlay(); } - }); control.pressedProperty().addListener((o, oldVal, newVal) -> this.rippler.hideOverlay()); this.registerChangeListener(control.selectedColorProperty(), ignored -> updateColors()); 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 84e667ce9..c5c338204 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -137,6 +137,7 @@ public final class FXUtils { public static final @Nullable ReadOnlyObjectProperty ACCENT_COLOR; public static final @Nullable MethodHandle TEXT_TRUNCATED_PROPERTY; + public static final @Nullable MethodHandle FOCUS_VISIBLE_PROPERTY; static { String jfxVersion = System.getProperty("javafx.version"); @@ -203,6 +204,20 @@ public final class FXUtils { } } TEXT_TRUNCATED_PROPERTY = textTruncatedProperty; + + MethodHandle focusVisibleProperty = null; + if (JAVAFX_MAJOR_VERSION >= 19) { + try { + focusVisibleProperty = MethodHandles.publicLookup().findVirtual( + Node.class, + "focusVisibleProperty", + MethodType.methodType(ReadOnlyBooleanProperty.class) + ); + } catch (Throwable e) { + LOG.warning("Failed to lookup focusVisibleProperty", e); + } + } + FOCUS_VISIBLE_PROPERTY = focusVisibleProperty; } public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace"; @@ -423,6 +438,20 @@ public final class FXUtils { } } + public static @Nullable ReadOnlyBooleanProperty focusVisibleProperty(Node node) { + if (FOCUS_VISIBLE_PROPERTY != null) { + try { + return (ReadOnlyBooleanProperty) FOCUS_VISIBLE_PROPERTY.invokeExact(node); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } else { + return null; + } + } + private static final Duration TOOLTIP_FAST_SHOW_DELAY = Duration.millis(50); private static final Duration TOOLTIP_SLOW_SHOW_DELAY = Duration.millis(500); private static final Duration TOOLTIP_SHOW_DURATION = Duration.millis(5000);