// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
type BackendOwner
///|
extern "C" fn backend_new() -> BackendOwner = "moon_gamepad_backend_new"
///|
#borrow(owner)
extern "C" fn backend_poll(owner : BackendOwner) -> Unit = "moon_gamepad_backend_poll"
///|
#borrow(owner)
extern "C" fn backend_poll_timeout(
owner : BackendOwner,
timeout_ms : Int,
) -> Unit = "moon_gamepad_backend_poll_timeout"
///|
#borrow(owner)
extern "C" fn backend_gamepad_count(owner : BackendOwner) -> Int = "moon_gamepad_backend_gamepad_count"
///|
#borrow(owner)
extern "C" fn backend_next_event_bin(owner : BackendOwner) -> Bytes = "moon_gamepad_backend_next_event_bin"
///|
extern "C" fn backend_now_ms() -> Int64 = "moon_gamepad_now_ms"
///|
extern "C" fn backend_env_sdl_gamecontrollerconfig() -> String = "moon_gamepad_env_sdl_gamecontrollerconfig"
///|
extern "C" fn backend_sdl_platform_name() -> String = "moon_gamepad_sdl_platform_name"
///|
#borrow(owner)
extern "C" fn backend_name(owner : BackendOwner, id : Int) -> String = "moon_gamepad_backend_name"
///|
#borrow(owner)
extern "C" fn backend_uuid_simple(owner : BackendOwner, id : Int) -> String = "moon_gamepad_backend_uuid_simple"
///|
#borrow(owner)
extern "C" fn backend_vendor_id(owner : BackendOwner, id : Int) -> Int = "moon_gamepad_backend_vendor_id"
///|
#borrow(owner)
extern "C" fn backend_product_id(owner : BackendOwner, id : Int) -> Int = "moon_gamepad_backend_product_id"
///|
#borrow(owner)
extern "C" fn backend_is_ff_supported(owner : BackendOwner, id : Int) -> Int = "moon_gamepad_backend_is_ff_supported"
///|
#borrow(owner)
extern "C" fn backend_axes_bin(owner : BackendOwner, id : Int) -> Bytes = "moon_gamepad_backend_axes_bin"
///|
#borrow(owner)
extern "C" fn backend_buttons_bin(owner : BackendOwner, id : Int) -> Bytes = "moon_gamepad_backend_buttons_bin"
///|
#borrow(owner)
extern "C" fn backend_axis_info_bin(
owner : BackendOwner,
id : Int,
code : Int,
) -> Bytes = "moon_gamepad_backend_axis_info_bin"
///|
#borrow(owner)
extern "C" fn backend_set_rumble(
owner : BackendOwner,
id : Int,
strong : Double,
weak : Double,
duration_ms : Int,
) -> Int = "moon_gamepad_backend_set_rumble"
///|
pub struct NativeBackend {
owner : BackendOwner
}
///|
pub fn NativeBackend::new() -> NativeBackend {
{ owner: backend_new() }
}
///|
pub fn NativeBackend::poll(self : NativeBackend) -> Unit {
backend_poll(self.owner)
}
///|
pub fn NativeBackend::poll_timeout(
self : NativeBackend,
timeout_ms : Int,
) -> Unit {
backend_poll_timeout(self.owner, timeout_ms)
}
///|
pub fn NativeBackend::gamepad_count(self : NativeBackend) -> Int {
backend_gamepad_count(self.owner)
}
///|
pub fn NativeBackend::next_event(self : NativeBackend) -> NativeEvent? {
let b = backend_next_event_bin(self.owner)
decode_native_event(b)
}
///|
pub fn runtime_now_ms() -> Int64 {
backend_now_ms()
}
///|
pub fn runtime_env_sdl_gamecontrollerconfig() -> String {
backend_env_sdl_gamecontrollerconfig()
}
///|
pub fn runtime_sdl_platform_name() -> String {
backend_sdl_platform_name()
}
///|
pub fn NativeBackend::name(self : NativeBackend, id : Int) -> String {
backend_name(self.owner, id)
}
///|
pub fn NativeBackend::uuid_simple(self : NativeBackend, id : Int) -> String {
backend_uuid_simple(self.owner, id)
}
///|
pub fn NativeBackend::vendor_id(self : NativeBackend, id : Int) -> Int? {
let v = backend_vendor_id(self.owner, id)
if v < 0 {
None
} else {
Some(v)
}
}
///|
pub fn NativeBackend::product_id(self : NativeBackend, id : Int) -> Int? {
let v = backend_product_id(self.owner, id)
if v < 0 {
None
} else {
Some(v)
}
}
///|
pub fn NativeBackend::is_ff_supported(self : NativeBackend, id : Int) -> Bool {
backend_is_ff_supported(self.owner, id) != 0
}
///|
fn read_i32_le(b : Bytes, off : Int) -> Int {
let b0 = b[off + 0].to_int()
let b1 = b[off + 1].to_int()
let b2 = b[off + 2].to_int()
let b3 = b[off + 3].to_int()
b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)
}
///|
fn decode_i32s(b : Bytes) -> Array[Int] {
let out : Array[Int] = []
if b.length() == 0 {
return out
}
let n = b.length() / 4
for i in 0.. Array[Int] {
decode_i32s(backend_axes_bin(self.owner, id))
}
///|
pub fn NativeBackend::buttons(self : NativeBackend, id : Int) -> Array[Int] {
decode_i32s(backend_buttons_bin(self.owner, id))
}
///|
pub fn NativeBackend::axis_info(
self : NativeBackend,
id : Int,
code : Int,
) -> AxisInfo? {
let b = backend_axis_info_bin(self.owner, id, code)
if b.length() < 12 {
return None
}
let present = read_i32_le(b, 0)
if present == 0 {
return None
}
let minv = read_i32_le(b, 4)
let maxv = read_i32_le(b, 8)
Some(AxisInfo::new(minv, maxv, None))
}
///|
pub fn NativeBackend::set_rumble(
self : NativeBackend,
id : Int,
strong : Double,
weak : Double,
duration_ms : Int,
) -> Bool {
backend_set_rumble(self.owner, id, strong, weak, duration_ms) != 0
}