[oden] Input

This commit is contained in:
John Doty 2023-07-07 07:28:46 -07:00
parent c934914ac5
commit e0878b4ea6
6 changed files with 363 additions and 14 deletions

View file

@ -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 = {
Up: 0,
Down: 1,
@ -6,6 +209,6 @@ export const Button = {
} as const;
type Button = (typeof Button)[keyof typeof Button];
export function btn(_which: Button): boolean {
return false;
export function btn(b: Button): boolean {
return core.btn(b);
}

View file

@ -296,10 +296,6 @@ impl State {
}
}
fn input(&mut self, _event: &WindowEvent) -> bool {
false
}
fn update(&mut self) {
self.screen_uniform = ScreenUniforms::new(self.size.width, self.size.height);
self.queue.write_buffer(
@ -486,8 +482,8 @@ struct UIEvent {
fn main_thread(state: State, reciever: Receiver<UIEvent>) {
let mut state = state;
let mut context = script::ScriptContext::new();
context.init();
let mut script = script::ScriptContext::new();
script.init();
const SPF: f64 = 1.0 / 60.0;
loop {
@ -502,7 +498,7 @@ fn main_thread(state: State, reciever: Receiver<UIEvent>) {
ref event,
window_id,
} if window_id == state.window().id() => {
if !state.input(event) {
if !script.input(event) {
match event {
WindowEvent::CursorMoved { position, .. } => {
state.mouse_x = position.x;
@ -530,13 +526,13 @@ fn main_thread(state: State, reciever: Receiver<UIEvent>) {
{
let _span = span!("update");
context.update();
script.update();
state.update();
}
{
let _span = span!("render");
match state.render(context.render()) {
match state.render(script.render()) {
Ok(_) => {}
// Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => state.resize(state.size),

View file

@ -6,16 +6,18 @@ use std::ffi::OsStr;
use std::sync::mpsc::{channel, Receiver};
use std::time::Instant;
use tracy_client::span;
use winit::event::*;
pub mod graphics;
mod input;
mod io;
mod time;
use graphics::GraphicsCommand;
mod typescript;
use typescript::transpile_to_javascript;
mod io;
mod time;
struct Loader {}
impl Loader {
@ -49,6 +51,7 @@ pub struct ScriptContext {
gfx_receive: Receiver<graphics::GraphicsCommand>,
time: time::TimeAPI,
input: input::InputAPI,
}
impl ScriptContext {
@ -66,6 +69,8 @@ impl ScriptContext {
.expect("Graphics 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 input =
input::InputAPI::define(&context).expect("Input module should load without error");
let module = context
.import_module("./main.ts", "")
@ -92,6 +97,7 @@ impl ScriptContext {
gfx_receive,
time,
input,
}
}
@ -107,6 +113,13 @@ impl ScriptContext {
.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) {
let _span = span!("script update");

View file

@ -3,6 +3,8 @@ use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::mpsc::Sender;
use std::sync::Arc;
// TODO: Fix the dumb command structures.
#[derive(Debug)]
pub struct PrintCommand {
pub text: String,

132
src/script/input.rs Normal file
View 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
View file

@ -0,0 +1,3 @@
// These are the functions exposed by the native input module.
//
export function btn(b: number): boolean;