wip: most of the input types can be sent from rust -> beam.

This commit is contained in:
James Harton 2024-05-16 13:20:21 +12:00
parent fc46908151
commit 4451c2e887
Signed by: james
GPG key ID: 90E82DAA13F624F4
15 changed files with 658 additions and 104 deletions

1
.gitignore vendored
View file

@ -26,3 +26,4 @@ scenic_driver_renderling-*.tar
/tmp/
priv/__scenic
priv/native

View file

@ -1,11 +1,5 @@
defmodule Scenic.Driver.Renderling.Window.Config do
defstruct name: nil,
limit_ms: nil,
layer: nil,
opacity: nil,
debug: false,
debugger: "",
debug_fps: 0,
antialias: true,
position: nil,
window: nil,
@ -41,19 +35,14 @@ defmodule Scenic.Driver.Renderling.Window.Config do
@type t :: %__MODULE__{
name: atom | String.t(),
limit_ms: non_neg_integer(),
layer: integer,
opacity: integer,
debug: boolean,
debugger: String.t(),
debug_fps: integer,
antialias: boolean,
position: Position.t(),
window: Window.t(),
cursor: boolean,
key_map: module,
on_close: :restart | :stop_driver | :stop_viewport | :stop_system | :halt_system,
input_blacklist: [String.t()]
input_blacklist: [String.t()],
server_path: Path.t()
}
def init(opts) do

View file

@ -9,10 +9,6 @@ defmodule Scenic.Driver.Renderling.Window do
use Scenic.Driver
require Logger
@default_limit 29
@default_layer 0
@default_opacity 255
@position_schema [
scaled: [type: :boolean, default: false],
centered: [type: :boolean, default: false],
@ -26,12 +22,6 @@ defmodule Scenic.Driver.Renderling.Window do
@opts_schema [
name: [type: {:or, [:atom, :string]}],
limit_ms: [type: :non_neg_integer, default: @default_limit],
layer: [type: :integer, default: @default_layer],
opacity: [type: :integer, default: @default_opacity],
debug: [type: :boolean, default: false],
debugger: [type: :string, default: ""],
debug_fps: [type: :integer, default: 0],
antialias: [type: :boolean, default: true],
position: [type: :keyword_list, keys: @position_schema, default: []],
window: [type: :keyword_list, keys: @window_schema, default: []],

View file

@ -8,6 +8,7 @@
"Rect",
"Renderling",
"Rrect",
"Stdio"
"Stdio",
"winit"
]
}

View file

@ -634,6 +634,9 @@ name = "cursor-icon"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
dependencies = [
"serde",
]
[[package]]
name = "d3d12"
@ -716,6 +719,9 @@ name = "dpi"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
dependencies = [
"serde",
]
[[package]]
name = "either"
@ -3315,6 +3321,7 @@ dependencies = [
"redox_syscall 0.4.1",
"rustix",
"sctk-adwaita 0.9.0",
"serde",
"smithay-client-toolkit",
"smol_str",
"tracing",

View file

@ -17,7 +17,7 @@ renderling = "0.4.1"
rustler = {version = "0.32.1", features = ["serde", "nif_version_2_16"]}
serde = {version = "1", features = ["derive"]}
wgpu = "0.20.0"
winit = "0.30.0"
winit = {version = "0.30.0", features = ["serde"]}
[[bin]]
name = "renderling_window_server"

View file

@ -1,5 +1,5 @@
use crate::message;
use rustler::{NifStruct, NifTaggedEnum, NifTuple, NifUnitEnum, NifUntaggedEnum, Term};
use rustler::{NifStruct, NifTaggedEnum, NifTuple, NifUnitEnum};
/// Structures received from BEAM.
@ -40,12 +40,6 @@ pub enum OnCloseAction {
#[derive(NifStruct, Debug, Clone)]
#[module = "Scenic.Driver.Renderling.Window.Config"]
pub struct DriverConfig {
pub limit_ms: u32,
pub layer: u32,
pub opacity: u32,
pub debug: bool,
pub debugger: String,
pub debug_fps: u32,
pub antialias: bool,
pub position: WindowPosition,
pub window: WindowConfig,
@ -458,11 +452,339 @@ impl From<message::ViewPortEvent> for ViewPortEvent {
}
}
#[derive(NifUnitEnum, Debug, Clone)]
pub enum ElementState {
Pressed,
Released,
}
impl From<message::ElementState> for ElementState {
fn from(state: message::ElementState) -> Self {
match state {
message::ElementState::Pressed => ElementState::Pressed,
message::ElementState::Released => ElementState::Released,
}
}
}
#[derive(NifUnitEnum, Debug, Clone)]
pub enum Key {
KeySpace,
KeyApostrophe,
KeyComma,
KeyMinus,
KeyDot,
KeySlash,
Key0,
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
KeySemicolon,
KeyEqual,
KeyA,
KeyB,
KeyC,
KeyD,
KeyE,
KeyF,
KeyG,
KeyH,
KeyI,
KeyJ,
KeyK,
KeyL,
KeyM,
KeyN,
KeyO,
KeyP,
KeyQ,
KeyR,
KeyS,
KeyT,
KeyU,
KeyV,
KeyW,
KeyX,
KeyY,
KeyZ,
KeyLeftbrace,
KeyBlackslash,
KeyRightbrace,
KeyGrave,
KeyEsc,
KeyEnter,
KeyTab,
KeyBackspace,
KeyInsert,
KeyDelete,
KeyRight,
KeyLeft,
KeyDown,
KeyUp,
KeyPageup,
KeyPagedown,
KeyHome,
KeyEnd,
KeyCapslock,
KeyScrolllock,
KeyNumlock,
KeyScreen,
KeyPause,
KeyF1,
KeyF2,
KeyF3,
KeyF4,
KeyF5,
KeyF6,
KeyF7,
KeyF8,
KeyF9,
KeyF10,
KeyF11,
KeyF12,
KeyF13,
KeyF14,
KeyF15,
KeyF16,
KeyF17,
KeyF18,
KeyF19,
KeyF20,
KeyF21,
KeyF22,
KeyF23,
KeyF24,
KeyF25,
KeyKp0,
KeyKp1,
KeyKp2,
KeyKp3,
KeyKp4,
KeyKp5,
KeyKp6,
KeyKp7,
KeyKp8,
KeyKp9,
KeyKpdot,
KeyKpslash,
KeyKpasterisk,
KeyKpminus,
KeyKpplus,
KeyKpenter,
KeyKpequal,
KeyLeftshift,
KeyLeftctrl,
KeyLeftalt,
KeyLeftsuper,
KeyRightshift,
KeyRightctrl,
KeyRightalt,
KeyRightsuper,
KeyMenu,
// Added specifically because `From<_>` can't fail, so we can handle up in BEAM land.
KeyUnsupported,
// Added because I felt bad Scenic didn't know about them:
KeyPrintscreen,
KeyBrback,
KeyBrfavs,
KeyBrfwd,
KeyBrhome,
KeyBrrefresh,
KeyBrsearch,
KeyBrstop,
KeyEject,
KeyMedplay,
KeyMedsel,
KeyMedstop,
KeyMednext,
KeyMedprev,
KeyMedvolup,
KeyMedmute,
KeyMedvoldown,
}
impl From<winit::keyboard::KeyCode> for Key {
fn from(key: winit::keyboard::KeyCode) -> Self {
match key {
winit::keyboard::KeyCode::Backquote => Key::KeyGrave,
winit::keyboard::KeyCode::Backslash => Key::KeyBlackslash,
winit::keyboard::KeyCode::BracketLeft => Key::KeyLeftbrace,
winit::keyboard::KeyCode::BracketRight => Key::KeyRightbrace,
winit::keyboard::KeyCode::Comma => Key::KeyComma,
winit::keyboard::KeyCode::Digit0 => Key::Key0,
winit::keyboard::KeyCode::Digit1 => Key::Key1,
winit::keyboard::KeyCode::Digit2 => Key::Key2,
winit::keyboard::KeyCode::Digit3 => Key::Key3,
winit::keyboard::KeyCode::Digit4 => Key::Key4,
winit::keyboard::KeyCode::Digit5 => Key::Key5,
winit::keyboard::KeyCode::Digit6 => Key::Key6,
winit::keyboard::KeyCode::Digit7 => Key::Key7,
winit::keyboard::KeyCode::Digit8 => Key::Key8,
winit::keyboard::KeyCode::Digit9 => Key::Key9,
winit::keyboard::KeyCode::Equal => Key::KeyEqual,
winit::keyboard::KeyCode::IntlBackslash => Key::KeyBlackslash,
winit::keyboard::KeyCode::IntlRo => Key::KeyBlackslash,
winit::keyboard::KeyCode::KeyA => Key::KeyA,
winit::keyboard::KeyCode::KeyB => Key::KeyB,
winit::keyboard::KeyCode::KeyC => Key::KeyC,
winit::keyboard::KeyCode::KeyD => Key::KeyD,
winit::keyboard::KeyCode::KeyE => Key::KeyE,
winit::keyboard::KeyCode::KeyF => Key::KeyF,
winit::keyboard::KeyCode::KeyG => Key::KeyG,
winit::keyboard::KeyCode::KeyH => Key::KeyH,
winit::keyboard::KeyCode::KeyI => Key::KeyI,
winit::keyboard::KeyCode::KeyJ => Key::KeyJ,
winit::keyboard::KeyCode::KeyK => Key::KeyK,
winit::keyboard::KeyCode::KeyL => Key::KeyL,
winit::keyboard::KeyCode::KeyM => Key::KeyM,
winit::keyboard::KeyCode::KeyN => Key::KeyN,
winit::keyboard::KeyCode::KeyO => Key::KeyO,
winit::keyboard::KeyCode::KeyP => Key::KeyP,
winit::keyboard::KeyCode::KeyQ => Key::KeyQ,
winit::keyboard::KeyCode::KeyR => Key::KeyR,
winit::keyboard::KeyCode::KeyS => Key::KeyS,
winit::keyboard::KeyCode::KeyT => Key::KeyT,
winit::keyboard::KeyCode::KeyU => Key::KeyU,
winit::keyboard::KeyCode::KeyV => Key::KeyV,
winit::keyboard::KeyCode::KeyW => Key::KeyW,
winit::keyboard::KeyCode::KeyX => Key::KeyX,
winit::keyboard::KeyCode::KeyY => Key::KeyY,
winit::keyboard::KeyCode::KeyZ => Key::KeyZ,
winit::keyboard::KeyCode::Minus => Key::KeyMinus,
winit::keyboard::KeyCode::Period => Key::KeyDot,
winit::keyboard::KeyCode::Quote => Key::KeyApostrophe,
winit::keyboard::KeyCode::Semicolon => Key::KeySemicolon,
winit::keyboard::KeyCode::Slash => Key::KeySlash,
winit::keyboard::KeyCode::AltLeft => Key::KeyLeftalt,
winit::keyboard::KeyCode::AltRight => Key::KeyRightalt,
winit::keyboard::KeyCode::Backspace => Key::KeyBackspace,
winit::keyboard::KeyCode::CapsLock => Key::KeyCapslock,
winit::keyboard::KeyCode::ContextMenu => Key::KeyMenu,
winit::keyboard::KeyCode::ControlLeft => Key::KeyLeftctrl,
winit::keyboard::KeyCode::ControlRight => Key::KeyRightctrl,
winit::keyboard::KeyCode::Enter => Key::KeyEnter,
winit::keyboard::KeyCode::SuperLeft => Key::KeyLeftsuper,
winit::keyboard::KeyCode::SuperRight => Key::KeyRightsuper,
winit::keyboard::KeyCode::ShiftLeft => Key::KeyLeftshift,
winit::keyboard::KeyCode::ShiftRight => Key::KeyRightshift,
winit::keyboard::KeyCode::Space => Key::KeySpace,
winit::keyboard::KeyCode::Tab => Key::KeyTab,
winit::keyboard::KeyCode::Delete => Key::KeyDelete,
winit::keyboard::KeyCode::End => Key::KeyEnd,
winit::keyboard::KeyCode::Insert => Key::KeyInsert,
winit::keyboard::KeyCode::PageDown => Key::KeyPagedown,
winit::keyboard::KeyCode::PageUp => Key::KeyPageup,
winit::keyboard::KeyCode::ArrowDown => Key::KeyDown,
winit::keyboard::KeyCode::ArrowLeft => Key::KeyLeft,
winit::keyboard::KeyCode::ArrowRight => Key::KeyRight,
winit::keyboard::KeyCode::ArrowUp => Key::KeyUp,
winit::keyboard::KeyCode::NumLock => Key::KeyNumlock,
winit::keyboard::KeyCode::Numpad0 => Key::KeyKp0,
winit::keyboard::KeyCode::Numpad1 => Key::KeyKp1,
winit::keyboard::KeyCode::Numpad2 => Key::KeyKp2,
winit::keyboard::KeyCode::Numpad3 => Key::KeyKp3,
winit::keyboard::KeyCode::Numpad4 => Key::KeyKp4,
winit::keyboard::KeyCode::Numpad5 => Key::KeyKp5,
winit::keyboard::KeyCode::Numpad6 => Key::KeyKp6,
winit::keyboard::KeyCode::Numpad7 => Key::KeyKp7,
winit::keyboard::KeyCode::Numpad8 => Key::KeyKp8,
winit::keyboard::KeyCode::Numpad9 => Key::KeyKp9,
winit::keyboard::KeyCode::NumpadAdd => Key::KeyKpplus,
winit::keyboard::KeyCode::NumpadBackspace => Key::KeyBackspace,
winit::keyboard::KeyCode::NumpadComma => Key::KeyComma,
winit::keyboard::KeyCode::NumpadDecimal => Key::KeyKpdot,
winit::keyboard::KeyCode::NumpadDivide => Key::KeyKpslash,
winit::keyboard::KeyCode::NumpadEqual => Key::KeyKpequal,
winit::keyboard::KeyCode::NumpadMultiply => Key::KeyKpasterisk,
winit::keyboard::KeyCode::NumpadStar => Key::KeyKpasterisk,
winit::keyboard::KeyCode::NumpadSubtract => Key::KeyKpminus,
winit::keyboard::KeyCode::Escape => Key::KeyEsc,
winit::keyboard::KeyCode::PrintScreen => Key::KeyPrintscreen,
winit::keyboard::KeyCode::ScrollLock => Key::KeyScrolllock,
winit::keyboard::KeyCode::Pause => Key::KeyPause,
winit::keyboard::KeyCode::BrowserBack => Key::KeyBrback,
winit::keyboard::KeyCode::BrowserFavorites => Key::KeyBrfavs,
winit::keyboard::KeyCode::BrowserForward => Key::KeyBrfwd,
winit::keyboard::KeyCode::BrowserHome => Key::KeyBrhome,
winit::keyboard::KeyCode::BrowserRefresh => Key::KeyBrrefresh,
winit::keyboard::KeyCode::BrowserSearch => Key::KeyBrsearch,
winit::keyboard::KeyCode::BrowserStop => Key::KeyBrstop,
winit::keyboard::KeyCode::Eject => Key::KeyEject,
winit::keyboard::KeyCode::MediaPlayPause => Key::KeyMedplay,
winit::keyboard::KeyCode::MediaSelect => Key::KeyMedsel,
winit::keyboard::KeyCode::MediaStop => Key::KeyMedstop,
winit::keyboard::KeyCode::MediaTrackNext => Key::KeyMednext,
winit::keyboard::KeyCode::MediaTrackPrevious => Key::KeyMedprev,
winit::keyboard::KeyCode::AudioVolumeUp => Key::KeyMedvolup,
winit::keyboard::KeyCode::AudioVolumeMute => Key::KeyMedmute,
winit::keyboard::KeyCode::AudioVolumeDown => Key::KeyMedvoldown,
winit::keyboard::KeyCode::F1 => Key::KeyF1,
winit::keyboard::KeyCode::F2 => Key::KeyF2,
winit::keyboard::KeyCode::F3 => Key::KeyF3,
winit::keyboard::KeyCode::F4 => Key::KeyF4,
winit::keyboard::KeyCode::F5 => Key::KeyF5,
winit::keyboard::KeyCode::F6 => Key::KeyF6,
winit::keyboard::KeyCode::F7 => Key::KeyF7,
winit::keyboard::KeyCode::F8 => Key::KeyF8,
winit::keyboard::KeyCode::F9 => Key::KeyF9,
winit::keyboard::KeyCode::F10 => Key::KeyF10,
winit::keyboard::KeyCode::F11 => Key::KeyF11,
winit::keyboard::KeyCode::F12 => Key::KeyF12,
winit::keyboard::KeyCode::F13 => Key::KeyF13,
winit::keyboard::KeyCode::F14 => Key::KeyF14,
winit::keyboard::KeyCode::F15 => Key::KeyF15,
winit::keyboard::KeyCode::F16 => Key::KeyF16,
winit::keyboard::KeyCode::F17 => Key::KeyF17,
winit::keyboard::KeyCode::F18 => Key::KeyF18,
winit::keyboard::KeyCode::F19 => Key::KeyF19,
winit::keyboard::KeyCode::F20 => Key::KeyF20,
winit::keyboard::KeyCode::F21 => Key::KeyF21,
winit::keyboard::KeyCode::F22 => Key::KeyF22,
winit::keyboard::KeyCode::F23 => Key::KeyF23,
winit::keyboard::KeyCode::F24 => Key::KeyF24,
winit::keyboard::KeyCode::F25 => Key::KeyF25,
_ => Key::KeyUnsupported,
}
}
}
#[derive(NifUnitEnum, Debug, Clone)]
pub enum MouseButton {
BtnLeft,
BtnRight,
BtnMiddle,
BtnBack,
BtnForward,
BtnOther,
}
impl From<winit::event::MouseButton> for MouseButton {
fn from(btn: winit::event::MouseButton) -> Self {
match btn {
winit::event::MouseButton::Left => MouseButton::BtnLeft,
winit::event::MouseButton::Right => MouseButton::BtnRight,
winit::event::MouseButton::Middle => MouseButton::BtnMiddle,
winit::event::MouseButton::Back => MouseButton::BtnBack,
winit::event::MouseButton::Forward => MouseButton::BtnForward,
winit::event::MouseButton::Other(_) => MouseButton::BtnOther,
}
}
}
#[derive(NifTaggedEnum, Debug, Clone)]
pub enum InputEvent {
CodePoint(String, Vec<ModifierKey>),
Key(String, u8, Vec<ModifierKey>),
CursorButton(String, u8, Vec<ModifierKey>, Point),
CodePoint(u32, Vec<ModifierKey>),
Key(Key, ElementState, Vec<ModifierKey>),
CursorButton(MouseButton, ElementState, Vec<ModifierKey>, Point),
CursorScroll(Point, Point),
CursorPos(Point),
ViewPort(ViewPortEvent, Point),
@ -483,21 +805,21 @@ impl From<message::InputEvent> for InputEvent {
),
message::InputEvent::Key {
key,
value,
state,
modifiers,
} => InputEvent::Key(
key,
value,
key.into(),
state.into(),
modifiers.iter().map(|x| x.clone().into()).collect(),
),
message::InputEvent::CursorButton {
button,
value,
state,
modifiers,
position,
} => InputEvent::CursorButton(
button,
value,
button.into(),
state.into(),
modifiers.iter().map(|x| x.clone().into()).collect(),
position.into(),
),
@ -514,3 +836,39 @@ impl From<message::InputEvent> for InputEvent {
}
}
}
#[derive(NifUnitEnum, Debug, Clone)]
pub enum ShutdownAtom {
Shutdown,
}
#[derive(NifUnitEnum, Debug, Clone)]
pub enum ShutdownReason {
Normal,
Terminate,
}
#[derive(NifTuple, Debug, Clone)]
pub struct ShutdownMessage(ShutdownAtom, ShutdownReason);
impl ShutdownMessage {
pub fn normal() -> Self {
ShutdownMessage(ShutdownAtom::Shutdown, ShutdownReason::Normal)
}
pub fn terminate() -> Self {
ShutdownMessage(ShutdownAtom::Shutdown, ShutdownReason::Terminate)
}
}
impl From<message::ShutdownReason> for ShutdownMessage {
fn from(reason: message::ShutdownReason) -> Self {
match reason {
message::ShutdownReason::Normal => {
ShutdownMessage(ShutdownAtom::Shutdown, ShutdownReason::Normal)
}
message::ShutdownReason::Terminate => {
ShutdownMessage(ShutdownAtom::Shutdown, ShutdownReason::Terminate)
}
}
}
}

View file

@ -1,9 +1,11 @@
mod elixir_types;
mod message;
use crate::elixir_types::{Color, DriverConfig, InputClass, InputEvent, ScriptItem};
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
use rustler::{Encoder, Env, LocalPid, NifResult, OwnedEnv, ResourceArc, Term};
use crate::elixir_types::{
Color, DriverConfig, InputClass, InputEvent, ScriptItem, ShutdownMessage,
};
use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
use rustler::{Encoder, Env, NifResult, OwnedEnv, ResourceArc, Term};
use std::process::{Child, Command, Stdio};
use std::sync::Mutex;
use std::thread::sleep;
@ -33,21 +35,32 @@ fn init(env: Env<'_>, cfg: DriverConfig) -> ResourceArc<IpcResource> {
let pid = env.pid();
std::thread::spawn(move || loop {
let event = receiver.recv().unwrap();
let mut msg_env = OwnedEnv::new();
match event {
message::Message::InputEvent(input_event) => {
let _ = msg_env.send_and_clear(&pid, |env| {
let input_event: InputEvent = input_event.into();
input_event.encode(env)
});
if let Ok(event) = receiver.recv() {
let mut msg_env = OwnedEnv::new();
match event {
message::Message::InputEvent(input_event) => {
msg_env
.send_and_clear(&pid, |env| {
let input_event: InputEvent = input_event.into();
input_event.encode(env)
})
.unwrap();
}
message::Message::Shutdown(reason) => {
msg_env
.send_and_clear(&pid, |env| {
let msg: ShutdownMessage = reason.into();
msg.encode(env)
})
.unwrap();
}
_ => unimplemented!(),
}
message::Message::Shutdown => {
let _ = msg_env.send_and_clear(&pid, |env| {
rustler::Atom::from_str(env, "shutdown").unwrap()
});
}
_ => unimplemented!(),
} else {
let mut msg_env = OwnedEnv::new();
msg_env
.send_and_clear(&pid, |env| ShutdownMessage::terminate().encode(env))
.unwrap();
}
});
@ -128,7 +141,10 @@ fn terminate(resource: ResourceArc<IpcResource>) {
println!("Shutting down server.");
let mut mutex = resource.0.lock().unwrap();
if let None = mutex.handle.try_wait().unwrap() {
mutex.sender.send(message::Message::Shutdown).unwrap();
mutex
.sender
.send(message::Message::Shutdown(message::ShutdownReason::Normal))
.unwrap();
drop(mutex);
std::thread::spawn(move || {
// We give the server 100 millis to shut down and then we just kill

View file

@ -611,7 +611,7 @@ impl From<elixir_types::ScriptItem> for ScriptItem {
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
pub enum ModifierKey {
Meta,
Alt,
@ -628,6 +628,24 @@ pub struct Point {
pub y: u32,
}
impl From<winit::dpi::PhysicalPosition<f64>> for Point {
fn from(pos: winit::dpi::PhysicalPosition<f64>) -> Self {
Point {
x: pos.x.round() as u32,
y: pos.y.round() as u32,
}
}
}
impl From<winit::dpi::PhysicalSize<u32>> for Point {
fn from(pos: winit::dpi::PhysicalSize<u32>) -> Self {
Point {
x: pos.width,
y: pos.height,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum ViewPortEvent {
Enter,
@ -635,20 +653,35 @@ pub enum ViewPortEvent {
Reshape,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum ElementState {
Pressed,
Released,
}
impl From<winit::event::ElementState> for ElementState {
fn from(state: winit::event::ElementState) -> Self {
match state {
winit::event::ElementState::Pressed => ElementState::Pressed,
winit::event::ElementState::Released => ElementState::Released,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum InputEvent {
CodePoint {
codepoint: String,
codepoint: u32,
modifiers: Vec<ModifierKey>,
},
Key {
key: String,
value: u8,
key: winit::keyboard::KeyCode,
state: ElementState,
modifiers: Vec<ModifierKey>,
},
CursorButton {
button: String,
value: u8,
button: winit::event::MouseButton,
state: ElementState,
modifiers: Vec<ModifierKey>,
position: Point,
},
@ -676,13 +709,17 @@ pub enum InputEvent {
},
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum ShutdownReason {
Normal,
Terminate,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Message {
Shutdown,
Shutdown(ShutdownReason),
ResetScene,
Init {
opacity: u32,
debug: bool,
antialias: bool,
centered: bool,
scaled: bool,
@ -703,8 +740,6 @@ pub enum Message {
impl From<elixir_types::DriverConfig> for Message {
fn from(driver_config: elixir_types::DriverConfig) -> Self {
Message::Init {
opacity: driver_config.opacity,
debug: driver_config.debug,
antialias: driver_config.antialias,
centered: driver_config.position.centered,
scaled: driver_config.position.scaled,

View file

@ -1,6 +1,7 @@
mod elixir_types;
mod message;
use std::collections::HashSet;
use std::process::exit;
use crate::message::{IpcExchange, Message};
@ -8,12 +9,12 @@ use clap::Parser;
use ipc_channel::ipc;
use ipc_channel::ipc::IpcSender;
use message::{InputClass, OnClose, Orientation};
use message::{InputClass, ModifierKey, OnClose, Orientation};
use winit::application::ApplicationHandler;
use winit::dpi::{LogicalPosition, LogicalSize};
use winit::event::WindowEvent;
use winit::event::{ElementState, KeyEvent, WindowEvent};
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::keyboard::{Key, ModifiersState};
use winit::keyboard::{Key, NamedKey, PhysicalKey};
use winit::window::{Window, WindowId};
#[cfg(macos_platform)]
@ -54,7 +55,8 @@ fn main() -> anyhow::Result<()> {
let event = c2s_recv.recv().unwrap();
match event {
Message::Shutdown => exit(0),
Message::Shutdown(message::ShutdownReason::Normal) => exit(0),
Message::Shutdown(message::ShutdownReason::Terminate) => exit(1),
Message::Init { .. } => unreachable!(),
_ => event_loop_proxy.send_event(event).unwrap(),
};
@ -68,8 +70,6 @@ fn main() -> anyhow::Result<()> {
}
struct Application {
opacity: u32,
debug: bool,
antialias: bool,
centered: bool,
scaled: bool,
@ -82,14 +82,14 @@ struct Application {
window: Option<Window>,
input_classes: Vec<InputClass>,
sender: IpcSender<Message>,
current_modifier_keys: HashSet<message::ModifierKey>,
last_cursor_pos: message::Point,
}
impl Application {
fn new(event: Message, sender: IpcSender<Message>) -> Self {
match event {
Message::Init {
opacity,
debug,
antialias,
centered,
scaled,
@ -100,8 +100,6 @@ impl Application {
height,
on_close,
} => Application {
opacity,
debug,
antialias,
centered,
scaled,
@ -124,6 +122,8 @@ impl Application {
InputClass::Switch,
],
sender,
current_modifier_keys: HashSet::default(),
last_cursor_pos: message::Point { x: 0, y: 0 },
},
_ => unreachable!(),
}
@ -142,42 +142,199 @@ impl ApplicationHandler<Message> for Application {
event: WindowEvent,
) {
match event {
// Keep a record of which modifier keys are pressed at any given time.
WindowEvent::KeyboardInput { event, .. } => {
// From cairo driver:
//
// int action = (event->type == GDK_KEY_PRESS) ? 1 : 0;
// uint32_t unicode = gdk_keyval_to_unicode(event->keyval);
// send_key(KEYMAP_GDK, event->keyval, event->hardware_keycode, action, event->state);
// if (!(event->keyval & 0xF000) && event->type == GDK_KEY_PRESS) {
// send_codepoint(KEYMAP_GDK, unicode, event->state);
// }
// return TRUE;
//
// Basically, always send a Key event and sometimes a Codepoint event.
match event {
KeyEvent {
logical_key: Key::Named(NamedKey::Meta),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::Meta),
KeyEvent {
logical_key: Key::Named(NamedKey::Meta),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::Meta),
KeyEvent {
logical_key: Key::Named(NamedKey::Alt),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::Alt),
KeyEvent {
logical_key: Key::Named(NamedKey::Alt),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::Alt),
KeyEvent {
logical_key: Key::Named(NamedKey::Control),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::Ctrl),
KeyEvent {
logical_key: Key::Named(NamedKey::Control),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::Ctrl),
KeyEvent {
logical_key: Key::Named(NamedKey::Shift),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::Shift),
KeyEvent {
logical_key: Key::Named(NamedKey::Shift),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::Shift),
KeyEvent {
logical_key: Key::Named(NamedKey::CapsLock),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::CapsLock),
KeyEvent {
logical_key: Key::Named(NamedKey::CapsLock),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::CapsLock),
KeyEvent {
logical_key: Key::Named(NamedKey::NumLock),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::NumLock),
KeyEvent {
logical_key: Key::Named(NamedKey::NumLock),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::NumLock),
KeyEvent {
logical_key: Key::Named(NamedKey::ScrollLock),
state: ElementState::Pressed,
..
} => self.current_modifier_keys.insert(ModifierKey::ScrollLock),
KeyEvent {
logical_key: Key::Named(NamedKey::ScrollLock),
state: ElementState::Released,
..
} => self.current_modifier_keys.remove(&ModifierKey::ScrollLock),
_ => true,
};
if let PhysicalKey::Code(keycode) = event.physical_key {
self.sender
.send(Message::InputEvent(message::InputEvent::Key {
key: keycode,
state: event.state.into(),
modifiers: self
.current_modifier_keys
.iter()
.cloned()
.collect::<Vec<ModifierKey>>(),
}))
.unwrap();
}
if let Some(text) = event.text {
let codepoint = text.chars().next().unwrap();
self.sender
.send(Message::InputEvent(message::InputEvent::CodePoint {
codepoint: codepoint as u32,
modifiers: self
.current_modifier_keys
.iter()
.cloned()
.collect::<Vec<ModifierKey>>(),
}))
.unwrap();
}
}
WindowEvent::CloseRequested => {
self.sender.send(Message::Shutdown).unwrap();
self.sender
.send(Message::Shutdown(message::ShutdownReason::Normal))
.unwrap();
}
WindowEvent::Destroyed => {
self.sender.send(Message::Shutdown).unwrap();
self.sender
.send(Message::Shutdown(message::ShutdownReason::Terminate))
.unwrap();
}
WindowEvent::CursorMoved { position, .. } => {
// Send an CursorPos event.
let pos: message::Point = position.into();
self.last_cursor_pos = pos.clone();
self.sender
.send(Message::InputEvent(message::InputEvent::CursorPos {
position: pos,
}))
.unwrap();
}
WindowEvent::MouseInput { state, button, .. } => {
// Send a CursorButton event.
self.sender
.send(Message::InputEvent(message::InputEvent::CursorButton {
button: button,
state: state.into(),
modifiers: self
.current_modifier_keys
.iter()
.cloned()
.collect::<Vec<ModifierKey>>(),
position: self.last_cursor_pos.clone(),
}))
.unwrap();
}
WindowEvent::AxisMotion { axis, value, .. } => {
// Send a CursorScroll event.
WindowEvent::Touch(touch) => match touch.phase {
winit::event::TouchPhase::Started => {
self.sender
.send(Message::InputEvent(message::InputEvent::CursorButton {
button: winit::event::MouseButton::Left,
state: message::ElementState::Pressed,
modifiers: self
.current_modifier_keys
.iter()
.cloned()
.collect::<Vec<ModifierKey>>(),
position: self.last_cursor_pos.clone(),
}))
.unwrap();
}
winit::event::TouchPhase::Ended => {
self.sender
.send(Message::InputEvent(message::InputEvent::CursorButton {
button: winit::event::MouseButton::Left,
state: message::ElementState::Released,
modifiers: self
.current_modifier_keys
.iter()
.cloned()
.collect::<Vec<ModifierKey>>(),
position: self.last_cursor_pos.clone(),
}))
.unwrap();
}
_ => (),
},
WindowEvent::CursorEntered { .. } => {
self.sender
.send(Message::InputEvent(message::InputEvent::ViewPort {
event: message::ViewPortEvent::Enter,
position: self.last_cursor_pos.clone(),
}))
.unwrap();
}
WindowEvent::CursorEntered { device_id } => {
// Send a ViewPort { event: ViewPortEvent::Enter, position: ?? }
}
WindowEvent::CursorLeft { device_id } => {
// Send a ViewPort { event: ViewPortEvent::Exit, position: ?? }
WindowEvent::CursorLeft { .. } => {
self.sender
.send(Message::InputEvent(message::InputEvent::ViewPort {
event: message::ViewPortEvent::Exit,
position: self.last_cursor_pos.clone(),
}))
.unwrap();
}
WindowEvent::Resized(size) => {
// Send a ViewPort { event: ViewPortEvent::Reshape, position: Point(size.x, size.y) }
self.sender
.send(Message::InputEvent(message::InputEvent::ViewPort {
event: message::ViewPortEvent::Reshape,
position: size.into(),
}))
.unwrap();
}
_ => println!("unhandled window event {:?}", event),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -7,7 +7,7 @@ defmodule Example do
[
module: Scenic.Driver.Renderling.Window,
name: :window,
window: [resizeable: false, title: "Example Window"]
window: [resizeable: true, title: "Example Window"]
]
]
]