lua: start exposing events
This commit is contained in:
parent
9e9478966b
commit
8e56ee1f0f
File diff suppressed because it is too large
Load Diff
|
@ -4,3 +4,5 @@ pub use plugin::*;
|
||||||
|
|
||||||
mod window;
|
mod window;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
|
pub use winit::dpi as dpi;
|
|
@ -13,6 +13,9 @@ use winit::{
|
||||||
window::{Window, WindowAttributes, WindowId},
|
window::{Window, WindowAttributes, WindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use winit::event::{DeviceId, DeviceEvent, MouseScrollDelta, ElementState};
|
||||||
|
pub use winit::keyboard::PhysicalKey;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
game::{App, WindowState},
|
game::{App, WindowState},
|
||||||
plugin::Plugin,
|
plugin::Plugin,
|
||||||
|
@ -26,9 +29,9 @@ use super::WindowOptions;
|
||||||
#[derive(Debug, Clone, Reflect)]
|
#[derive(Debug, Clone, Reflect)]
|
||||||
pub struct DeviceEventPair {
|
pub struct DeviceEventPair {
|
||||||
#[reflect(skip)]
|
#[reflect(skip)]
|
||||||
pub device_src: winit::event::DeviceId,
|
pub device_src: DeviceId,
|
||||||
#[reflect(skip)]
|
#[reflect(skip)]
|
||||||
pub event: winit::event::DeviceEvent,
|
pub event: DeviceEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WinitPlugin {
|
pub struct WinitPlugin {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::{field::{Field, FieldType}, FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNA
|
||||||
enum SkipType {
|
enum SkipType {
|
||||||
/// Skips implementing
|
/// Skips implementing
|
||||||
LuaReflect,
|
LuaReflect,
|
||||||
|
LuaWrapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl syn::parse::Parse for SkipType {
|
impl syn::parse::Parse for SkipType {
|
||||||
|
@ -19,6 +20,7 @@ impl syn::parse::Parse for SkipType {
|
||||||
|
|
||||||
match name_str.as_str() {
|
match name_str.as_str() {
|
||||||
"lua_reflect" => Ok(Self::LuaReflect),
|
"lua_reflect" => Ok(Self::LuaReflect),
|
||||||
|
"lua_wrapper" => Ok(Self::LuaWrapper),
|
||||||
_ => Err(syn::Error::new_spanned(name, "unknown skip type")),
|
_ => Err(syn::Error::new_spanned(name, "unknown skip type")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,6 +485,24 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let lua_wrapper = if input.skips.contains(&SkipType::LuaWrapper) {
|
||||||
|
quote!()
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
impl lyra_scripting::lua::LuaWrapper for #wrapper_typename {
|
||||||
|
type Wrap = #path;
|
||||||
|
|
||||||
|
fn wrapped_type_id() -> std::any::TypeId {
|
||||||
|
std::any::TypeId::of::<#path>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_wrapped(self) -> Self::Wrap {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for field in input.auto_fields.iter() {
|
for field in input.auto_fields.iter() {
|
||||||
if field.field_ty.is_unknown() && !field.skip_setter {
|
if field.field_ty.is_unknown() && !field.skip_setter {
|
||||||
return syn::Error::new(
|
return syn::Error::new(
|
||||||
|
@ -583,6 +603,7 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||||
impl mlua::UserData for #wrapper_typename {
|
impl mlua::UserData for #wrapper_typename {
|
||||||
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
|
||||||
use mlua::IntoLua;
|
use mlua::IntoLua;
|
||||||
|
use mlua::FromLua;
|
||||||
|
|
||||||
#(#fields)*
|
#(#fields)*
|
||||||
|
|
||||||
|
@ -591,6 +612,7 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||||
|
|
||||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||||
use mlua::IntoLua;
|
use mlua::IntoLua;
|
||||||
|
use mlua::FromLua;
|
||||||
|
|
||||||
#lua_reflects
|
#lua_reflects
|
||||||
|
|
||||||
|
@ -600,16 +622,6 @@ pub fn wrap_lua_struct_impl(input: proc_macro::TokenStream) -> proc_macro::Token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl lyra_scripting::lua::LuaWrapper for #wrapper_typename {
|
#lua_wrapper
|
||||||
type Wrap = #path;
|
|
||||||
|
|
||||||
fn wrapped_type_id() -> std::any::TypeId {
|
|
||||||
std::any::TypeId::of::<#path>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_wrapped(self) -> Self::Wrap {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,11 @@ pub trait LuaWrapper {
|
||||||
type Wrap: Reflect + 'static;
|
type Wrap: Reflect + 'static;
|
||||||
|
|
||||||
/// The type id of the wrapped type.
|
/// The type id of the wrapped type.
|
||||||
fn wrapped_type_id() -> TypeId;
|
#[inline(always)]
|
||||||
|
fn wrapped_type_id() -> TypeId {
|
||||||
|
TypeId::of::<Self::Wrap>()
|
||||||
|
}
|
||||||
|
|
||||||
fn into_wrapped(self) -> Self::Wrap;
|
fn into_wrapped(self) -> Self::Wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,318 @@
|
||||||
|
use crate::lua::LuaWrapper;
|
||||||
|
use lyra_game::{
|
||||||
|
input::{KeyCode, NativeKeyCode},
|
||||||
|
math::Vec2,
|
||||||
|
winit::{
|
||||||
|
dpi::PhysicalPosition, DeviceEvent, DeviceEventPair, DeviceId, MouseScrollDelta,
|
||||||
|
PhysicalKey,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use lyra_scripting_derive::wrap_lua_struct;
|
||||||
|
|
||||||
|
use crate::lyra_engine;
|
||||||
|
|
||||||
|
use super::LuaVec2;
|
||||||
|
|
||||||
|
wrap_lua_struct!(DeviceId, skip(lua_reflect, lua_wrapper));
|
||||||
|
|
||||||
|
/// Wraps [`DeviceEvent`] and implements [`IntoLua`]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaDeviceEventRaw(pub(crate) DeviceEvent);
|
||||||
|
|
||||||
|
impl std::ops::Deref for LuaDeviceEventRaw {
|
||||||
|
type Target = DeviceEvent;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for LuaDeviceEventRaw {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaDeviceEventRaw {
|
||||||
|
fn from_lua(v: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let ty = v.type_name();
|
||||||
|
let table = v.as_table().ok_or(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some("expected Lua Table".into()),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let type_str: String = table.get("type")?;
|
||||||
|
let type_str = type_str.as_str();
|
||||||
|
|
||||||
|
let ret = match type_str {
|
||||||
|
"added" => Self(DeviceEvent::Added),
|
||||||
|
"removed" => Self(DeviceEvent::Removed),
|
||||||
|
"mouse_motion" => {
|
||||||
|
let delta: LuaVec2 = table.get("delta")?;
|
||||||
|
Self(DeviceEvent::MouseMotion {
|
||||||
|
delta: (delta.x as _, delta.y as _),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
"mouse_wheel" => {
|
||||||
|
let delta = if table.contains_key("line_delta")? {
|
||||||
|
let ld: LuaVec2 = table.get("line_delta")?;
|
||||||
|
MouseScrollDelta::LineDelta(ld.x, ld.y)
|
||||||
|
} else if table.contains_key("pixel_delta")? {
|
||||||
|
let pd: LuaVec2 = table.get("pixel_delta")?;
|
||||||
|
let pos = PhysicalPosition::new(pd.x as f64, pd.y as f64);
|
||||||
|
MouseScrollDelta::PixelDelta(pos)
|
||||||
|
} else {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(
|
||||||
|
"could not find line_delta or pixel_delta in 'mouse_wheel' \
|
||||||
|
device event"
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(DeviceEvent::MouseWheel { delta })
|
||||||
|
}
|
||||||
|
"motion" => {
|
||||||
|
let axis: u32 = table.get("axis")?;
|
||||||
|
let value: f64 = table.get("value")?;
|
||||||
|
Self(DeviceEvent::Motion { axis, value })
|
||||||
|
}
|
||||||
|
"button" => {
|
||||||
|
let button: u32 = table.get("button")?;
|
||||||
|
|
||||||
|
let state_str: String = table.get("state")?;
|
||||||
|
let state_str = state_str.as_str();
|
||||||
|
let state = match state_str {
|
||||||
|
"pressed" => lyra_game::winit::ElementState::Pressed,
|
||||||
|
"released" => lyra_game::winit::ElementState::Released,
|
||||||
|
_ => {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(format!("unknown button state: '{}'", state_str)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(DeviceEvent::Button { button, state })
|
||||||
|
}
|
||||||
|
"key" => {
|
||||||
|
let state_str: String = table.get("state")?;
|
||||||
|
let state_str = state_str.as_str();
|
||||||
|
let state = match state_str {
|
||||||
|
"pressed" => lyra_game::winit::ElementState::Pressed,
|
||||||
|
"released" => lyra_game::winit::ElementState::Released,
|
||||||
|
_ => {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(format!("unknown key state: '{}'", state_str)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if table.contains_key("code")? {
|
||||||
|
let code_str: String = table.get("code")?;
|
||||||
|
let code = KeyCode::from_str(&code_str);
|
||||||
|
if code.is_none() {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(format!("unknown key code: '{}'", code_str)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let phy = PhysicalKey::Code(code);
|
||||||
|
Self(DeviceEvent::Key(RawKeyEvent {
|
||||||
|
physical_key: phy,
|
||||||
|
state,
|
||||||
|
}))
|
||||||
|
} else if table.contains_key("native")? {
|
||||||
|
let native_str: String = table.get("native")?;
|
||||||
|
let native_str = native_str.as_str();
|
||||||
|
let native_code: u32 = table.get("native_code")?;
|
||||||
|
|
||||||
|
let native_code = match native_str {
|
||||||
|
"unknown" => NativeKeyCode::Unidentified,
|
||||||
|
"android" => NativeKeyCode::Android(native_code),
|
||||||
|
"macos" => NativeKeyCode::MacOS(native_code as u16),
|
||||||
|
"windows" => NativeKeyCode::Windows(native_code),
|
||||||
|
"xkb" => NativeKeyCode::Xkb(native_code),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(DeviceEvent::Key(RawKeyEvent {
|
||||||
|
physical_key: PhysicalKey::Unidentified(native_code),
|
||||||
|
state,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(
|
||||||
|
"malformed Table for LuaDeviceEventRaw, missing key \
|
||||||
|
code"
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEventRaw".into(),
|
||||||
|
message: Some(format!("unknown device event type '{}'", type_str)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::IntoLua for LuaDeviceEventRaw {
|
||||||
|
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
|
||||||
|
match self.0 {
|
||||||
|
DeviceEvent::Added => {
|
||||||
|
table.set("type", "added")?;
|
||||||
|
}
|
||||||
|
DeviceEvent::Removed => {
|
||||||
|
table.set("type", "removed")?;
|
||||||
|
}
|
||||||
|
DeviceEvent::MouseMotion { delta } => {
|
||||||
|
table.set("type", "mouse_motion")?;
|
||||||
|
table.set("delta", LuaVec2(Vec2::new(delta.0 as _, delta.1 as _)))?;
|
||||||
|
}
|
||||||
|
DeviceEvent::MouseWheel { delta } => {
|
||||||
|
table.set("type", "mouse_wheel")?;
|
||||||
|
|
||||||
|
match delta {
|
||||||
|
MouseScrollDelta::LineDelta(x, y) => {
|
||||||
|
let d = LuaVec2(Vec2::new(x, y));
|
||||||
|
table.set("line_delta", d)?;
|
||||||
|
}
|
||||||
|
MouseScrollDelta::PixelDelta(delta) => {
|
||||||
|
let d = delta.cast::<f32>();
|
||||||
|
let d = LuaVec2(Vec2::new(d.x, d.y));
|
||||||
|
table.set("pixel_delta", d)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeviceEvent::Motion { axis, value } => {
|
||||||
|
table.set("type", "motion")?;
|
||||||
|
table.set("axis", axis)?;
|
||||||
|
table.set("value", value)?;
|
||||||
|
}
|
||||||
|
DeviceEvent::Button { button, state } => {
|
||||||
|
table.set("type", "button")?;
|
||||||
|
table.set("button", button)?;
|
||||||
|
|
||||||
|
let state = match state {
|
||||||
|
lyra_game::winit::ElementState::Pressed => "pressed",
|
||||||
|
lyra_game::winit::ElementState::Released => "released",
|
||||||
|
};
|
||||||
|
table.set("state", state)?;
|
||||||
|
}
|
||||||
|
DeviceEvent::Key(raw_key_event) => {
|
||||||
|
table.set("type", "key")?;
|
||||||
|
|
||||||
|
let state = match raw_key_event.state {
|
||||||
|
lyra_game::winit::ElementState::Pressed => "pressed",
|
||||||
|
lyra_game::winit::ElementState::Released => "released",
|
||||||
|
};
|
||||||
|
table.set("state", state)?;
|
||||||
|
|
||||||
|
let e = KeyCode::from_raw_event(&raw_key_event);
|
||||||
|
let s = e.as_str();
|
||||||
|
|
||||||
|
if let Some(s) = s {
|
||||||
|
table.set("code", s)?;
|
||||||
|
} else if let Some(un) = e.get_unknown() {
|
||||||
|
match un {
|
||||||
|
lyra_game::input::NativeKeyCode::Unidentified => {
|
||||||
|
table.set("native", "unknown")?;
|
||||||
|
}
|
||||||
|
lyra_game::input::NativeKeyCode::Android(v) => {
|
||||||
|
table.set("native", "android")?;
|
||||||
|
table.set("native_code", *v)?;
|
||||||
|
}
|
||||||
|
lyra_game::input::NativeKeyCode::MacOS(v) => {
|
||||||
|
table.set("native", "macos")?;
|
||||||
|
table.set("native_code", *v)?;
|
||||||
|
}
|
||||||
|
lyra_game::input::NativeKeyCode::Windows(v) => {
|
||||||
|
table.set("native", "windows")?;
|
||||||
|
table.set("native_code", *v)?;
|
||||||
|
}
|
||||||
|
lyra_game::input::NativeKeyCode::Xkb(v) => {
|
||||||
|
table.set("native", "xkb")?;
|
||||||
|
table.set("native_code", *v)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.into_lua(lua)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaDeviceEvent(pub(crate) DeviceEventPair);
|
||||||
|
|
||||||
|
impl std::ops::Deref for LuaDeviceEvent {
|
||||||
|
type Target = DeviceEventPair;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for LuaDeviceEvent {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::FromLua for LuaDeviceEvent {
|
||||||
|
fn from_lua(v: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
let ty = v.type_name();
|
||||||
|
let table = v.as_table().ok_or(mlua::Error::FromLuaConversionError {
|
||||||
|
from: ty,
|
||||||
|
to: "LuaDeviceEvent".into(),
|
||||||
|
message: Some("expected Lua Table".into()),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let id: LuaDeviceId = table.get("device")?;
|
||||||
|
let ev: LuaDeviceEventRaw = table.get("event")?;
|
||||||
|
|
||||||
|
Ok(Self(DeviceEventPair {
|
||||||
|
device_src: id,
|
||||||
|
event: ev,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl mlua::IntoLua for LuaDeviceEvent {
|
||||||
|
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<mlua::Value> {
|
||||||
|
let table = lua.create_table()?;
|
||||||
|
table.set("device", LuaDeviceId(self.device_src))?;
|
||||||
|
table.set("event", LuaDeviceEventRaw(self.event.clone()))?;
|
||||||
|
|
||||||
|
table.into_lua(lua)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaWrapper for LuaDeviceEvent {
|
||||||
|
type Wrap = DeviceEventPair;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn into_wrapped(self) -> Self::Wrap {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,4 +17,7 @@ mod camera;
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
|
|
||||||
mod free_fly_camera;
|
mod free_fly_camera;
|
||||||
pub use free_fly_camera::*;
|
pub use free_fly_camera::*;
|
||||||
|
|
||||||
|
mod events;
|
||||||
|
pub use events::*;
|
Loading…
Reference in New Issue