Merge pull request #11255 from AlfaRojo/fix/screen-over-playing-releases-keys

A book, sign editor or prompt over the world releases the held buttons
This commit is contained in:
rdbt authored and GitHub committed 2026-11-06 21:16:17 +00:00
commit a3c540e8c0
3 files changed
+29 -12

No files matched your search

+22 -10
View File
@@ -8312,7 +8312,7 @@ impl Game<'_> {
gameplay_has_keyboard(
self.screen,
self.title.is_some(),
self.dialog_open(),
self.screen_over_playing(),
),
action,
) {
@@ -8357,8 +8357,11 @@ impl Game<'_> {
(_, false) => KeyAction::Press,
(_, true) => KeyAction::Repeat,
};
let screen_open =
!gameplay_has_keyboard(self.screen, self.title.is_some(), self.dialog_open());
let screen_open = !gameplay_has_keyboard(
self.screen,
self.title.is_some(),
self.screen_over_playing(),
);
self.toggles.key(slot, action, screen_open, option);
self.sync_toggle(slot);
if !pressed {
@@ -8386,7 +8389,11 @@ impl Game<'_> {
fn track_toggle_screens(&mut self) {
let dialog = self.dialog_open();
drop_held_behind_dialog(dialog, &mut self.keys, &mut self.left, &mut self.right);
let playing = gameplay_has_keyboard(self.screen, self.title.is_some(), dialog);
let playing = gameplay_has_keyboard(
self.screen,
self.title.is_some(),
self.screen_over_playing(),
);
if playing == self.was_playing {
return;
}
@@ -22896,10 +22903,13 @@ fn keyboard_button(playing: bool, action: KeyAction) -> Option<bool> {
playing.then_some(action != KeyAction::Release)
}
/// Gameplay owns the keyboard: `Screen::Playing`, no title, no server dialog.
/// Vanilla's `DialogScreen` is a screen, so `KeyMapping.releaseAll` runs.
fn gameplay_has_keyboard(screen: Screen, title: bool, dialog: bool) -> bool {
screen == Screen::Playing && !title && !dialog
/// Gameplay owns the keyboard: `Screen::Playing`, no title, and nothing open
/// over the world (`screen_over_playing`: a server dialog, a book or lectern,
/// a sign editor, a prompt). Each is a `Screen` in vanilla, so `Gui.setScreen`
/// runs `KeyMapping.releaseAll` and `Minecraft.tick` skips `handleKeybinds`
/// while it is up: a mouse button held into it is let go of (#9729).
fn gameplay_has_keyboard(screen: Screen, title: bool, screen_over: bool) -> bool {
screen == Screen::Playing && !title && !screen_over
}
/// A dialog drops held keys and mouse buttons it does not see (#4974).
@@ -23636,8 +23646,10 @@ mod tests {
}
}
/// A server dialog is a screen: held keys and the use button are released
/// (`KeyMapping.releaseAll`), and toggled sneak comes back when it closes (#4974).
/// A server dialog, a book, a sign editor or a prompt over the world is a
/// screen: held keys and the mouse buttons are released
/// (`KeyMapping.releaseAll`), and toggled sneak comes back when it closes
/// (#4974, #9729).
#[test]
fn a_dialog_releases_held_keys_like_a_screen() {
assert!(gameplay_has_keyboard(Screen::Playing, false, false));
+6 -1
View File
@@ -9046,10 +9046,15 @@ impl Game<'_> {
};
let mut input = std::mem::take(&mut r.input);
let stop = std::mem::take(&mut r.stop_mining);
// Minecraft.tick runs handleKeybinds only while `gui.screen() == null`: a
// book, a sign editor, a dialog or a prompt over the world (each a
// `Screen` in vanilla) stops the attack and use mappings from acting,
// and `KeyMapping.releaseAll` let go of the buttons when it opened
// (`track_toggle_screens`), so a dig held into a book ends (#9729).
let ready = r.loaded_sent
&& self.screen == Screen::Playing
&& self.sleeping.is_none()
&& !self.dialog_open();
&& !self.screen_over_playing();
// MultiPlayerGameMode.tick, first in Minecraft.tick, screen or not: the slot
// chosen since the last tick (the wheel, the last tick's number keys, the
// server's SetHeldSlot) goes out before anything else of this tick.
+1 -1
View File
@@ -47,7 +47,7 @@ struct Settings { keys: Bindings }
struct Game { keys: HashSet<i32>, settings: Settings, screen: bool, title: Option<()>, modifiers: u32,
open: bool, cancel: bool, calls: Cell<usize>, handled: usize, released: Vec<(bool, i32)> }
impl Game {
fn dialog_open(&self) -> bool { false }
fn screen_over_playing(&self) -> bool { false }
fn screen_view_now(&self) -> Option<&'static str> { self.open.then_some("options") }
fn native_screen_key_released_pre(&self, screen: &&str, name: &str, modifiers: u32, canceled: &mut bool) {
assert_eq!((*screen, name, modifiers), ("options", "key.keyboard.a", 5));