use super::*;
pub(crate) fn push_input(ptr: *mut KuiCtx, ev: InputEvent) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
let evs = c.core().handle_input(ev);
c.absorb(evs);
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_cursor(ptr: *mut KuiCtx, x: f32, y: f32) {
push_input(ptr, InputEvent::CursorMoved(Vec2::new(x, y)));
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_cursor_left(ptr: *mut KuiCtx) {
push_input(ptr, InputEvent::CursorLeft);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_mouse(ptr: *mut KuiCtx, down: bool, clicks: u32) {
kui_input_mouse_button(ptr, down, MouseButton::Primary.code(), clicks);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_mouse_button(ptr: *mut KuiCtx, down: bool, button: u32, clicks: u32) {
let button = MouseButton::from_code(button);
push_input(
ptr,
if down {
InputEvent::MouseDown {
button,
clicks: clicks.clamp(1, u8::MAX as u32) as u8,
}
} else {
InputEvent::MouseUp { button }
},
);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_scroll(ptr: *mut KuiCtx, dx: f32, dy: f32) {
push_input(ptr, InputEvent::Scroll(Vec2::new(dx, dy)));
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_scroll_gesture(ptr: *mut KuiCtx, dx: f32, dy: f32, begins: bool) {
push_input(
ptr,
InputEvent::ScrollGesture {
delta: Vec2::new(dx, dy),
begins,
},
);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_text(ptr: *mut KuiCtx, text: KuiStr) {
guard((), || {
let text = kstr(text).into_owned();
push_input(ptr, InputEvent::Text(text));
});
}
fn paths_of(paths: *const KuiStr, count: usize) -> Vec<String> {
if paths.is_null() || count == 0 {
return Vec::new();
}
unsafe { std::slice::from_raw_parts(paths, count) }
.iter()
.map(|s| kstr(*s).into_owned())
.collect()
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_drag_files(
ptr: *mut KuiCtx,
paths: *const KuiStr,
count: usize,
x: f32,
y: f32,
) {
guard((), || {
let paths = paths_of(paths, count);
push_input(
ptr,
InputEvent::DragFiles {
paths,
at: Vec2::new(x, y),
},
);
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_drop_files(
ptr: *mut KuiCtx,
paths: *const KuiStr,
count: usize,
x: f32,
y: f32,
) {
guard((), || {
let paths = paths_of(paths, count);
push_input(
ptr,
InputEvent::DropFiles {
paths,
at: Vec2::new(x, y),
},
);
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_drag_cancel(ptr: *mut KuiCtx) {
push_input(ptr, InputEvent::DragCancel);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_open(ptr: *mut KuiCtx, paths: *const KuiStr, count: usize) {
guard((), || {
let paths = paths_of(paths, count);
push_input(ptr, InputEvent::Open(paths));
});
}
fn edit_key_of(key: u32) -> Option<EditKey> {
KUI_EDIT_KEYS.get(key as usize).map(|(_, k)| *k)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_modifiers(ptr: *mut KuiCtx, mods: u32) {
push_input(
ptr,
InputEvent::Modifiers(kui_core::KeyMods::from_bits(mods)),
);
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_key(ptr: *mut KuiCtx, key: u32, mods: u32) {
if let Some(k) = edit_key_of(key) {
let mods = Mods {
shift: mods & KUI_MOD_SHIFT != 0,
word: mods & KUI_MOD_WORD != 0,
doc: mods & KUI_MOD_DOC != 0,
};
push_input(ptr, InputEvent::Key(k, mods));
}
}
fn key_press_of(
code: KuiStr,
physical: KuiStr,
kmods: u32,
text: KuiStr,
) -> Option<kui_core::KeyPress> {
let layout = kui_core::KeyCode::from_name(&kstr(code))?;
let mods = kui_core::KeyMods::from_bits(kmods);
let press = match physical.ptr.is_null() {
true => kui_core::KeyPress::new(layout, mods),
false => {
let phys = kui_core::KeyCode::from_name(&kstr(physical))?;
let script = kui_core::LayoutScript::from_bits(kmods);
kui_core::KeyPress::from_layout_in(layout, phys, mods, script)
}
};
let text = match text.ptr.is_null() {
false => Some(kstr(text).into_owned()),
true => layout.typed(mods),
};
Some(kui_core::KeyPress {
text,
location: kui_core::KeyLocation::from_bits(kmods),
locks: kui_core::KeyLocks::from_bits(kmods),
..press
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_key_down(
ptr: *mut KuiCtx,
code: KuiStr,
physical: KuiStr,
kmods: u32,
text: KuiStr,
repeat: bool,
) {
guard((), || {
if let Some(kp) = key_press_of(code, physical, kmods, text) {
push_input(
ptr,
InputEvent::KeyDown(kui_core::KeyPress { repeat, ..kp }),
);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_key_up(ptr: *mut KuiCtx, code: KuiStr, physical: KuiStr, kmods: u32) {
guard((), || {
if let Some(kp) = key_press_of(
code,
physical,
kmods,
KuiStr {
ptr: std::ptr::null(),
len: 0,
},
) {
push_input(ptr, InputEvent::KeyUp(kp.released()));
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_press(
ptr: *mut KuiCtx,
code: KuiStr,
physical: KuiStr,
kmods: u32,
text: KuiStr,
repeat: bool,
) {
guard((), || {
let Some(kp) = key_press_of(code, physical, kmods, text) else {
return;
};
if let Some(c) = unsafe { ctx(ptr) } {
let evs = c.core().press(kui_core::KeyPress { repeat, ..kp });
c.absorb(evs);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_release(ptr: *mut KuiCtx, code: KuiStr, physical: KuiStr, kmods: u32) {
guard((), || {
let Some(kp) = key_press_of(
code,
physical,
kmods,
KuiStr {
ptr: std::ptr::null(),
len: 0,
},
) else {
return;
};
if let Some(c) = unsafe { ctx(ptr) } {
let evs = c.core().release(kp);
c.absorb(evs);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_release_held_keys(ptr: *mut KuiCtx) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().release_held_keys();
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_poll_event(ptr: *mut KuiCtx, out: *mut KuiEvent) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
c.last_payload = None;
let pending = c.core().take_pending_events();
c.absorb(pending);
if c.events.is_empty() || !out_accepts(out) {
return false;
}
let ev = c.events.remove(0);
let payload = Box::new(KuiValue(ev.payload));
let payload_ptr: *const KuiValue = &*payload;
c.last_payload = Some(payload);
write_out(
out,
KuiEvent {
origin: ev.origin.0,
key: ev.key.0,
payload: payload_ptr,
window: ev.window.0,
slot: ev.slot.map_or(0, |k| k.0),
..Default::default()
},
)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_cursor_shape(ptr: *mut KuiCtx) -> u32 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let shape = c.core().cursor_shape();
kui_core::schema::CURSORS
.iter()
.position(|n| *n == shape.name())
.map_or(0, |i| i as u32 + 1)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_commit(ptr: *mut KuiCtx, text: KuiStr) {
guard((), || {
let text = kstr(text).into_owned();
push_input(ptr, InputEvent::Commit(text));
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_paste(ptr: *mut KuiCtx, text: KuiStr, marks: u32) {
guard((), || {
let text = kstr(text).into_owned();
let marks = kui_core::ClipboardMarks::from_bits(marks);
push_input(ptr, InputEvent::Paste { text, marks });
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_input_preedit(
ptr: *mut KuiCtx,
text: KuiStr,
cursor_start: u32,
cursor_end: u32,
) {
guard((), || {
let text = kstr(text).into_owned();
let cursor =
(cursor_start != u32::MAX).then_some((cursor_start as usize, cursor_end as usize));
push_input(ptr, InputEvent::Preedit(text, cursor));
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_edit_text(ptr: *mut KuiCtx, key: u64, out: *mut KuiStr) -> bool {
guard(false, || {
let (Some(c), Some(out)) = (unsafe { ctx(ptr) }, unsafe { out.as_mut() }) else {
return false;
};
let Some(text) = c.core().edit_text(Key(key)) else {
return false;
};
c.last_edit_text = Some(text);
let s = c.last_edit_text.as_ref().unwrap();
*out = KuiStr {
ptr: s.as_ptr(),
len: s.len(),
};
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_edit_set_text(ptr: *mut KuiCtx, key: u64, text: KuiStr) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
let text = kstr(text).into_owned();
c.core().set_edit_text(Key(key), &text);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_edit_set_text_label(ptr: *mut KuiCtx, label: KuiStr, text: KuiStr) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
let label = kstr(label).into_owned();
let text = kstr(text).into_owned();
c.core().set_edit_text_by_label(&label, &text);
}
});
}