From 2592b1a1d16837fb15ea1c43e5c5ec8b9c7ac678 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sun, 8 Feb 2026 13:52:51 +0000 Subject: [PATCH] fixed issues with Input API --- Cargo.lock | 4 - crates/prometeu-abi/src/model/button.rs | 3 +- crates/prometeu-abi/src/syscalls.rs | 70 ++++++++ .../src/frontends/pbs/contracts.rs | 97 ++++++++--- .../src/frontends/pbs/lowering.rs | 162 ++++++++++++++++-- .../src/frontends/pbs/typecheck.rs | 7 +- crates/prometeu-hardware-contract/src/lib.rs | 2 +- crates/prometeu-hardware/Cargo.toml | 4 - crates/prometeu-hardware/src/lib.rs | 3 +- crates/prometeu-hardware/src/touch.rs | 16 +- crates/prometeu-kernel/src/prometeu_os.rs | 107 ++++++++++++ .../sdk/src/main/modules/gfx/color.pbs | 8 + .../sdk/src/main/modules/gfx/gfx.pbs | 9 - .../sdk/src/main/modules/input/button.pbs | 6 + .../sdk/src/main/modules/input/input.pbs | 41 ++--- test-cartridges/test01/cartridge/program.pbc | Bin 2497 -> 1723 bytes .../test01/src/main/modules/main.pbs | 8 +- 17 files changed, 457 insertions(+), 90 deletions(-) create mode 100644 test-cartridges/sdk/src/main/modules/gfx/color.pbs create mode 100644 test-cartridges/sdk/src/main/modules/input/button.pbs diff --git a/Cargo.lock b/Cargo.lock index 66777e48..7769ca30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1940,13 +1940,9 @@ name = "prometeu-hardware" version = "0.1.0" dependencies = [ "prometeu-abi", - "prometeu-bytecode", "prometeu-hardware-contract", - "prometeu-kernel", "prometeu-vm", - "serde", "serde_json", - "url", ] [[package]] diff --git a/crates/prometeu-abi/src/model/button.rs b/crates/prometeu-abi/src/model/button.rs index de214d2a..a5f2f66b 100644 --- a/crates/prometeu-abi/src/model/button.rs +++ b/crates/prometeu-abi/src/model/button.rs @@ -15,12 +15,13 @@ pub enum ButtonId { Select = 11, } +#[repr(C)] #[derive(Default, Clone, Copy, Debug)] pub struct Button { pub pressed: bool, pub released: bool, pub down: bool, - pub hold_frames: u32, + pub hold_frames: u16, } impl Button { diff --git a/crates/prometeu-abi/src/syscalls.rs b/crates/prometeu-abi/src/syscalls.rs index 94e4c129..0348bfab 100644 --- a/crates/prometeu-abi/src/syscalls.rs +++ b/crates/prometeu-abi/src/syscalls.rs @@ -66,6 +66,23 @@ pub enum Syscall { TouchIsReleased = 0x2105, /// Returns how many frames the pointer has been held down. TouchGetHold = 0x2106, + /// Returns the full Button struct (6 bytes) for the touch finger state. + TouchGetFinger = 0x2107, + + // --- Input (Pad service-based) --- + /// Returns the full Button struct (6 bytes) for each gamepad button + PadGetUp = 0x2200, + PadGetDown = 0x2201, + PadGetLeft = 0x2202, + PadGetRight = 0x2203, + PadGetA = 0x2204, + PadGetB = 0x2205, + PadGetX = 0x2206, + PadGetY = 0x2207, + PadGetL = 0x2208, + PadGetR = 0x2209, + PadGetStart = 0x220A, + PadGetSelect = 0x220B, // --- Audio --- /// Starts playback of a sound sample by its Bank and ID. @@ -138,6 +155,19 @@ impl Syscall { 0x2104 => Some(Self::TouchIsPressed), 0x2105 => Some(Self::TouchIsReleased), 0x2106 => Some(Self::TouchGetHold), + 0x2107 => Some(Self::TouchGetFinger), + 0x2200 => Some(Self::PadGetUp), + 0x2201 => Some(Self::PadGetDown), + 0x2202 => Some(Self::PadGetLeft), + 0x2203 => Some(Self::PadGetRight), + 0x2204 => Some(Self::PadGetA), + 0x2205 => Some(Self::PadGetB), + 0x2206 => Some(Self::PadGetX), + 0x2207 => Some(Self::PadGetY), + 0x2208 => Some(Self::PadGetL), + 0x2209 => Some(Self::PadGetR), + 0x220A => Some(Self::PadGetStart), + 0x220B => Some(Self::PadGetSelect), 0x3001 => Some(Self::AudioPlaySample), 0x3002 => Some(Self::AudioPlay), 0x4001 => Some(Self::FsOpen), @@ -184,6 +214,19 @@ impl Syscall { Self::TouchIsPressed => 0, Self::TouchIsReleased => 0, Self::TouchGetHold => 0, + Self::TouchGetFinger => 0, + Self::PadGetUp => 0, + Self::PadGetDown => 0, + Self::PadGetLeft => 0, + Self::PadGetRight => 0, + Self::PadGetA => 0, + Self::PadGetB => 0, + Self::PadGetX => 0, + Self::PadGetY => 0, + Self::PadGetL => 0, + Self::PadGetR => 0, + Self::PadGetStart => 0, + Self::PadGetSelect => 0, Self::AudioPlaySample => 5, Self::AudioPlay => 7, Self::FsOpen => 1, @@ -209,6 +252,20 @@ impl Syscall { Self::GfxClear565 => 0, Self::InputPadSnapshot => 48, Self::InputTouchSnapshot => 6, + // Touch finger and Pad per-button services return a Button (4 slots) + Self::TouchGetFinger => 4, + Self::PadGetUp + | Self::PadGetDown + | Self::PadGetLeft + | Self::PadGetRight + | Self::PadGetA + | Self::PadGetB + | Self::PadGetX + | Self::PadGetY + | Self::PadGetL + | Self::PadGetR + | Self::PadGetStart + | Self::PadGetSelect => 4, _ => 1, } } @@ -238,6 +295,19 @@ impl Syscall { Self::TouchIsPressed => "TouchIsPressed", Self::TouchIsReleased => "TouchIsReleased", Self::TouchGetHold => "TouchGetHold", + Self::TouchGetFinger => "TouchGetFinger", + Self::PadGetUp => "PadGetUp", + Self::PadGetDown => "PadGetDown", + Self::PadGetLeft => "PadGetLeft", + Self::PadGetRight => "PadGetRight", + Self::PadGetA => "PadGetA", + Self::PadGetB => "PadGetB", + Self::PadGetX => "PadGetX", + Self::PadGetY => "PadGetY", + Self::PadGetL => "PadGetL", + Self::PadGetR => "PadGetR", + Self::PadGetStart => "PadGetStart", + Self::PadGetSelect => "PadGetSelect", Self::AudioPlaySample => "AudioPlaySample", Self::AudioPlay => "AudioPlay", Self::FsOpen => "FsOpen", diff --git a/crates/prometeu-compiler/src/frontends/pbs/contracts.rs b/crates/prometeu-compiler/src/frontends/pbs/contracts.rs index 935e589f..992fc37f 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/contracts.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/contracts.rs @@ -59,7 +59,7 @@ impl ContractRegistry { }); mappings.insert("Gfx".to_string(), gfx); - // Input mappings + // Input legacy mappings (kept for backward compatibility) let mut input = HashMap::new(); input.insert("pad".to_string(), ContractMethod { id: 0x2010, @@ -73,37 +73,90 @@ impl ContractRegistry { }); mappings.insert("Input".to_string(), input); - // Touch mappings + // New Pad service-based mappings (each button as a method returning Button) + let mut pad = HashMap::new(); + // NOTE: The syscalls for per-button access must be handled by the runtime. + // We reserve the 0x2200..0x220B range for Pad buttons returning a Button struct (6 bytes). + pad.insert("up".to_string(), ContractMethod { + id: 0x2200, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("down".to_string(), ContractMethod { + id: 0x2201, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("left".to_string(), ContractMethod { + id: 0x2202, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("right".to_string(), ContractMethod { + id: 0x2203, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("a".to_string(), ContractMethod { + id: 0x2204, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("b".to_string(), ContractMethod { + id: 0x2205, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("x".to_string(), ContractMethod { + id: 0x2206, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("y".to_string(), ContractMethod { + id: 0x2207, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("l".to_string(), ContractMethod { + id: 0x2208, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("r".to_string(), ContractMethod { + id: 0x2209, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("start".to_string(), ContractMethod { + id: 0x220A, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + pad.insert("select".to_string(), ContractMethod { + id: 0x220B, + params: vec![], + return_type: PbsType::Struct("Button".to_string()), + }); + mappings.insert("Pad".to_string(), pad); + + // Touch mappings (service-based) let mut touch = HashMap::new(); - touch.insert("getX".to_string(), ContractMethod { + // SDK agora expõe screen_x/screen_y/finger() + touch.insert("screen_x".to_string(), ContractMethod { id: 0x2101, params: vec![], return_type: PbsType::Int, }); - touch.insert("getY".to_string(), ContractMethod { + touch.insert("screen_y".to_string(), ContractMethod { id: 0x2102, params: vec![], return_type: PbsType::Int, }); - touch.insert("isDown".to_string(), ContractMethod { - id: 0x2103, + // Novo syscall dedicado para retornar Button completo do touch (dedo) + touch.insert("finger".to_string(), ContractMethod { + id: 0x2107, params: vec![], - return_type: PbsType::Bool, - }); - touch.insert("isPressed".to_string(), ContractMethod { - id: 0x2104, - params: vec![], - return_type: PbsType::Bool, - }); - touch.insert("isReleased".to_string(), ContractMethod { - id: 0x2105, - params: vec![], - return_type: PbsType::Bool, - }); - touch.insert("getHold".to_string(), ContractMethod { - id: 0x2106, - params: vec![], - return_type: PbsType::Int, + return_type: PbsType::Struct("Button".to_string()), }); mappings.insert("Touch".to_string(), touch); diff --git a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs index 237678f5..0c34f7e4 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs @@ -57,6 +57,8 @@ impl<'a> Lowerer<'a> { let mut struct_slots = HashMap::new(); struct_slots.insert("Color".to_string(), 1); struct_slots.insert("ButtonState".to_string(), 4); + // New service-based input returns `Button` (same layout as legacy ButtonState: 4 slots) + struct_slots.insert("Button".to_string(), 4); struct_slots.insert("Pad".to_string(), 48); struct_slots.insert("Touch".to_string(), 6); @@ -564,7 +566,46 @@ impl<'a> Lowerer<'a> { fn lower_block(&mut self, _node: NodeId, n: &BlockNodeArena) -> Result<(), ()> { self.local_vars.push(HashMap::new()); for stmt in &n.stmts { + // Lower the statement normally self.lower_node(*stmt)?; + + // Guardrail: if the statement is a standalone Call that returns values, + // discard them to keep the stack balanced. This is essential for host + // contract calls that return multi-slot structs (e.g., Button=4 slots). + if let NodeKind::Call(call) = self.arena.kind(*stmt) { + // Try to compute return slots conservatively + let mut return_slots: u32 = 0; + + match self.arena.kind(call.callee) { + NodeKind::MemberAccess(ma) => { + // Static contract call: Contract.method(...) + if let NodeKind::Ident(obj_id) = self.arena.kind(ma.object) { + let contract_name = self.interner.resolve(obj_id.name); + let method_name = self.interner.resolve(ma.member); + if let Some(method) = self.contract_registry.get_method(contract_name, method_name) { + let ty = self.convert_pbs_type(&method.return_type); + return_slots = self.get_type_slots(&ty); + } + } + } + NodeKind::Ident(id_node) => { + // Calling a local function or imported symbol — attempt best effort via symbol table + let callee_name = self.interner.resolve(id_node.name).to_string(); + if let Some(func_id) = self.function_ids.get(&callee_name) { + let _ = func_id; // unresolved return info in v0 → assume 0 (no discard) + } else { + // ImportCall or unknown — assume 0 (safe) + } + } + _ => {} + } + + if return_slots > 0 { + for _ in 0..return_slots { + self.emit(InstrKind::Pop); + } + } + } } if let Some(tail) = n.tail { self.lower_node(tail)?; @@ -585,10 +626,16 @@ impl<'a> Lowerer<'a> { if let NodeKind::Ident(obj) = self.arena.kind(ma.object) { let obj_name = self.interner.resolve(obj.name); let member_name = self.interner.resolve(ma.member); - match (obj_name, member_name) { - ("Input", "pad") => Type::Struct("Pad".to_string()), - ("Input", "touch") => Type::Struct("Touch".to_string()), - _ => Type::Int, + // 1) Prefer exact contract registry mapping (Pad/Touch services, etc.) + if let Some(method) = self.contract_registry.get_method(obj_name, member_name) { + self.convert_pbs_type(&method.return_type) + } else { + // 2) Legacy snapshot helpers + match (obj_name, member_name) { + ("Input", "pad") => Type::Struct("Pad".to_string()), + ("Input", "touch") => Type::Struct("Touch".to_string()), + _ => Type::Int, + } } } else { Type::Int @@ -747,6 +794,39 @@ impl<'a> Lowerer<'a> { return Ok(()); } + // Fallback: Handle member access where the object is a Call to a host contract method + // Example: Pad.a().down — object is a Call(MemberAccess(Pad, a)) + if let NodeKind::Call(call_node) = self.arena.kind(n.object) { + if let NodeKind::MemberAccess(inner_ma) = self.arena.kind(call_node.callee) { + if let NodeKind::Ident(obj_id) = self.arena.kind(inner_ma.object) { + let contract_name = self.interner.resolve(obj_id.name); + let method_name = self.interner.resolve(inner_ma.member); + if let Some(method) = self.contract_registry.get_method(contract_name, method_name) { + // Determine return type and slots + let ret_ty = self.convert_pbs_type(&method.return_type); + let slots = self.get_type_slots(&ret_ty); + if let Type::Struct(struct_name) = &ret_ty { + // Lower the call to push all slots + self.lower_call(n.object, &call_node)?; + // Store into a temp local to avoid leaving extra slots on the operand stack + let tmp_slot = self.add_local_to_scope( + format!("$tmp_{}", self.get_next_local_slot()), + ret_ty.clone(), + ); + for i in (0..slots).rev() { + self.emit(InstrKind::SetLocal(tmp_slot + i)); + } + // Load only the requested field + let field_name = self.interner.resolve(n.member); + let field_off = self.get_field_offset(struct_name, field_name); + self.emit(InstrKind::GetLocal(tmp_slot + field_off)); + return Ok(()); + } + } + } + } + } + Ok(()) } @@ -789,6 +869,14 @@ impl<'a> Lowerer<'a> { } } match struct_name { + // New `Button` mirrors legacy `ButtonState` offsets + "Button" => match field_name { + "pressed" => 0, + "released" => 1, + "down" => 2, + "hold_frames" => 3, + _ => 0, + }, "ButtonState" => match field_name { "pressed" => 0, "released" => 1, @@ -828,13 +916,20 @@ impl<'a> Lowerer<'a> { } } match struct_name { - "Pad" => Type::Struct("ButtonState".to_string()), + // Pad's per-button service returns a `Button` in the new API + "Pad" => Type::Struct("Button".to_string()), + // Field types for `Button` mirror legacy `ButtonState` + "Button" => match field_name { + "hold_frames" => Type::Bounded, + _ => Type::Bool, + }, "ButtonState" => match field_name { "hold_frames" => Type::Bounded, _ => Type::Bool, }, "Touch" => match field_name { - "f" => Type::Struct("ButtonState".to_string()), + // Touch.f() now returns a `Button` + "f" => Type::Struct("Button".to_string()), _ => Type::Int, }, _ => Type::Int, @@ -943,6 +1038,46 @@ impl<'a> Lowerer<'a> { } } NodeKind::MemberAccess(ma) => { + // Special-case: Member access over a call expression that returns a struct from a host contract, + // e.g., Pad.a().down — we must: + // 1) lower the call (pushing all struct slots), + // 2) store it into a temporary local (all slots), + // 3) load only the requested field slot back to the stack. + if let NodeKind::Call(call_node) = self.arena.kind(ma.object) { + // Try to resolve if callee is a host contract method to infer return struct and slots + if let NodeKind::MemberAccess(inner_ma) = self.arena.kind(call_node.callee) { + if let NodeKind::Ident(obj_id) = self.arena.kind(inner_ma.object) { + let contract_name = self.interner.resolve(obj_id.name); + let method_name = self.interner.resolve(inner_ma.member); + if let Some(method) = self.contract_registry.get_method(contract_name, method_name) { + // Determine slots from the declared return type BEFORE lowering the call + let ret_ty = self.convert_pbs_type(&method.return_type); + let slots = self.get_type_slots(&ret_ty); + let struct_name = match &ret_ty { Type::Struct(s) => s.clone(), _ => String::new() }; + + // Lower the call first (this will push all return slots from HostCall) + self.lower_call(n.callee, &call_node)?; + + // Allocate a temp local to capture the struct + let tmp_slot = self.add_local_to_scope( + format!("$tmp_{}", self.get_next_local_slot()), + ret_ty.clone(), + ); + // Store all slots (top of stack has the last slot). We must store in reverse order. + for i in (0..slots).rev() { + self.emit(InstrKind::SetLocal(tmp_slot + i)); + } + + // Compute field offset/type and load only that field + let field_name = self.interner.resolve(ma.member); + let field_off = self.get_field_offset(&struct_name, field_name); + let _field_ty = self.get_field_type(&struct_name, field_name); + self.emit(InstrKind::GetLocal(tmp_slot + field_off)); + return Ok(()); + } + } + } + } // Check if it's a constructor alias: TypeName.Alias(...) let ctor = if let NodeKind::Ident(obj_id) = self.arena.kind(ma.object) { let obj_name = self.interner.resolve(obj_id.name); @@ -995,10 +1130,17 @@ impl<'a> Lowerer<'a> { } if let Some(method) = self.contract_registry.get_method(obj_name, member_name) { let id = method.id; - let return_slots = if matches!(method.return_type, PbsType::Void) { - 0 - } else { - 1 + // Compute return slots from declared return type. Structs may span >1 slot (e.g., Button=4) + let return_slots = match &method.return_type { + PbsType::Void | PbsType::None => 0, + PbsType::Struct(name) => { + // Prefer builtin struct slots, then fallback to struct_slots map, default 1 + if let Some(bi) = self.get_builtin_struct_slots(name) { bi } else { *self.struct_slots.get(name).unwrap_or(&1) } + } + other => { + let ty = self.convert_pbs_type(other); + self.get_type_slots(&ty) + } }; self.emit(InstrKind::HostCall(id, return_slots)); return Ok(()); diff --git a/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs b/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs index f5ec6e71..a840a163 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/typecheck.rs @@ -362,7 +362,8 @@ impl<'a> TypeChecker<'a> { _ => {} } } - "ButtonState" => { + // New `Button` mirrors legacy `ButtonState` for field typing + "Button" | "ButtonState" => { match member_str { "pressed" | "released" | "down" => return PbsType::Bool, "hold_frames" => return PbsType::Bounded, @@ -372,7 +373,7 @@ impl<'a> TypeChecker<'a> { "Pad" => { match member_str { "up" | "down" | "left" | "right" | "a" | "b" | "x" | "y" | "l" | "r" | "start" | "select" => { - return PbsType::Struct("ButtonState".to_string()); + return PbsType::Struct("Button".to_string()); } "any" => { return PbsType::Function { @@ -385,7 +386,7 @@ impl<'a> TypeChecker<'a> { } "Touch" => { match member_str { - "f" => return PbsType::Struct("ButtonState".to_string()), + "f" => return PbsType::Struct("Button".to_string()), "x" | "y" => return PbsType::Int, _ => {} } diff --git a/crates/prometeu-hardware-contract/src/lib.rs b/crates/prometeu-hardware-contract/src/lib.rs index 9d6b63ab..2e677269 100644 --- a/crates/prometeu-hardware-contract/src/lib.rs +++ b/crates/prometeu-hardware-contract/src/lib.rs @@ -4,11 +4,11 @@ pub mod gfx_bridge; pub mod hardware_bridge; pub mod host_context; pub mod host_return; -pub mod input_signals; pub mod native_interface; pub mod pad_bridge; pub mod touch_bridge; pub mod native_helpers; +pub mod input_signals; pub use asset_bridge::AssetBridge; pub use audio_bridge::{AudioBridge, LoopMode}; diff --git a/crates/prometeu-hardware/Cargo.toml b/crates/prometeu-hardware/Cargo.toml index fdebbcd5..430a69ce 100644 --- a/crates/prometeu-hardware/Cargo.toml +++ b/crates/prometeu-hardware/Cargo.toml @@ -5,11 +5,7 @@ edition = "2024" license.workspace = true [dependencies] -serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" prometeu-vm = { path = "../prometeu-vm" } -prometeu-kernel = { path = "../prometeu-kernel" } -prometeu-bytecode = { path = "../prometeu-bytecode" } prometeu-abi = { path = "../prometeu-abi" } prometeu-hardware-contract = { path = "../prometeu-hardware-contract" } -url = "2.5.8" \ No newline at end of file diff --git a/crates/prometeu-hardware/src/lib.rs b/crates/prometeu-hardware/src/lib.rs index 3b7318dc..deb14174 100644 --- a/crates/prometeu-hardware/src/lib.rs +++ b/crates/prometeu-hardware/src/lib.rs @@ -10,5 +10,4 @@ pub use crate::asset::AssetManager; pub use crate::audio::{Audio, AudioCommand, Channel, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; pub use crate::gfx::Gfx; pub use crate::memory_banks::MemoryBanks; -pub use crate::pad::Pad; -pub use crate::touch::Touch; \ No newline at end of file +pub use crate::pad::Pad; \ No newline at end of file diff --git a/crates/prometeu-hardware/src/touch.rs b/crates/prometeu-hardware/src/touch.rs index 6be1af58..b1a61248 100644 --- a/crates/prometeu-hardware/src/touch.rs +++ b/crates/prometeu-hardware/src/touch.rs @@ -1,4 +1,4 @@ -use prometeu_abi::model::Button; +use prometeu_abi::model::{Button}; use prometeu_hardware_contract::{InputSignals, TouchBridge}; #[derive(Default, Clone, Copy, Debug)] @@ -8,13 +8,6 @@ pub struct Touch { pub y: i32, } -impl TouchBridge for Touch { - fn begin_frame(&mut self, signals: &InputSignals) { self.begin_frame(signals) } - fn f(&self) -> &Button { &self.f } - fn x(&self) -> i32 { self.x } - fn y(&self) -> i32 { self.y } -} - impl Touch { /// Transient flags should last only 1 frame. pub fn begin_frame(&mut self, signals: &InputSignals) { @@ -23,3 +16,10 @@ impl Touch { self.y = signals.y_pos.clone(); } } + +impl TouchBridge for Touch { + fn begin_frame(&mut self, signals: &InputSignals) { self.begin_frame(signals) } + fn f(&self) -> &Button { &self.f } + fn x(&self) -> i32 { self.x } + fn y(&self) -> i32 { self.y } +} \ No newline at end of file diff --git a/crates/prometeu-kernel/src/prometeu_os.rs b/crates/prometeu-kernel/src/prometeu_os.rs index a64ffa4a..04162930 100644 --- a/crates/prometeu-kernel/src/prometeu_os.rs +++ b/crates/prometeu-kernel/src/prometeu_os.rs @@ -1066,6 +1066,15 @@ impl NativeInterface for PrometeuOS { ret.push_int(hw.touch().f().hold_frames as i64); Ok(()) } + Syscall::TouchGetFinger => { + let btn = hw.touch().f(); + // Return as 4 slots to mirror snapshot order + ret.push_bool(btn.pressed); + ret.push_bool(btn.released); + ret.push_bool(btn.down); + ret.push_int(btn.hold_frames as i64); + Ok(()) + } Syscall::InputPadSnapshot => { let pad = hw.pad(); for btn in [ @@ -1091,6 +1100,104 @@ impl NativeInterface for PrometeuOS { Ok(()) } + // --- Pad per-button service-based syscalls (return Button as 4 slots) --- + Syscall::PadGetUp => { + let b = hw.pad().up(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetDown => { + let b = hw.pad().down(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetLeft => { + let b = hw.pad().left(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetRight => { + let b = hw.pad().right(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetA => { + let b = hw.pad().a(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetB => { + let b = hw.pad().b(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetX => { + let b = hw.pad().x(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetY => { + let b = hw.pad().y(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetL => { + let b = hw.pad().l(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetR => { + let b = hw.pad().r(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetStart => { + let b = hw.pad().start(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + Syscall::PadGetSelect => { + let b = hw.pad().select(); + ret.push_bool(b.pressed); + ret.push_bool(b.released); + ret.push_bool(b.down); + ret.push_int(b.hold_frames as i64); + Ok(()) + } + // --- Audio Syscalls --- // audio.play_sample(sample_id, voice_id, volume, pan, pitch) diff --git a/test-cartridges/sdk/src/main/modules/gfx/color.pbs b/test-cartridges/sdk/src/main/modules/gfx/color.pbs new file mode 100644 index 00000000..f17de0c8 --- /dev/null +++ b/test-cartridges/sdk/src/main/modules/gfx/color.pbs @@ -0,0 +1,8 @@ +pub declare struct Color(raw: bounded) +[[ + BLACK: Color(0b), + WHITE: Color(65535b), + RED: Color(63488b), + GREEN: Color(2016b), + BLUE: Color(31b) +]] \ No newline at end of file diff --git a/test-cartridges/sdk/src/main/modules/gfx/gfx.pbs b/test-cartridges/sdk/src/main/modules/gfx/gfx.pbs index e1fb5488..5e584b6c 100644 --- a/test-cartridges/sdk/src/main/modules/gfx/gfx.pbs +++ b/test-cartridges/sdk/src/main/modules/gfx/gfx.pbs @@ -1,12 +1,3 @@ -pub declare struct Color(raw: bounded) -[[ - BLACK: Color(0b), - WHITE: Color(65535b), - RED: Color(63488b), - GREEN: Color(2016b), - BLUE: Color(31b) -]] - pub declare contract Gfx host { fn clear(color: Color): void; } \ No newline at end of file diff --git a/test-cartridges/sdk/src/main/modules/input/button.pbs b/test-cartridges/sdk/src/main/modules/input/button.pbs new file mode 100644 index 00000000..56c8f6e0 --- /dev/null +++ b/test-cartridges/sdk/src/main/modules/input/button.pbs @@ -0,0 +1,6 @@ +pub declare struct Button( + pressed: bool, + released: bool, + down: bool, + hold_frames: bounded +) \ No newline at end of file diff --git a/test-cartridges/sdk/src/main/modules/input/input.pbs b/test-cartridges/sdk/src/main/modules/input/input.pbs index 98c33154..9ed46967 100644 --- a/test-cartridges/sdk/src/main/modules/input/input.pbs +++ b/test-cartridges/sdk/src/main/modules/input/input.pbs @@ -1,25 +1,20 @@ -pub declare struct ButtonState( - pressed: bool, - released: bool, - down: bool, - hold_frames: bounded -) +pub declare contract Pad host { + fn up(): Button; + fn down(): Button; + fn left(): Button; + fn right(): Button; + fn a(): Button; + fn b(): Button; + fn x(): Button; + fn y(): Button; + fn l(): Button; + fn r(): Button; + fn start(): Button; + fn select(): Button; +} -pub declare struct Pad( - up: ButtonState, - down: ButtonState, - left: ButtonState, - right: ButtonState, - a: ButtonState, - b: ButtonState, - x: ButtonState, - y: ButtonState, - l: ButtonState, - r: ButtonState, - start: ButtonState, - select: ButtonState -) - -pub declare contract Input host { - fn pad(): Pad; +pub declare contract Touch host { + fn screen_x(): int; + fn screen_y(): int; + fn finger(): Button; } \ No newline at end of file diff --git a/test-cartridges/test01/cartridge/program.pbc b/test-cartridges/test01/cartridge/program.pbc index e9d748829762321f9afeb37004426d2128a91403..fe796d272ee282677fd3df22885c61f630ecea63 100644 GIT binary patch literal 1723 zcmZvcO-NKx6vyw3rsYQtR)QdEB2g|>L|dqV%z%q>F=mBDABr=hg4!?^2$2QVCJI`# zjG%B)6jGK#8D!t9A`M08gBERqR?)&1VZU=c6K@_p_}}~goqNui_wIf3qTwzl*E${l zKO82!0|n3p6hlGu9Ze9-V!ljZ6_bs>l;d0-v-S*>~tI~D4Opa(>SjUj&?DFMAwceZ8$vw)i zMXa+-Yh5GSAu}$w8rALb{&G||DQbPBTS&JvqGL$&BUUBb99Eyc7un#jc38XTdaCXb z3%cu!rS5C4b4eFsD}(O2M%+qfBav#Fy@aK{I zT6$fWhf{uvpF<_aFYqr>nP**CUPq~)!oNb*#`E|ERAan^Uq$T$MN!JfW5#`~ zji7NKUo=j#b_!kb@lE6Xter-;jBn%bph@E!_`B$#@gw{!dTe|j{{+n$zs0{puZ`d1 z=h1@kGyDg%Y`lX1jbu+`zy9D?(KpY!@K57<{vIue7hLnV;agEQXD0PW@ClS>+=cH) zCB~EZX;fxBfuBKDKHl!*S|2wWzoB*!H5Oy5>T=*MGl z^w_{)|3Ey&k!U_^4U!|@s6?uFI4(`(Gjkx`*HGIZKhZ5K-oQaA%_tF&|MO_7uWq<^ RaHMYdc-8?rl zi`cB5&M>f^&lJ+-iGSyiE>g(N!`TA5oSu3>`+IH_mpQ1}zZWiWP-lqUb1_C;LS3Sq zglEaeRFUlxz)~j4eXWtcfi-B&iqRvC<2~IAY=g1Q*9-L=0D165x8Hx=`lzwbwmhf)MT z^nHI%4Nn;Nyi(S|d7)X_P_-N4tmJm&y%6ujZzuDP$v2U2L3~Q`9pt+ZSH^EAbJfTf zkncgUPmV}8@^gs0!}gcRuOaRzneAlmJUJDX29-NbM;-z#b^IHBGr-FoXCY@p{4}DF zw@@#%#_bM4N4N$w`LykA2Z5MRJ@EOM; zw6#L#9iK%$2l1Xz$O%{nbk*@y5C(3iM&@(;(e@S!h*`W#P2UH~OyAJ9#zk;72B;|k=BP^RM!&$s{{Vx4=1Kqn diff --git a/test-cartridges/test01/src/main/modules/main.pbs b/test-cartridges/test01/src/main/modules/main.pbs index bc375c85..25df192d 100644 --- a/test-cartridges/test01/src/main/modules/main.pbs +++ b/test-cartridges/test01/src/main/modules/main.pbs @@ -1,5 +1,5 @@ import { Color, Gfx } from "@sdk:gfx"; -import { Input } from "@sdk:input"; +import { Pad, Touch } from "@sdk:input"; declare struct Vec2(x: int, y: int) [ @@ -51,8 +51,10 @@ fn frame(): void { } // 4. Input Snapshot & Nested Member Access - let p = Input.pad(); - if p.a.down { + let pad = Pad.a(); + let touch = Touch.finger(); + let is_pressed = pad.down || touch.down; + if is_pressed { Gfx.clear(Color.BLUE); } }