[oden] Input
This commit is contained in:
parent
c934914ac5
commit
e0878b4ea6
6 changed files with 363 additions and 14 deletions
207
src/input.ts
207
src/input.ts
|
|
@ -1,3 +1,206 @@
|
||||||
|
import * as core from "input-core";
|
||||||
|
|
||||||
|
// NOTE: This is derived from rust's winit VirtualKeyCode as of 2023/07/07
|
||||||
|
export const Key = {
|
||||||
|
/// The '1' key over the letters.
|
||||||
|
Key1: 1,
|
||||||
|
/// The '2' key over the letters.
|
||||||
|
Key2: 2,
|
||||||
|
/// The '3' key over the letters.
|
||||||
|
Key3: 3,
|
||||||
|
/// The '4' key over the letters.
|
||||||
|
Key4: 4,
|
||||||
|
/// The '5' key over the letters.
|
||||||
|
Key5: 5,
|
||||||
|
/// The '6' key over the letters.
|
||||||
|
Key6: 6,
|
||||||
|
/// The '7' key over the letters.
|
||||||
|
Key7: 7,
|
||||||
|
/// The '8' key over the letters.
|
||||||
|
Key8: 8,
|
||||||
|
/// The '9' key over the letters.
|
||||||
|
Key9: 9,
|
||||||
|
/// The '0' key over the 'O' and 'P' keys.
|
||||||
|
Key0: 10,
|
||||||
|
|
||||||
|
A: 11,
|
||||||
|
B: 12,
|
||||||
|
C: 13,
|
||||||
|
D: 14,
|
||||||
|
E: 15,
|
||||||
|
F: 16,
|
||||||
|
G: 17,
|
||||||
|
H: 18,
|
||||||
|
I: 19,
|
||||||
|
J: 20,
|
||||||
|
K: 21,
|
||||||
|
L: 22,
|
||||||
|
M: 23,
|
||||||
|
N: 24,
|
||||||
|
O: 25,
|
||||||
|
P: 26,
|
||||||
|
Q: 27,
|
||||||
|
R: 28,
|
||||||
|
S: 29,
|
||||||
|
T: 30,
|
||||||
|
U: 31,
|
||||||
|
V: 32,
|
||||||
|
W: 33,
|
||||||
|
X: 34,
|
||||||
|
Y: 35,
|
||||||
|
Z: 36,
|
||||||
|
|
||||||
|
/// The Escape key, next to F1.
|
||||||
|
Escape: 37,
|
||||||
|
|
||||||
|
F1: 38,
|
||||||
|
F2: 39,
|
||||||
|
F3: 40,
|
||||||
|
F4: 41,
|
||||||
|
F5: 42,
|
||||||
|
F6: 43,
|
||||||
|
F7: 44,
|
||||||
|
F8: 45,
|
||||||
|
F9: 46,
|
||||||
|
F10: 47,
|
||||||
|
F11: 48,
|
||||||
|
F12: 49,
|
||||||
|
F13: 50,
|
||||||
|
F14: 51,
|
||||||
|
F15: 52,
|
||||||
|
F16: 53,
|
||||||
|
F17: 54,
|
||||||
|
F18: 55,
|
||||||
|
F19: 56,
|
||||||
|
F20: 57,
|
||||||
|
F21: 58,
|
||||||
|
F22: 59,
|
||||||
|
F23: 60,
|
||||||
|
F24: 61,
|
||||||
|
|
||||||
|
/// Print Screen/SysRq.
|
||||||
|
Snapshot: 62,
|
||||||
|
/// Scroll Lock.
|
||||||
|
Scroll: 63,
|
||||||
|
/// Pause/Break key, next to Scroll lock.
|
||||||
|
Pause: 64,
|
||||||
|
|
||||||
|
/// `Insert`, next to Backspace.
|
||||||
|
Insert: 65,
|
||||||
|
Home: 66,
|
||||||
|
Delete: 67,
|
||||||
|
End: 68,
|
||||||
|
PageDown: 69,
|
||||||
|
PageUp: 70,
|
||||||
|
|
||||||
|
Left: 71,
|
||||||
|
Up: 72,
|
||||||
|
Right: 73,
|
||||||
|
Down: 74,
|
||||||
|
|
||||||
|
/// The Backspace key, right over Enter.
|
||||||
|
// TODO: rename
|
||||||
|
Back: 75,
|
||||||
|
/// The Enter key.
|
||||||
|
Return: 76,
|
||||||
|
/// The space bar.
|
||||||
|
Space: 77,
|
||||||
|
|
||||||
|
/// The "Compose" key on Linux.
|
||||||
|
Compose: 78,
|
||||||
|
|
||||||
|
Caret: 79,
|
||||||
|
|
||||||
|
Numlock: 80,
|
||||||
|
Numpad0: 81,
|
||||||
|
Numpad1: 82,
|
||||||
|
Numpad2: 83,
|
||||||
|
Numpad3: 84,
|
||||||
|
Numpad4: 85,
|
||||||
|
Numpad5: 86,
|
||||||
|
Numpad6: 87,
|
||||||
|
Numpad7: 88,
|
||||||
|
Numpad8: 89,
|
||||||
|
Numpad9: 90,
|
||||||
|
NumpadAdd: 91,
|
||||||
|
NumpadDivide: 92,
|
||||||
|
NumpadDecimal: 93,
|
||||||
|
NumpadComma: 94,
|
||||||
|
NumpadEnter: 95,
|
||||||
|
NumpadEquals: 96,
|
||||||
|
NumpadMultiply: 97,
|
||||||
|
NumpadSubtract: 98,
|
||||||
|
|
||||||
|
AbntC1: 99,
|
||||||
|
AbntC2: 100,
|
||||||
|
Apostrophe: 101,
|
||||||
|
Apps: 102,
|
||||||
|
Asterisk: 103,
|
||||||
|
At: 104,
|
||||||
|
Ax: 105,
|
||||||
|
Backslash: 106,
|
||||||
|
Calculator: 107,
|
||||||
|
Capital: 108,
|
||||||
|
Colon: 109,
|
||||||
|
Comma: 110,
|
||||||
|
Convert: 111,
|
||||||
|
Equals: 112,
|
||||||
|
Grave: 113,
|
||||||
|
Kana: 114,
|
||||||
|
Kanji: 115,
|
||||||
|
LAlt: 116,
|
||||||
|
LBracket: 117,
|
||||||
|
LControl: 118,
|
||||||
|
LShift: 119,
|
||||||
|
LWin: 120,
|
||||||
|
Mail: 121,
|
||||||
|
MediaSelect: 122,
|
||||||
|
MediaStop: 123,
|
||||||
|
Minus: 124,
|
||||||
|
Mute: 125,
|
||||||
|
MyComputer: 126,
|
||||||
|
// also called "Next"
|
||||||
|
NavigateForward: 127,
|
||||||
|
// also called "Prior"
|
||||||
|
NavigateBackward: 128,
|
||||||
|
NextTrack: 129,
|
||||||
|
NoConvert: 130,
|
||||||
|
OEM102: 131,
|
||||||
|
Period: 132,
|
||||||
|
PlayPause: 133,
|
||||||
|
Plus: 134,
|
||||||
|
Power: 135,
|
||||||
|
PrevTrack: 136,
|
||||||
|
RAlt: 137,
|
||||||
|
RBracket: 138,
|
||||||
|
RControl: 139,
|
||||||
|
RShift: 140,
|
||||||
|
RWin: 141,
|
||||||
|
Semicolon: 142,
|
||||||
|
Slash: 143,
|
||||||
|
Sleep: 144,
|
||||||
|
Stop: 145,
|
||||||
|
Sysrq: 146,
|
||||||
|
Tab: 147,
|
||||||
|
Underline: 148,
|
||||||
|
Unlabeled: 149,
|
||||||
|
VolumeDown: 150,
|
||||||
|
VolumeUp: 151,
|
||||||
|
Wake: 152,
|
||||||
|
WebBack: 153,
|
||||||
|
WebFavorites: 154,
|
||||||
|
WebForward: 155,
|
||||||
|
WebHome: 156,
|
||||||
|
WebRefresh: 157,
|
||||||
|
WebSearch: 158,
|
||||||
|
WebStop: 159,
|
||||||
|
Yen: 160,
|
||||||
|
Copy: 161,
|
||||||
|
Paste: 162,
|
||||||
|
Cut: 163,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// NOTE: This must match the definition in input.rs.
|
||||||
export const Button = {
|
export const Button = {
|
||||||
Up: 0,
|
Up: 0,
|
||||||
Down: 1,
|
Down: 1,
|
||||||
|
|
@ -6,6 +209,6 @@ export const Button = {
|
||||||
} as const;
|
} as const;
|
||||||
type Button = (typeof Button)[keyof typeof Button];
|
type Button = (typeof Button)[keyof typeof Button];
|
||||||
|
|
||||||
export function btn(_which: Button): boolean {
|
export function btn(b: Button): boolean {
|
||||||
return false;
|
return core.btn(b);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/lib.rs
14
src/lib.rs
|
|
@ -296,10 +296,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input(&mut self, _event: &WindowEvent) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self) {
|
fn update(&mut self) {
|
||||||
self.screen_uniform = ScreenUniforms::new(self.size.width, self.size.height);
|
self.screen_uniform = ScreenUniforms::new(self.size.width, self.size.height);
|
||||||
self.queue.write_buffer(
|
self.queue.write_buffer(
|
||||||
|
|
@ -486,8 +482,8 @@ struct UIEvent {
|
||||||
|
|
||||||
fn main_thread(state: State, reciever: Receiver<UIEvent>) {
|
fn main_thread(state: State, reciever: Receiver<UIEvent>) {
|
||||||
let mut state = state;
|
let mut state = state;
|
||||||
let mut context = script::ScriptContext::new();
|
let mut script = script::ScriptContext::new();
|
||||||
context.init();
|
script.init();
|
||||||
|
|
||||||
const SPF: f64 = 1.0 / 60.0;
|
const SPF: f64 = 1.0 / 60.0;
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -502,7 +498,7 @@ fn main_thread(state: State, reciever: Receiver<UIEvent>) {
|
||||||
ref event,
|
ref event,
|
||||||
window_id,
|
window_id,
|
||||||
} if window_id == state.window().id() => {
|
} if window_id == state.window().id() => {
|
||||||
if !state.input(event) {
|
if !script.input(event) {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
state.mouse_x = position.x;
|
state.mouse_x = position.x;
|
||||||
|
|
@ -530,13 +526,13 @@ fn main_thread(state: State, reciever: Receiver<UIEvent>) {
|
||||||
|
|
||||||
{
|
{
|
||||||
let _span = span!("update");
|
let _span = span!("update");
|
||||||
context.update();
|
script.update();
|
||||||
state.update();
|
state.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let _span = span!("render");
|
let _span = span!("render");
|
||||||
match state.render(context.render()) {
|
match state.render(script.render()) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
// Reconfigure the surface if lost
|
// Reconfigure the surface if lost
|
||||||
Err(wgpu::SurfaceError::Lost) => state.resize(state.size),
|
Err(wgpu::SurfaceError::Lost) => state.resize(state.size),
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,18 @@ use std::ffi::OsStr;
|
||||||
use std::sync::mpsc::{channel, Receiver};
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tracy_client::span;
|
use tracy_client::span;
|
||||||
|
use winit::event::*;
|
||||||
|
|
||||||
pub mod graphics;
|
pub mod graphics;
|
||||||
|
mod input;
|
||||||
|
mod io;
|
||||||
|
mod time;
|
||||||
|
|
||||||
use graphics::GraphicsCommand;
|
use graphics::GraphicsCommand;
|
||||||
|
|
||||||
mod typescript;
|
mod typescript;
|
||||||
use typescript::transpile_to_javascript;
|
use typescript::transpile_to_javascript;
|
||||||
|
|
||||||
mod io;
|
|
||||||
mod time;
|
|
||||||
|
|
||||||
struct Loader {}
|
struct Loader {}
|
||||||
|
|
||||||
impl Loader {
|
impl Loader {
|
||||||
|
|
@ -49,6 +51,7 @@ pub struct ScriptContext {
|
||||||
gfx_receive: Receiver<graphics::GraphicsCommand>,
|
gfx_receive: Receiver<graphics::GraphicsCommand>,
|
||||||
|
|
||||||
time: time::TimeAPI,
|
time: time::TimeAPI,
|
||||||
|
input: input::InputAPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptContext {
|
impl ScriptContext {
|
||||||
|
|
@ -66,6 +69,8 @@ impl ScriptContext {
|
||||||
.expect("Graphics module should load without error");
|
.expect("Graphics module should load without error");
|
||||||
let _io = io::IoAPI::define(&context).expect("IO module should load without error");
|
let _io = io::IoAPI::define(&context).expect("IO module should load without error");
|
||||||
let time = time::TimeAPI::define(&context).expect("Time module should load without error");
|
let time = time::TimeAPI::define(&context).expect("Time module should load without error");
|
||||||
|
let input =
|
||||||
|
input::InputAPI::define(&context).expect("Input module should load without error");
|
||||||
|
|
||||||
let module = context
|
let module = context
|
||||||
.import_module("./main.ts", "")
|
.import_module("./main.ts", "")
|
||||||
|
|
@ -92,6 +97,7 @@ impl ScriptContext {
|
||||||
gfx_receive,
|
gfx_receive,
|
||||||
|
|
||||||
time,
|
time,
|
||||||
|
input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,6 +113,13 @@ impl ScriptContext {
|
||||||
.expect("Exception in init");
|
.expect("Exception in init");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||||
|
match event {
|
||||||
|
WindowEvent::KeyboardInput { input, .. } => self.input.handle_keyboard_input(input),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
let _span = span!("script update");
|
let _span = span!("script update");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
// TODO: Fix the dumb command structures.
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PrintCommand {
|
pub struct PrintCommand {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
|
|
||||||
132
src/script/input.rs
Normal file
132
src/script/input.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
use oden_js::{module::native::NativeModuleBuilder, ContextRef};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode};
|
||||||
|
|
||||||
|
/// An abstraction over hardware keys.
|
||||||
|
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||||
|
enum Button {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Button> for u32 {
|
||||||
|
fn from(v: Button) -> Self {
|
||||||
|
match v {
|
||||||
|
Button::Up => 0,
|
||||||
|
Button::Down => 1,
|
||||||
|
Button::Left => 2,
|
||||||
|
Button::Right => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for Button {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn try_from(v: u32) -> Result<Self, Self::Error> {
|
||||||
|
match v {
|
||||||
|
0 => Ok(Button::Up),
|
||||||
|
1 => Ok(Button::Down),
|
||||||
|
2 => Ok(Button::Left),
|
||||||
|
3 => Ok(Button::Right),
|
||||||
|
_ => Err("unknown button value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputState {
|
||||||
|
up_pressed: bool,
|
||||||
|
down_pressed: bool,
|
||||||
|
left_pressed: bool,
|
||||||
|
right_pressed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputState {
|
||||||
|
fn new() -> Self {
|
||||||
|
InputState {
|
||||||
|
up_pressed: false,
|
||||||
|
down_pressed: false,
|
||||||
|
left_pressed: false,
|
||||||
|
right_pressed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_keyboard_input(&mut self, input: &KeyboardInput) -> bool {
|
||||||
|
let pressed = input.state == ElementState::Pressed;
|
||||||
|
match input.virtual_keycode {
|
||||||
|
Some(VirtualKeyCode::Left) => {
|
||||||
|
self.left_pressed = pressed;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some(VirtualKeyCode::Right) => {
|
||||||
|
self.right_pressed = pressed;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some(VirtualKeyCode::Up) => {
|
||||||
|
self.up_pressed = pressed;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some(VirtualKeyCode::Down) => {
|
||||||
|
self.down_pressed = pressed;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputImpl {
|
||||||
|
state: RefCell<InputState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputImpl {
|
||||||
|
fn new() -> Self {
|
||||||
|
InputImpl {
|
||||||
|
state: RefCell::new(InputState::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_keyboard_input(&self, input: &KeyboardInput) -> bool {
|
||||||
|
self.state.borrow_mut().handle_keyboard_input(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btn(&self, button: u32) -> bool {
|
||||||
|
if let Ok(b) = Button::try_from(button) {
|
||||||
|
let state = self.state.borrow();
|
||||||
|
match b {
|
||||||
|
Button::Up => state.up_pressed,
|
||||||
|
Button::Down => state.down_pressed,
|
||||||
|
Button::Left => state.left_pressed,
|
||||||
|
Button::Right => state.right_pressed,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InputAPI {
|
||||||
|
input: Arc<InputImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputAPI {
|
||||||
|
pub fn define(ctx: &ContextRef) -> oden_js::Result<Self> {
|
||||||
|
let input = Arc::new(InputImpl::new());
|
||||||
|
let mut builder = NativeModuleBuilder::new(ctx);
|
||||||
|
{
|
||||||
|
let input = input.clone();
|
||||||
|
builder.export(
|
||||||
|
"btn",
|
||||||
|
ctx.new_fn(move |_ctx: &ContextRef, b: u32| input.btn(b))?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
builder.build("input-core")?;
|
||||||
|
Ok(InputAPI { input })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_keyboard_input(&mut self, input: &KeyboardInput) -> bool {
|
||||||
|
self.input.handle_keyboard_input(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
3
types/input-core.d.ts
vendored
Normal file
3
types/input-core.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
// These are the functions exposed by the native input module.
|
||||||
|
//
|
||||||
|
export function btn(b: number): boolean;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue