@ -8,47 +8,51 @@ pub fn cursor_grab(
mut mouse_button_input : ResMut < ButtonInput < MouseButton > > ,
key_input : Res < ButtonInput < KeyCode > > ,
window : Single < ( & mut Window , & mut CursorOptions ) > ,
crosshair : Single < & mut Visibility , With < Crosshair > > ,
mut request_center_cursor : Local < bool > ,
) {
let ( mut window , mut cursor ) = window . into_inner ( ) ;
let mut crosshair_visibility = crosshair . into_inner ( ) ;
let is_grabbed = cursor . grab_mode = = CursorGrabMode ::Locked ;
let is_grabbed = cursor . grab_mode ! = CursorGrabMode ::None ;
let request_grab = mouse_button_input . any_just_pressed ( [ MouseButton ::Left , MouseButton ::Right ] ) ;
let request_ungrab = ! window . focused | | key_input . just_pressed ( KeyCode ::Escape ) ;
if ! is_grabbed & & request_grab & & ! request_ungrab {
* crosshair_visibility = Visibility ::Inherited ;
cursor . grab_mode = CursorGrabMode ::Locked ;
cursor . visible = false ;
// HACK: It appears setting the cursor position in the same frame we're
// locking it is not possible, so we're delaying it by a frame.
* request_center_cursor = true ;
// To prevent other systems (such as `place_break_blocks`)
// from seeing the mouse button inputs, clear the state here.
mouse_button_input . clear ( ) ;
}
if is_grabbed & & * request_center_cursor {
// Set the cursor position to the middle of the window,
// so when it is ungrabbed again it'll reappear there.
if is_grabbed & & request_ungrab & & ! request_grab {
cursor . grab_mode = CursorGrabMode ::None ;
}
if is_grabbed & & ! request_ungrab {
// Set the cursor position to the center of the window, so that when
// it is ungrabbed, it will reappear there. Because `is_grabbed` is
// not updated on grab, this block is delayed by one frame.
//
// On Wayland, since the cursor is locked into place, this only needs
// to be done once. Unfortunately, for some reason this doesn't work
// in the same frame as setting `grab_mode`, and would log an error.
//
// On X11, the cursor can't be locked into place, only confined to the
// window bounds, so we repeatedly move the cursor back to the center
// while it's grabbed.
//
// On the web, the cursor can be locked, but setting its position is
// not supported at all, so this would instead log a bunch of errors.
let center = window . resolution . size ( ) / 2. ;
#[ cfg(not(target_arch = " wasm32 " )) ] // skip on web
window . set_cursor_position ( Some ( center ) ) ;
* request_center_cursor = false ; // Only do this once.
}
if is_grabbed & & request_ungrab & & ! request_grab {
* crosshair_visibility = Visibility ::Hidden ;
cursor . grab_mode = CursorGrabMode ::None ;
cursor . visible = true ;
}
// Keep cursor visbility in sync with `grab_mode`.
cursor . visible = cursor . grab_mode = = CursorGrabMode ::None ;
}
pub fn is_cursor_grabbed ( cursor : Single < & CursorOptions > ) -> bool {
cursor . grab_mode = = CursorGrabMode ::Locked
cursor . grab_mode ! = CursorGrabMode ::None
}
#[ derive(Component, Debug) ]
@ -196,3 +200,14 @@ pub fn setup_crosshair(mut commands: Commands, asset_server: Res<AssetServer>) {
) ] ,
) ) ;
}
pub fn update_crosshair_visibility (
cursor : Single < & CursorOptions , Changed < CursorOptions > > ,
crosshair : Single < & mut Visibility , With < Crosshair > > ,
) {
let is_grabbed = cursor . grab_mode ! = CursorGrabMode ::None ;
let mut crosshair_visibility = crosshair . into_inner ( ) ;
* crosshair_visibility = ( ! is_grabbed | | cursor . visible )
. then_some ( Visibility ::Hidden )
. unwrap_or_default ( ) ;
}