use bevy_ecs::prelude::Entity;
use windows::Win32::Foundation::POINT;
use windows::Win32::Graphics::Gdi::ClientToScreen;
use windows::Win32::UI::Input::KeyboardAndMouse::VK_ESCAPE;
use windows::Win32::UI::WindowsAndMessaging::{
WA_INACTIVE, WM_ACTIVATE, WM_CANCELMODE, WM_CAPTURECHANGED, WM_KEYDOWN, WM_LBUTTONUP,
};
use crate::ecs::drag::{
DragClose, cancel_dragging, cancel_dragging_on_capture_lost, end_dragging_on_release,
};
use crate::ecs::pointer::PhysicalPoint;
use crate::ecs::world::tick_wake;
use crate::executor::util::WindowMessage;
pub(crate) fn handle_message_while_world_busy(window_entity: Entity, msg: &WindowMessage) -> bool {
let (kind, close) = match msg.msg {
WM_KEYDOWN if msg.wparam.0 == VK_ESCAPE.0 as usize => {
("WM_KEYDOWN(ESC)", cancel_dragging())
}
WM_CANCELMODE => ("WM_CANCELMODE", cancel_dragging()),
WM_ACTIVATE if (msg.wparam.0 & 0xFFFF) as u32 == WA_INACTIVE => {
("WM_ACTIVATE(WA_INACTIVE)", cancel_dragging())
}
WM_CAPTURECHANGED => ("WM_CAPTURECHANGED", cancel_dragging_on_capture_lost()),
WM_LBUTTONUP => (
"WM_LBUTTONUP",
end_dragging_on_release(msg.hwnd, release_screen_pos(window_entity, msg)),
),
_ => return false,
};
tick_wake::mark(tick_wake::wake_bits_for_message(msg.msg));
let window = format!("{window_entity:?}");
match close {
DragClose::Closed { entity, .. } => {
let action = if msg.msg == WM_LBUTTONUP {
"ended"
} else {
"cancelled"
};
tracing::warn!(
event = "drag_reentry_handled",
msg = kind,
entity = format!("{entity:?}").as_str(),
window = window.as_str(),
action,
"[drag] World を借りられない間のドラッグの終わりを扱った"
);
}
DragClose::OtherWindow | DragClose::NotActive => {
tracing::debug!(
event = "drag_reentry_handled",
msg = kind,
entity = "",
window = window.as_str(),
action = "none",
"[drag] World を借りられない間のメッセージ(ドラッグの扱いなし)"
);
}
}
true
}
fn release_screen_pos(window_entity: Entity, msg: &WindowMessage) -> Option<PhysicalPoint> {
let mut point = POINT {
x: (msg.lparam.0 & 0xFFFF) as i16 as i32,
y: ((msg.lparam.0 >> 16) & 0xFFFF) as i16 as i32,
};
if unsafe { ClientToScreen(msg.hwnd, &mut point) }.as_bool() {
return Some(PhysicalPoint::new(point.x, point.y));
}
tracing::warn!(
event = "drag_reentry_pos_unreadable",
window = ?window_entity,
hwnd = format!("0x{:X}", msg.hwnd.0 as usize),
"[drag] 離した位置を画面の座標へ直せない。最後の画面の座標で終える"
);
None
}
#[cfg(test)]
#[path = "reentry_tests.rs"]
mod tests;