61 lines
1.9 KiB
GDScript
61 lines
1.9 KiB
GDScript
class_name ScreenCursor
|
|
extends RefCounted
|
|
## Maps the global mouse position to a normalized -1..1 range
|
|
## relative to the window center, using screen edges as bounds.
|
|
## Handles multi-monitor and Wayland focus limitations.
|
|
|
|
## Max pixel distance from window center that maps to 1.0.
|
|
## Prevents over-sensitive tracking on ultra-wide setups.
|
|
const MAX_RANGE_PX: float = 2000.0
|
|
|
|
static var _last_valid: Vector2 = Vector2.ZERO
|
|
|
|
|
|
static func get_normalized_position() -> Vector2:
|
|
var ds := DisplayServer
|
|
var mouse := ds.mouse_get_position()
|
|
var win_pos := ds.window_get_position()
|
|
var win_size := ds.window_get_size()
|
|
|
|
var cx := win_pos.x + win_size.x / 2
|
|
var cy := win_pos.y + win_size.y / 2
|
|
|
|
var dx := float(mouse.x - cx)
|
|
var dy := float(mouse.y - cy)
|
|
|
|
# On Wayland, mouse position may freeze at (0,0) when unfocused
|
|
if mouse.x == 0 and mouse.y == 0:
|
|
return _last_valid
|
|
|
|
# Use screen the window is on for bounds
|
|
var screen_idx := ds.window_get_current_screen()
|
|
var screen_rect := ds.screen_get_usable_rect(screen_idx)
|
|
var screen_pos := screen_rect.position
|
|
var screen_size := screen_rect.size
|
|
|
|
# Distance from window center to each screen edge
|
|
var dist_left := maxf(float(cx - screen_pos.x), 1.0)
|
|
var dist_right := maxf(float(screen_pos.x + screen_size.x - cx), 1.0)
|
|
var dist_up := maxf(float(cy - screen_pos.y), 1.0)
|
|
var dist_down := maxf(float(screen_pos.y + screen_size.y - cy), 1.0)
|
|
|
|
# Cap range so ultra-wide screens don't make gaze too sensitive
|
|
dist_left = minf(dist_left, MAX_RANGE_PX)
|
|
dist_right = minf(dist_right, MAX_RANGE_PX)
|
|
dist_up = minf(dist_up, MAX_RANGE_PX)
|
|
dist_down = minf(dist_down, MAX_RANGE_PX)
|
|
|
|
var nx: float = 0.0
|
|
if dx > 0.0:
|
|
nx = clampf(dx / dist_right, 0.0, 1.0)
|
|
elif dx < 0.0:
|
|
nx = clampf(dx / dist_left, -1.0, 0.0)
|
|
|
|
var ny: float = 0.0
|
|
if dy > 0.0:
|
|
ny = -clampf(dy / dist_down, 0.0, 1.0)
|
|
elif dy < 0.0:
|
|
ny = -clampf(dy / dist_up, -1.0, 0.0)
|
|
|
|
_last_valid = Vector2(nx, ny)
|
|
return _last_valid
|