Skip to content

Commit

Permalink
Initial AccessKit support
Browse files Browse the repository at this point in the history
This change adds initial accessibility support for the winit backend
through use of AccessKit.
  • Loading branch information
tronical committed Jun 13, 2023
1 parent d48e719 commit 965d3c5
Show file tree
Hide file tree
Showing 5 changed files with 494 additions and 5 deletions.
17 changes: 17 additions & 0 deletions helper_crates/vtable/src/vrc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,23 @@ impl<VTable: VTableMetaDropInPlace + 'static> VRc<VTable, Dyn> {
) -> VRcMapped<VTable, MappedType> {
VRcMapped { parent_strong: this.clone(), object: map_fn(Self::borrow_pin(&this)).get_ref() }
}

/// Returns a raw pointer to the inner data structure that holds the reference counted object.
/// This pointer is only valid as long as a `VRc` remains alive.
pub fn as_raw_ptr(&self) -> *const core::ffi::c_void {
self.inner.as_ptr() as _
}

/// Transmutes a raw pointer to VRc's inner data structure back into a VRc. Use in combination
/// with `as_raw_ptr()`.
///
/// Safety: This is highly unsafe. Don't use this unless you're absolutely certain that somebody
/// else is keeping the object alive via a VRc.
pub unsafe fn from_raw_ptr(raw_dyn: *const core::ffi::c_void) -> Self {
let inner: NonNull<VRcInner<'static, VTable, Dyn>> = core::mem::transmute(raw_dyn);
inner.as_ref().strong_ref.fetch_add(1, Ordering::SeqCst);
Self { inner }
}
}
impl<VTable: VTableMetaDropInPlace, X> VRc<VTable, X> {
/// Create a Pinned reference to the inner.
Expand Down
4 changes: 3 additions & 1 deletion internal/backends/winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ winit = { version = "=0.28.6", default-features = false }
instant = "0.1"
raw-window-handle = { version = "0.5", features = ["alloc"] }
scopeguard = { version = "1.1.0", default-features = false }
send_wrapper = { workspace = true }

# For the FemtoVG renderer
i-slint-renderer-femtovg = { version = "=1.0.3", path = "../../renderers/femtovg", optional = true }
Expand All @@ -64,11 +65,12 @@ rgb = { version = "0.8.27", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features=["HtmlInputElement", "HtmlCanvasElement", "Window", "Document", "Event", "KeyboardEvent", "InputEvent", "CompositionEvent", "DomStringMap", "ClipboardEvent", "DataTransfer"] }
wasm-bindgen = { version = "0.2" }
send_wrapper = { workspace = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
glutin = { version = "0.30", optional = true, default-features = false, features = ["egl", "wgl"] }
glutin-winit = { version = "0.3.0", optional = true, default-features = false, features = ["egl", "wgl"] }
accesskit = { version = "0.11.0" }
accesskit_winit = { version = "0.14.0" }

[target.'cfg(target_os = "macos")'.dependencies]
# For GL rendering
Expand Down
13 changes: 11 additions & 2 deletions internal/backends/winit/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,17 @@ pub fn run() -> Result<(), corelib::platform::PlatformError> {
match event {
Event::WindowEvent { event, window_id } => {
if let Some(window) = window_by_id(window_id) {
*inner_event_loop_error.borrow_mut() =
process_window_event(window, event, &mut cursor_pos, &mut pressed).err();
#[cfg(target_arch = "wasm32")]
let process_event = true;
#[cfg(not(target_arch = "wasm32"))]
let process_event =
window.accesskit_adapter.on_event(&window.winit_window(), &event);

if process_event {
*inner_event_loop_error.borrow_mut() =
process_window_event(window, event, &mut cursor_pos, &mut pressed)
.err();
}
};
}

Expand Down
32 changes: 30 additions & 2 deletions internal/backends/winit/winitwindowadapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ use crate::renderer::WinitCompatibleRenderer;
use const_field_offset::FieldOffsets;

use corelib::component::ComponentRc;
use corelib::items::MouseCursor;
#[cfg(not(target_arch = "wasm32"))]
use corelib::component::ComponentRef;
#[cfg(not(target_arch = "wasm32"))]
use corelib::items::ItemRef;
use corelib::items::{ItemRc, MouseCursor};

use corelib::layout::Orientation;
use corelib::lengths::{LogicalLength, LogicalSize};
Expand All @@ -31,6 +35,9 @@ use corelib::{graphics::*, Coord};
use i_slint_core as corelib;
use once_cell::unsync::OnceCell;

#[cfg(not(target_arch = "wasm32"))]
mod accesskit;

fn position_to_winit(pos: &corelib::api::WindowPosition) -> winit::dpi::Position {
match pos {
corelib::api::WindowPosition::Logical(pos) => {
Expand Down Expand Up @@ -118,6 +125,9 @@ pub struct WinitWindowAdapter {

#[cfg(target_arch = "wasm32")]
virtual_keyboard_helper: RefCell<Option<super::wasm_input_helper::WasmInputHelper>>,

#[cfg(not(target_arch = "wasm32"))]
pub accesskit_adapter: accesskit::AccessKitAdapter,
}

impl WinitWindowAdapter {
Expand All @@ -131,6 +141,8 @@ impl WinitWindowAdapter {
)
.and_then(|builder| R::new(builder))?;

let winit_window = Rc::new(winit_window);

let self_rc = Rc::new_cyclic(|self_weak| Self {
window: OnceCell::with_value(corelib::api::Window::new(self_weak.clone() as _)),
#[cfg(target_arch = "wasm32")]
Expand All @@ -140,10 +152,12 @@ impl WinitWindowAdapter {
dark_color_scheme: Default::default(),
constraints: Default::default(),
shown: Default::default(),
winit_window: Rc::new(winit_window),
winit_window: winit_window.clone(),
renderer: Box::new(renderer),
#[cfg(target_arch = "wasm32")]
virtual_keyboard_helper: Default::default(),
#[cfg(not(target_arch = "wasm32"))]
accesskit_adapter: accesskit::AccessKitAdapter::new(self_weak.clone(), &*winit_window),
});

let id = self_rc.winit_window().id();
Expand Down Expand Up @@ -639,6 +653,20 @@ impl WindowAdapterSealed for WinitWindowAdapter {
fn is_visible(&self) -> bool {
self.winit_window().is_visible().unwrap_or(true)
}

fn handle_focus_change(&self, _old: Option<ItemRc>, _new: Option<ItemRc>) {
#[cfg(not(target_arch = "wasm32"))]
self.accesskit_adapter.handle_focus_change(_new);
}

#[cfg(not(target_arch = "wasm32"))]
fn unregister_component<'a>(
&self,
_component: ComponentRef,
_: &mut dyn Iterator<Item = Pin<ItemRef<'a>>>,
) {
self.accesskit_adapter.unregister_component(_component);
}
}

impl Drop for WinitWindowAdapter {
Expand Down
Loading

0 comments on commit 965d3c5

Please sign in to comment.