rustdesk/libs/rust-sciter/src/eventhandler.rs
2021-05-23 10:55:19 +08:00

307 lines
7.9 KiB
Rust

use capi::sctypes::*;
use capi::scbehavior::*;
use capi::scdom::{HELEMENT};
use value::Value;
use dom::event::EventHandler;
#[repr(C)]
pub(crate) struct WindowHandler<T>
{
pub hwnd: HWINDOW,
pub handler: T,
}
#[repr(C)]
pub(crate) struct BoxedHandler {
pub handler: Box<dyn EventHandler>,
}
fn is_detach_event(evtg: UINT, params: LPVOID) -> bool {
let evtg : EVENT_GROUPS = unsafe { ::std::mem::transmute(evtg) };
if evtg == EVENT_GROUPS::HANDLE_INITIALIZATION {
assert!(!params.is_null());
let scnm = params as *const INITIALIZATION_EVENTS;
let cmd = unsafe { *scnm };
if cmd == INITIALIZATION_EVENTS::BEHAVIOR_DETACH {
return true;
}
}
false
}
pub(crate) extern "system" fn _event_handler_window_proc<T: EventHandler>(tag: LPVOID, _he: ::capi::scdom::HELEMENT, evtg: UINT, params: LPVOID) -> BOOL
{
let boxed = tag as *mut WindowHandler<T>;
let tuple: &mut WindowHandler<T> = unsafe { &mut *boxed };
let hroot: HELEMENT = if let Ok(root) = ::dom::Element::from_window(tuple.hwnd) {
root.as_ptr()
} else {
::std::ptr::null_mut()
};
// custom initialization (because there is no DOM in plain window)
if is_detach_event(evtg, params) {
tuple.handler.detached(hroot);
// here we drop our tuple
let ptr = unsafe { Box::from_raw(boxed) };
drop(ptr);
return true as BOOL;
}
process_events(&mut tuple.handler, hroot, evtg, params)
}
pub(crate) extern "system" fn _event_handler_behavior_proc(tag: LPVOID, he: HELEMENT, evtg: UINT, params: LPVOID) -> BOOL {
// reconstruct pointer to Handler
let boxed = tag as *mut BoxedHandler;
let me = unsafe { &mut *boxed };
let me = &mut *me.handler;
if is_detach_event(evtg, params) {
me.detached(he);
// here we drop our handler
let ptr = unsafe { Box::from_raw(boxed) };
drop(ptr);
return true as BOOL;
}
process_events(me, he, evtg, params)
}
pub(crate) extern "system" fn _event_handler_proc<T: EventHandler>(tag: LPVOID, he: HELEMENT, evtg: UINT, params: LPVOID) -> BOOL
{
// reconstruct pointer to Handler
let boxed = tag as *mut T;
let me = unsafe { &mut *boxed };
if is_detach_event(evtg, params) {
me.detached(he);
// here we drop our handler
let ptr = unsafe { Box::from_raw(boxed) };
drop(ptr);
return true as BOOL;
}
process_events(me, he, evtg, params)
}
fn process_events(me: &mut dyn EventHandler, he: HELEMENT, evtg: UINT, params: LPVOID) -> BOOL
{
let evtg : EVENT_GROUPS = unsafe { ::std::mem::transmute(evtg) };
if he.is_null()
&& evtg != EVENT_GROUPS::SUBSCRIPTIONS_REQUEST
&& evtg != EVENT_GROUPS::HANDLE_BEHAVIOR_EVENT
&& evtg != EVENT_GROUPS::HANDLE_INITIALIZATION
&& evtg != EVENT_GROUPS::HANDLE_SOM
{
eprintln!("[sciter] warning! null element for {:04X}", evtg as u32);
}
let result = match evtg {
EVENT_GROUPS::SUBSCRIPTIONS_REQUEST => {
assert!(!params.is_null());
let scnm = params as *mut EVENT_GROUPS;
let nm = unsafe {&mut *scnm};
let handled = me.get_subscription();
if let Some(needed) = handled {
*nm = needed;
}
handled.is_some()
},
EVENT_GROUPS::HANDLE_INITIALIZATION => {
assert!(!params.is_null());
let scnm = params as *mut INITIALIZATION_PARAMS;
let nm = unsafe { &mut *scnm };
match nm.cmd {
INITIALIZATION_EVENTS::BEHAVIOR_DETACH => {
me.detached(he);
},
INITIALIZATION_EVENTS::BEHAVIOR_ATTACH => {
me.attached(he);
},
};
true
},
EVENT_GROUPS::HANDLE_SOM => {
assert!(!params.is_null());
let scnm = params as *mut SOM_PARAMS;
let nm = unsafe { &mut *scnm };
match nm.cmd {
SOM_EVENTS::SOM_GET_PASSPORT => {
if let Some(asset) = me.get_asset() {
nm.result.passport = asset.get_passport();
return true as BOOL;
}
},
SOM_EVENTS::SOM_GET_ASSET => {
if let Some(asset) = me.get_asset() {
nm.result.asset = asset;
return true as BOOL;
}
},
};
false
},
EVENT_GROUPS::HANDLE_BEHAVIOR_EVENT => {
assert!(!params.is_null());
let scnm = params as *const BEHAVIOR_EVENT_PARAMS;
let nm = unsafe { &*scnm };
use dom::event::EventReason;
let code :BEHAVIOR_EVENTS = unsafe{ ::std::mem::transmute(nm.cmd & 0x0_0FFF) };
let phase: PHASE_MASK = unsafe { ::std::mem::transmute(nm.cmd & 0xFFFF_F000) };
let reason = match code {
BEHAVIOR_EVENTS::EDIT_VALUE_CHANGED | BEHAVIOR_EVENTS::EDIT_VALUE_CHANGING => {
let reason: EDIT_CHANGED_REASON = unsafe{ ::std::mem::transmute(nm.reason as UINT) };
EventReason::EditChanged(reason)
},
BEHAVIOR_EVENTS::VIDEO_BIND_RQ => {
EventReason::VideoBind(nm.reason as LPVOID)
}
_ => {
let reason: CLICK_REASON = unsafe{ ::std::mem::transmute(nm.reason as UINT) };
EventReason::General(reason)
}
};
if he.is_null() && code != BEHAVIOR_EVENTS::MEDIA_CHANGED {
eprintln!("[sciter] warning! null element for {:?}:{:?}", evtg, code);
}
if phase == PHASE_MASK::SINKING { // catch this only once
match code {
BEHAVIOR_EVENTS::DOCUMENT_COMPLETE => {
me.document_complete(he, nm.heTarget);
},
BEHAVIOR_EVENTS::DOCUMENT_CLOSE => {
me.document_close(he, nm.heTarget);
},
_ => ()
};
}
let handled = me.on_event(he, nm.he, nm.heTarget, code, phase, reason);
handled
},
EVENT_GROUPS::HANDLE_SCRIPTING_METHOD_CALL => {
assert!(!params.is_null());
let scnm = params as *mut SCRIPTING_METHOD_PARAMS;
let nm = unsafe { &mut *scnm };
let name = u2s!(nm.name);
let argv = unsafe { Value::unpack_from(nm.argv, nm.argc) };
let rv = me.on_script_call(he, &name, &argv);
let handled = if let Some(v) = rv {
v.pack_to(&mut nm.result);
true
} else {
false
};
handled
},
EVENT_GROUPS::HANDLE_METHOD_CALL => {
assert!(!params.is_null());
let scnm = params as *const METHOD_PARAMS;
let nm = unsafe { & *scnm };
let code: BEHAVIOR_METHOD_IDENTIFIERS = unsafe { ::std::mem::transmute((*nm).method) };
use capi::scbehavior::BEHAVIOR_METHOD_IDENTIFIERS::*;
// output values
let mut method_value = Value::new();
let mut is_empty = false;
let handled = {
// unpack method parameters
use dom::event::MethodParams;
let reason = match code {
DO_CLICK => {
MethodParams::Click
},
IS_EMPTY => {
MethodParams::IsEmpty(&mut is_empty)
},
GET_VALUE => {
MethodParams::GetValue(&mut method_value)
},
SET_VALUE => {
// Value from Sciter.
let payload = params as *const VALUE_PARAMS;
let pm = unsafe { & *payload };
MethodParams::SetValue(Value::from(&pm.value))
},
_ => {
MethodParams::Custom((*nm).method, params)
},
};
// call event handler
let handled = me.on_method_call(he, reason);
handled
};
if handled {
// Pack values back to Sciter.
match code {
GET_VALUE => {
let payload = params as *mut VALUE_PARAMS;
let pm = unsafe { &mut *payload };
method_value.pack_to(&mut pm.value);
},
IS_EMPTY => {
let payload = params as *mut IS_EMPTY_PARAMS;
let pm = unsafe { &mut *payload };
pm.is_empty = is_empty as UINT;
},
_ => {},
}
}
// we've done here
handled
},
EVENT_GROUPS::HANDLE_TIMER => {
assert!(!params.is_null());
let scnm = params as *const TIMER_PARAMS;
let nm = unsafe { & *scnm };
let handled = me.on_timer(he, nm.timerId as u64);
handled
},
EVENT_GROUPS::HANDLE_DRAW => {
assert!(!params.is_null());
let scnm = params as *const DRAW_PARAMS;
let nm = unsafe { & *scnm };
let handled = me.on_draw(he, nm.gfx, &nm.area, nm.layer);
handled
},
// unknown `EVENT_GROUPS` notification
_ => {
eprintln!("[sciter] warning! unknown event group {:04X}", evtg as u32);
false
},
};
return result as BOOL;
}