Compare commits
	
		
			2 Commits
		
	
	
		
			v1.42.0_rc
			...
			unlists
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e31ef19d03 | |||
| dcbd55c31e | 
@ -6,8 +6,8 @@ use std::ffi::CString;
 | 
				
			|||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
pub struct KeySym(pub String);
 | 
					pub struct KeySym(pub String);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Use to switch layouts
 | 
					/// Name of a set of buttons displayed at one time within the layout
 | 
				
			||||||
type Level = String;
 | 
					type View = String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Use to send modified keypresses
 | 
					/// Use to send modified keypresses
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
@ -20,12 +20,12 @@ pub enum Modifier {
 | 
				
			|||||||
#[derive(Debug, Clone, PartialEq)]
 | 
					#[derive(Debug, Clone, PartialEq)]
 | 
				
			||||||
pub enum Action {
 | 
					pub enum Action {
 | 
				
			||||||
    /// Switch to this view
 | 
					    /// Switch to this view
 | 
				
			||||||
    SetLevel(Level),
 | 
					    SetView(View),
 | 
				
			||||||
    /// Switch to a view and latch
 | 
					    /// Switch to a view and latch
 | 
				
			||||||
    LockLevel {
 | 
					    LockView {
 | 
				
			||||||
        lock: Level,
 | 
					        lock: View,
 | 
				
			||||||
        /// When unlocked by pressing it or emitting a key
 | 
					        /// When unlocked by pressing it or emitting a key
 | 
				
			||||||
        unlock: Level,
 | 
					        unlock: View,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    /// Set this modifier TODO: release?
 | 
					    /// Set this modifier TODO: release?
 | 
				
			||||||
    SetModifier(Modifier),
 | 
					    SetModifier(Modifier),
 | 
				
			||||||
 | 
				
			|||||||
@ -504,7 +504,7 @@ fn create_action<H: WarningHandler>(
 | 
				
			|||||||
    match submission {
 | 
					    match submission {
 | 
				
			||||||
        SubmitData::Action(
 | 
					        SubmitData::Action(
 | 
				
			||||||
            Action::SetView(view_name)
 | 
					            Action::SetView(view_name)
 | 
				
			||||||
        ) => ::action::Action::SetLevel(
 | 
					        ) => ::action::Action::SetView(
 | 
				
			||||||
            filter_view_name(
 | 
					            filter_view_name(
 | 
				
			||||||
                name, view_name.clone(), &view_names,
 | 
					                name, view_name.clone(), &view_names,
 | 
				
			||||||
                warning_handler,
 | 
					                warning_handler,
 | 
				
			||||||
@ -512,7 +512,7 @@ fn create_action<H: WarningHandler>(
 | 
				
			|||||||
        ),
 | 
					        ),
 | 
				
			||||||
        SubmitData::Action(Action::Locking {
 | 
					        SubmitData::Action(Action::Locking {
 | 
				
			||||||
            lock_view, unlock_view
 | 
					            lock_view, unlock_view
 | 
				
			||||||
        }) => ::action::Action::LockLevel {
 | 
					        }) => ::action::Action::LockView {
 | 
				
			||||||
            lock: filter_view_name(
 | 
					            lock: filter_view_name(
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
                lock_view.clone(),
 | 
					                lock_view.clone(),
 | 
				
			||||||
 | 
				
			|||||||
@ -41,16 +41,43 @@ pub enum PressType {
 | 
				
			|||||||
    Pressed = 1,
 | 
					    Pressed = 1,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub type KeyCode = u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct KeyState {
 | 
					pub struct KeyState {
 | 
				
			||||||
    pub pressed: PressType,
 | 
					    pub pressed: PressType,
 | 
				
			||||||
    pub locked: bool,
 | 
					    pub locked: bool,
 | 
				
			||||||
    /// A cache of raw keycodes derived from Action::Sumbit given a keymap
 | 
					    /// A cache of raw keycodes derived from Action::Sumbit given a keymap
 | 
				
			||||||
    pub keycodes: Vec<u32>,
 | 
					    pub keycodes: Vec<KeyCode>,
 | 
				
			||||||
    /// Static description of what the key does when pressed or released
 | 
					    /// Static description of what the key does when pressed or released
 | 
				
			||||||
    pub action: Action,
 | 
					    pub action: Action,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl KeyState {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn into_activated(self) -> KeyState {
 | 
				
			||||||
 | 
					        match self.action {
 | 
				
			||||||
 | 
					            Action::LockView { lock: _, unlock: _ } => KeyState {
 | 
				
			||||||
 | 
					                locked: self.locked ^ true,
 | 
				
			||||||
 | 
					                ..self
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            _ => self,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn into_switched(self) -> KeyState {
 | 
				
			||||||
 | 
					        use self::PressType::*;
 | 
				
			||||||
 | 
					        KeyState {
 | 
				
			||||||
 | 
					            pressed: match self.pressed {
 | 
				
			||||||
 | 
					                Released => Pressed,
 | 
				
			||||||
 | 
					                Pressed => Released,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            ..self
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generates a mapping where each key gets a keycode, starting from ~~8~~
 | 
					/// Generates a mapping where each key gets a keycode, starting from ~~8~~
 | 
				
			||||||
/// HACK: starting from 9, because 8 results in keycode 0,
 | 
					/// HACK: starting from 9, because 8 results in keycode 0,
 | 
				
			||||||
/// which the compositor likes to discard
 | 
					/// which the compositor likes to discard
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										446
									
								
								src/layout.rs
									
									
									
									
									
								
							
							
						
						
									
										446
									
								
								src/layout.rs
									
									
									
									
									
								
							@ -20,6 +20,7 @@
 | 
				
			|||||||
use std::cell::RefCell;
 | 
					use std::cell::RefCell;
 | 
				
			||||||
use std::collections::{ HashMap, HashSet };
 | 
					use std::collections::{ HashMap, HashSet };
 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
 | 
					use std::fmt;
 | 
				
			||||||
use std::rc::Rc;
 | 
					use std::rc::Rc;
 | 
				
			||||||
use std::vec::Vec;
 | 
					use std::vec::Vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,8 +28,11 @@ use ::action::Action;
 | 
				
			|||||||
use ::float_ord::FloatOrd;
 | 
					use ::float_ord::FloatOrd;
 | 
				
			||||||
use ::keyboard::{ KeyState, PressType };
 | 
					use ::keyboard::{ KeyState, PressType };
 | 
				
			||||||
use ::submission::{ Timestamp, VirtualKeyboard };
 | 
					use ::submission::{ Timestamp, VirtualKeyboard };
 | 
				
			||||||
 | 
					use ::util;
 | 
				
			||||||
 | 
					use ::util::Stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::borrow::Borrow;
 | 
					use std::borrow::Borrow;
 | 
				
			||||||
 | 
					use std::iter::FromIterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
@ -191,10 +195,7 @@ pub mod c {
 | 
				
			|||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_layout_get_current_view(layout: *const Layout) -> *const View {
 | 
					    fn squeek_layout_get_current_view(layout: *const Layout) -> *const View {
 | 
				
			||||||
        let layout = unsafe { &*layout };
 | 
					        let layout = unsafe { &*layout };
 | 
				
			||||||
        let view_name = layout.current_view.clone();
 | 
					        layout.get_current_view().as_ref() as *const View
 | 
				
			||||||
        layout.views.get(&view_name)
 | 
					 | 
				
			||||||
            .expect("Current view doesn't exist")
 | 
					 | 
				
			||||||
            .as_ref() as *const View
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
@ -354,20 +355,25 @@ pub mod c {
 | 
				
			|||||||
            let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
 | 
					            let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
 | 
				
			||||||
            // The list must be copied,
 | 
					            // The list must be copied,
 | 
				
			||||||
            // because it will be mutated in the loop
 | 
					            // because it will be mutated in the loop
 | 
				
			||||||
            for key in layout.pressed_keys.clone() {
 | 
					            let ui_backend = UIBackend {
 | 
				
			||||||
 | 
					                widget_to_layout,
 | 
				
			||||||
 | 
					                keyboard: ui_keyboard,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            let keys = layout.get_pressed_keys();
 | 
				
			||||||
 | 
					            for key in keys {
 | 
				
			||||||
                let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
					                let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
				
			||||||
                ui::release_key(
 | 
					                seat::release_key(
 | 
				
			||||||
                    layout,
 | 
					                    layout,
 | 
				
			||||||
                    &virtual_keyboard,
 | 
					                    &virtual_keyboard,
 | 
				
			||||||
                    &widget_to_layout,
 | 
					                    Some(&ui_backend),
 | 
				
			||||||
                    time,
 | 
					                    time,
 | 
				
			||||||
                    ui_keyboard,
 | 
					                    key,
 | 
				
			||||||
                    key
 | 
					 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// Release all buittons but don't redraw
 | 
					        /// Release all buttons but don't redraw.
 | 
				
			||||||
 | 
					        /// Use for situations where the UI is gone, e.g. unmapped.
 | 
				
			||||||
        #[no_mangle]
 | 
					        #[no_mangle]
 | 
				
			||||||
        pub extern "C"
 | 
					        pub extern "C"
 | 
				
			||||||
        fn squeek_layout_release_all_only(
 | 
					        fn squeek_layout_release_all_only(
 | 
				
			||||||
@ -375,16 +381,18 @@ pub mod c {
 | 
				
			|||||||
            virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
 | 
					            virtual_keyboard: ZwpVirtualKeyboardV1, // TODO: receive a reference to the backend
 | 
				
			||||||
            time: u32,
 | 
					            time: u32,
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            let layout = unsafe { &mut *layout };
 | 
					            let mut layout = unsafe { &mut *layout };
 | 
				
			||||||
            let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
 | 
					            let virtual_keyboard = VirtualKeyboard(virtual_keyboard);
 | 
				
			||||||
            // The list must be copied,
 | 
					            let time = Timestamp(time);
 | 
				
			||||||
            // because it will be mutated in the loop
 | 
					
 | 
				
			||||||
            for key in layout.pressed_keys.clone() {
 | 
					            for key in layout.get_pressed_keys() {
 | 
				
			||||||
                let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
					                let key: &Rc<RefCell<KeyState>> = key.borrow();
 | 
				
			||||||
                layout.release_key(
 | 
					                seat::release_key(
 | 
				
			||||||
 | 
					                    &mut layout,
 | 
				
			||||||
                    &virtual_keyboard,
 | 
					                    &virtual_keyboard,
 | 
				
			||||||
 | 
					                    None, // don't update anything UI related
 | 
				
			||||||
 | 
					                    time,
 | 
				
			||||||
                    &mut key.clone(),
 | 
					                    &mut key.clone(),
 | 
				
			||||||
                    Timestamp(time)
 | 
					 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -448,7 +456,12 @@ pub mod c {
 | 
				
			|||||||
                Point { x: x_widget, y: y_widget }
 | 
					                Point { x: x_widget, y: y_widget }
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            let pressed = layout.pressed_keys.clone();
 | 
					            let ui_backend = UIBackend {
 | 
				
			||||||
 | 
					                keyboard: ui_keyboard,
 | 
				
			||||||
 | 
					                widget_to_layout,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            let pressed = layout.get_pressed_keys();
 | 
				
			||||||
            let state_place = {
 | 
					            let state_place = {
 | 
				
			||||||
                let view = layout.get_current_view();
 | 
					                let view = layout.get_current_view();
 | 
				
			||||||
                let place = view.find_button_by_position(point);
 | 
					                let place = view.find_button_by_position(point);
 | 
				
			||||||
@ -460,18 +473,16 @@ pub mod c {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if let Some((mut state, c_place)) = state_place {
 | 
					            if let Some((mut state, c_place)) = state_place {
 | 
				
			||||||
                let mut found = false;
 | 
					                let mut found = false;
 | 
				
			||||||
                for wrapped_key in pressed {
 | 
					                for key in pressed {
 | 
				
			||||||
                    let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
 | 
					                    if Rc::ptr_eq(&state, &key) {
 | 
				
			||||||
                    if Rc::ptr_eq(&state, &wrapped_key.0) {
 | 
					 | 
				
			||||||
                        found = true;
 | 
					                        found = true;
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        ui::release_key(
 | 
					                        seat::release_key(
 | 
				
			||||||
                            layout,
 | 
					                            layout,
 | 
				
			||||||
                            &virtual_keyboard,
 | 
					                            &virtual_keyboard,
 | 
				
			||||||
                            &widget_to_layout,
 | 
					                            Some(&ui_backend),
 | 
				
			||||||
                            time,
 | 
					                            time,
 | 
				
			||||||
                            ui_keyboard,
 | 
					                            &key,
 | 
				
			||||||
                            key,
 | 
					 | 
				
			||||||
                        );
 | 
					                        );
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -480,15 +491,13 @@ pub mod c {
 | 
				
			|||||||
                    unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) };
 | 
					                    unsafe { eek_gtk_on_button_pressed(c_place, ui_keyboard) };
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                for wrapped_key in pressed {
 | 
					                for key in pressed {
 | 
				
			||||||
                    let key: &Rc<RefCell<KeyState>> = wrapped_key.borrow();
 | 
					                    seat::release_key(
 | 
				
			||||||
                    ui::release_key(
 | 
					 | 
				
			||||||
                        layout,
 | 
					                        layout,
 | 
				
			||||||
                        &virtual_keyboard,
 | 
					                        &virtual_keyboard,
 | 
				
			||||||
                        &widget_to_layout,
 | 
					                        Some(&ui_backend),
 | 
				
			||||||
                        time,
 | 
					                        time,
 | 
				
			||||||
                        ui_keyboard,
 | 
					                        &key,
 | 
				
			||||||
                        key,
 | 
					 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -740,12 +749,32 @@ pub enum ArrangementKind {
 | 
				
			|||||||
    Wide = 1,
 | 
					    Wide = 1,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ViewLockKind {
 | 
				
			||||||
 | 
					    /// Lock gets released the next time something is submitted
 | 
				
			||||||
 | 
					    OneShot,
 | 
				
			||||||
 | 
					    /// Lock persists until the lock button is clicked again
 | 
				
			||||||
 | 
					    Persisting,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct ViewLock {
 | 
				
			||||||
 | 
					    /// Name of the view
 | 
				
			||||||
 | 
					    view: String,
 | 
				
			||||||
 | 
					    /// ID of the lock, for unlocking.
 | 
				
			||||||
 | 
					    /// Ideally unique within the layout
 | 
				
			||||||
 | 
					    id: String,
 | 
				
			||||||
 | 
					    kind: ViewLockKind,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: split into sth like
 | 
					// TODO: split into sth like
 | 
				
			||||||
// Arrangement (views) + details (keymap) + State (keys)
 | 
					// Arrangement (views) + details (keymap) + State (keys)
 | 
				
			||||||
/// State of the UI, contains the backend as well
 | 
					/// State of the UI, contains the backend as well
 | 
				
			||||||
pub struct Layout {
 | 
					pub struct Layout {
 | 
				
			||||||
    pub kind: ArrangementKind,
 | 
					    pub kind: ArrangementKind,
 | 
				
			||||||
    pub current_view: String,
 | 
					    /// The view after unlocking all locking view locks.
 | 
				
			||||||
 | 
					    pub base_view: String,
 | 
				
			||||||
 | 
					    /// A stack of views that are locked, later locks with higher indices.
 | 
				
			||||||
 | 
					    /// Setting a view directly discards all.
 | 
				
			||||||
 | 
					    pub locked_views: Stack<ViewLock>,
 | 
				
			||||||
    // Views own the actual buttons which have state
 | 
					    // Views own the actual buttons which have state
 | 
				
			||||||
    // Maybe they should own UI only,
 | 
					    // Maybe they should own UI only,
 | 
				
			||||||
    // and keys should be owned by a dedicated non-UI-State?
 | 
					    // and keys should be owned by a dedicated non-UI-State?
 | 
				
			||||||
@ -755,15 +784,7 @@ pub struct Layout {
 | 
				
			|||||||
    /// xkb keymap applicable to the contained keys. Unchangeable
 | 
					    /// xkb keymap applicable to the contained keys. Unchangeable
 | 
				
			||||||
    pub keymap_str: CString,
 | 
					    pub keymap_str: CString,
 | 
				
			||||||
    // Changeable state
 | 
					    // Changeable state
 | 
				
			||||||
    // a Vec would be enough, but who cares, this will be small & fast enough
 | 
					    // TODO: store clicked buttons per-input point to track dragging.
 | 
				
			||||||
    // TODO: turn those into per-input point *_buttons to track dragging.
 | 
					 | 
				
			||||||
    // The renderer doesn't need the list of pressed keys any more,
 | 
					 | 
				
			||||||
    // because it needs to iterate
 | 
					 | 
				
			||||||
    // through all buttons of the current view anyway.
 | 
					 | 
				
			||||||
    // When the list tracks actual location,
 | 
					 | 
				
			||||||
    // it becomes possible to place popovers and other UI accurately.
 | 
					 | 
				
			||||||
    pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
 | 
					 | 
				
			||||||
    pub locked_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A builder structure for picking up layout data from storage
 | 
					/// A builder structure for picking up layout data from storage
 | 
				
			||||||
@ -772,8 +793,23 @@ pub struct LayoutData {
 | 
				
			|||||||
    pub keymap_str: CString,
 | 
					    pub keymap_str: CString,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
struct NoSuchView;
 | 
					struct NoSuchView;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for NoSuchView {
 | 
				
			||||||
 | 
					    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(out, "No such view")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct NoSuchLock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl fmt::Display for NoSuchLock {
 | 
				
			||||||
 | 
					    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
 | 
				
			||||||
 | 
					        write!(out, "No such lock")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Unfortunately, changes are not atomic due to mutability :(
 | 
					// Unfortunately, changes are not atomic due to mutability :(
 | 
				
			||||||
// An error will not be recoverable
 | 
					// An error will not be recoverable
 | 
				
			||||||
// The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special.
 | 
					// The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special.
 | 
				
			||||||
@ -782,104 +818,122 @@ impl Layout {
 | 
				
			|||||||
    pub fn new(data: LayoutData, kind: ArrangementKind) -> Layout {
 | 
					    pub fn new(data: LayoutData, kind: ArrangementKind) -> Layout {
 | 
				
			||||||
        Layout {
 | 
					        Layout {
 | 
				
			||||||
            kind,
 | 
					            kind,
 | 
				
			||||||
            current_view: "base".to_owned(),
 | 
					            base_view: "base".to_owned(),
 | 
				
			||||||
 | 
					            locked_views: Vec::new(),
 | 
				
			||||||
            views: data.views,
 | 
					            views: data.views,
 | 
				
			||||||
            keymap_str: data.keymap_str,
 | 
					            keymap_str: data.keymap_str,
 | 
				
			||||||
            pressed_keys: HashSet::new(),
 | 
					 | 
				
			||||||
            locked_keys: HashSet::new(),
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn get_current_view(&self) -> &Box<View> {
 | 
					    fn get_current_view(&self) -> &Box<View> {
 | 
				
			||||||
        self.views.get(&self.current_view).expect("Selected nonexistent view")
 | 
					        let view_name = self.locked_views.iter().next_back()
 | 
				
			||||||
 | 
					            .map(|lock| &lock.view)
 | 
				
			||||||
 | 
					            .unwrap_or(&self.base_view);
 | 
				
			||||||
 | 
					        self.views.get(view_name).expect("Selected nonexistent view")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns all keys matching filter, without duplicates
 | 
				
			||||||
 | 
					    fn get_filtered_keys<F>(&self, pred: F) -> Vec<Rc<RefCell<KeyState>>>
 | 
				
			||||||
 | 
					        where F: Fn(&Box<Button>) -> Option<Rc<RefCell<KeyState>>>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let keys = self.views.iter().flat_map(|(_name, view)| {
 | 
				
			||||||
 | 
					            view.rows.iter().flat_map(|row| {
 | 
				
			||||||
 | 
					                row.buttons.iter().filter_map(|x| pred(x))
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        // Key states can be attached to multiple buttons, so duplicates must
 | 
				
			||||||
 | 
					        // be removed
 | 
				
			||||||
 | 
					        let unique: HashSet<util::Pointer<RefCell<KeyState>>>
 | 
				
			||||||
 | 
					            = HashSet::from_iter(
 | 
				
			||||||
 | 
					                keys.map(|key| util::Pointer(key.clone()))
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        unique.into_iter()
 | 
				
			||||||
 | 
					            .map(|ptr| ptr.0)
 | 
				
			||||||
 | 
					            .collect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_pressed_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
 | 
				
			||||||
 | 
					        self.get_filtered_keys(|button| {
 | 
				
			||||||
 | 
					            let pressed = RefCell::borrow(&button.state).pressed;
 | 
				
			||||||
 | 
					            match pressed {
 | 
				
			||||||
 | 
					                PressType::Pressed => Some(button.state.clone()),
 | 
				
			||||||
 | 
					                PressType::Released => None
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
 | 
				
			||||||
 | 
					        self.get_filtered_keys(|button| {
 | 
				
			||||||
 | 
					            let locked = RefCell::borrow(&button.state).locked;
 | 
				
			||||||
 | 
					            match locked {
 | 
				
			||||||
 | 
					                true => Some(button.state.clone()),
 | 
				
			||||||
 | 
					                false => None
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Top oneshot locks can be all removed when a button is pressed
 | 
				
			||||||
 | 
					    fn get_top_oneshot_locks_idx(&self) -> usize {
 | 
				
			||||||
 | 
					        let last_persisting_idx = self.locked_views.iter()
 | 
				
			||||||
 | 
					            .rposition(|lock| match lock.kind {
 | 
				
			||||||
 | 
					                ViewLockKind::Persisting => true,
 | 
				
			||||||
 | 
					                ViewLockKind::OneShot => false,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        match last_persisting_idx {
 | 
				
			||||||
 | 
					            // don't remove the last persisting item
 | 
				
			||||||
 | 
					            Some(idx) => idx + 1,
 | 
				
			||||||
 | 
					            None => 0,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn lock_view(&mut self, view: String, id: String)
 | 
				
			||||||
 | 
					        -> Result<(), NoSuchView>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if self.views.contains_key(&view) {
 | 
				
			||||||
 | 
					            self.locked_views.push(ViewLock {
 | 
				
			||||||
 | 
					                view,
 | 
				
			||||||
 | 
					                id,
 | 
				
			||||||
 | 
					                kind: ViewLockKind::OneShot,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            Ok(())
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Err(NoSuchView)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fn unlock_view(&mut self, id: String) -> Result<(), NoSuchLock> {
 | 
				
			||||||
 | 
					        let lock_idx = self.locked_views.iter()
 | 
				
			||||||
 | 
					            // find the first occurrence: locking the same key multiple times
 | 
				
			||||||
 | 
					            // sounds like not something we want to do
 | 
				
			||||||
 | 
					            .position(|lock| lock.id == id);
 | 
				
			||||||
 | 
					        lock_idx.map(|idx| self.locked_views.truncate(idx))
 | 
				
			||||||
 | 
					            .ok_or(NoSuchLock)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
 | 
					    fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
 | 
				
			||||||
        if self.views.contains_key(&view) {
 | 
					        if self.views.contains_key(&view) {
 | 
				
			||||||
            self.current_view = view;
 | 
					            self.base_view = view;
 | 
				
			||||||
 | 
					            self.locked_views = Vec::new();
 | 
				
			||||||
            Ok(())
 | 
					            Ok(())
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            Err(NoSuchView)
 | 
					            Err(NoSuchView)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn release_key(
 | 
					 | 
				
			||||||
        &mut self,
 | 
					 | 
				
			||||||
        virtual_keyboard: &VirtualKeyboard,
 | 
					 | 
				
			||||||
        mut key: &mut Rc<RefCell<KeyState>>,
 | 
					 | 
				
			||||||
        time: Timestamp,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        if !self.pressed_keys.remove(&::util::Pointer(key.clone())) {
 | 
					 | 
				
			||||||
            eprintln!("Warning: key {:?} was not pressed", key);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        virtual_keyboard.switch(
 | 
					 | 
				
			||||||
            &mut key.borrow_mut(),
 | 
					 | 
				
			||||||
            PressType::Released,
 | 
					 | 
				
			||||||
            time,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        self.set_level_from_press(&mut key);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    fn press_key(
 | 
					    fn press_key(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        virtual_keyboard: &VirtualKeyboard,
 | 
					        virtual_keyboard: &VirtualKeyboard,
 | 
				
			||||||
        key: &mut Rc<RefCell<KeyState>>,
 | 
					        key: &mut Rc<RefCell<KeyState>>,
 | 
				
			||||||
        time: Timestamp,
 | 
					        time: Timestamp,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if !self.pressed_keys.insert(::util::Pointer(key.clone())) {
 | 
					        let mut bkey = key.borrow_mut();
 | 
				
			||||||
            eprintln!("Warning: key {:?} was already pressed", key);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        virtual_keyboard.switch(
 | 
					        virtual_keyboard.switch(
 | 
				
			||||||
            &mut key.borrow_mut(),
 | 
					            &bkey.keycodes,
 | 
				
			||||||
            PressType::Pressed,
 | 
					            PressType::Pressed,
 | 
				
			||||||
            time,
 | 
					            time,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					        bkey.pressed = PressType::Pressed;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn set_level_from_press(&mut self, key: &Rc<RefCell<KeyState>>) {
 | 
					 | 
				
			||||||
        let keys = self.locked_keys.clone();
 | 
					 | 
				
			||||||
        for key in &keys {
 | 
					 | 
				
			||||||
            self.locked_keys.remove(key);
 | 
					 | 
				
			||||||
            self.set_state_from_press(key.borrow());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Don't handle the same key twice, but handle it at least once,
 | 
					 | 
				
			||||||
        // because its press is the reason we're here
 | 
					 | 
				
			||||||
        if !keys.contains(&::util::Pointer(key.clone())) {
 | 
					 | 
				
			||||||
            self.set_state_from_press(key);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn set_state_from_press(&mut self, key: &Rc<RefCell<KeyState>>) {
 | 
					 | 
				
			||||||
        // Action should not hold a reference to key,
 | 
					 | 
				
			||||||
        // because key is later borrowed for mutation. So action is cloned.
 | 
					 | 
				
			||||||
        // RefCell::borrow() is covered up by (dyn Borrow)::borrow()
 | 
					 | 
				
			||||||
        // if used like key.borrow() :(
 | 
					 | 
				
			||||||
        let action = RefCell::borrow(key).action.clone();
 | 
					 | 
				
			||||||
        let view_name = match action {
 | 
					 | 
				
			||||||
            Action::SetLevel(name) => {
 | 
					 | 
				
			||||||
                Some(name.clone())
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            Action::LockLevel { lock, unlock } => {
 | 
					 | 
				
			||||||
                let locked = {
 | 
					 | 
				
			||||||
                    let mut key = key.borrow_mut();
 | 
					 | 
				
			||||||
                    key.locked ^= true;
 | 
					 | 
				
			||||||
                    key.locked
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if locked {
 | 
					 | 
				
			||||||
                    self.locked_keys.insert(::util::Pointer(key.clone()));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Some(if locked { lock } else { unlock }.clone())
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            _ => None,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if let Some(view_name) = view_name {
 | 
					 | 
				
			||||||
            if let Err(_e) = self.set_view(view_name.clone()) {
 | 
					 | 
				
			||||||
                eprintln!("No such view: {}, ignoring switch", view_name)
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -924,8 +978,7 @@ mod procedures {
 | 
				
			|||||||
        key: &Rc<RefCell<KeyState>>,
 | 
					        key: &Rc<RefCell<KeyState>>,
 | 
				
			||||||
        ui_keyboard: c::EekGtkKeyboard,
 | 
					        ui_keyboard: c::EekGtkKeyboard,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let paths = ::layout::procedures::find_key_paths(&view, key);
 | 
					        for (_row, button) in find_key_paths(&view, key) {
 | 
				
			||||||
        for (_row, button) in paths {
 | 
					 | 
				
			||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                c::procedures::eek_gtk_on_button_released(
 | 
					                c::procedures::eek_gtk_on_button_released(
 | 
				
			||||||
                    button.as_ref() as *const Button,
 | 
					                    button.as_ref() as *const Button,
 | 
				
			||||||
@ -1012,45 +1065,150 @@ mod procedures {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct UIBackend {
 | 
				
			||||||
 | 
					    widget_to_layout: c::procedures::Transformation,
 | 
				
			||||||
 | 
					    keyboard: c::EekGtkKeyboard,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Top level UI procedures
 | 
					/// Top level UI procedures
 | 
				
			||||||
mod ui {
 | 
					mod seat {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Only use from release_key for when the view switch is ignored
 | 
				
			||||||
 | 
					    fn set_all_unlocked(layout: &mut Layout) {
 | 
				
			||||||
 | 
					        for key in layout.get_locked_keys() {
 | 
				
			||||||
 | 
					            let mut key = RefCell::borrow_mut(&key);
 | 
				
			||||||
 | 
					            match &key.action {
 | 
				
			||||||
 | 
					                Action::LockView { lock: _, unlock: _ } => {},
 | 
				
			||||||
 | 
					                a => eprintln!(
 | 
				
			||||||
 | 
					                    "BUG: action {:?} was found inside locked keys",
 | 
				
			||||||
 | 
					                    a
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            key.locked = false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Only use from release_key. Changes state of other keys only.
 | 
				
			||||||
 | 
					    fn handle_set_view(layout: &mut Layout, view_name: String) {
 | 
				
			||||||
 | 
					        set_all_unlocked(layout);
 | 
				
			||||||
 | 
					        layout.set_view(view_name.clone())
 | 
				
			||||||
 | 
					            .map_err(|e|
 | 
				
			||||||
 | 
					                eprintln!("Bad view {} ({}), ignoring", view_name, e)
 | 
				
			||||||
 | 
					            ).ok();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fn handle_unstick_locks(layout: &mut Layout) {
 | 
				
			||||||
 | 
					        let oneshot_idx = layout.get_top_oneshot_locks_idx();
 | 
				
			||||||
 | 
					        let (_permalocks, onetimes) = layout.locked_views.split_at(oneshot_idx);
 | 
				
			||||||
 | 
					        // Convert into a hashmap for easier finding of elements
 | 
				
			||||||
 | 
					        let onetime_ids = HashSet::<&String>::from_iter(
 | 
				
			||||||
 | 
					            onetimes.into_iter().map(|lock| &lock.id)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        for key in layout.get_locked_keys() {
 | 
				
			||||||
 | 
					            let mut key = RefCell::borrow_mut(&key);
 | 
				
			||||||
 | 
					            match &key.action {
 | 
				
			||||||
 | 
					                Action::LockView { lock: _, unlock: id } => {
 | 
				
			||||||
 | 
					                    if onetime_ids.contains(id) {
 | 
				
			||||||
 | 
					                        key.locked = false;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                a => eprintln!(
 | 
				
			||||||
 | 
					                    "BUG: action {:?} was found inside locked keys",
 | 
				
			||||||
 | 
					                    a
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        layout.locked_views.truncate(oneshot_idx);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: turn into release_button
 | 
					    // TODO: turn into release_button
 | 
				
			||||||
    pub fn release_key(
 | 
					    pub fn release_key(
 | 
				
			||||||
        layout: &mut Layout,
 | 
					        layout: &mut Layout,
 | 
				
			||||||
        virtual_keyboard: &VirtualKeyboard,
 | 
					        virtual_keyboard: &VirtualKeyboard,
 | 
				
			||||||
        widget_to_layout: &c::procedures::Transformation,
 | 
					        ui: Option<&UIBackend>,
 | 
				
			||||||
        time: Timestamp,
 | 
					        time: Timestamp,
 | 
				
			||||||
        ui_keyboard: c::EekGtkKeyboard,
 | 
					        rckey: &Rc<RefCell<KeyState>>,
 | 
				
			||||||
        key: &Rc<RefCell<KeyState>>,
 | 
					 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        layout.release_key(virtual_keyboard, &mut key.clone(), time);
 | 
					        let key: KeyState = {
 | 
				
			||||||
 | 
					            RefCell::borrow(rckey).clone()
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let action = key.action.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let view = layout.get_current_view();
 | 
					        // update
 | 
				
			||||||
        let action = RefCell::borrow(key).action.clone();
 | 
					        let key = key.into_switched();
 | 
				
			||||||
        if let Action::ShowPreferences = action {
 | 
					        let key = match action {
 | 
				
			||||||
            let paths = ::layout::procedures::find_key_paths(
 | 
					            Action::LockView { lock: _, unlock: _ } => key.into_activated(),
 | 
				
			||||||
                view, key
 | 
					            _ => key,
 | 
				
			||||||
            );
 | 
					        };
 | 
				
			||||||
            // getting first item will cause mispositioning
 | 
					
 | 
				
			||||||
            // with more than one button with the same key
 | 
					        // process changes
 | 
				
			||||||
            // on the keyboard
 | 
					        match action {
 | 
				
			||||||
            if let Some((row, button)) = paths.get(0) {
 | 
					            Action::Submit { text: _, keys: _ } => {
 | 
				
			||||||
                let bounds = ::layout::procedures::get_button_bounds(
 | 
					                handle_unstick_locks(layout);
 | 
				
			||||||
                    view, row, button
 | 
					                virtual_keyboard.switch(
 | 
				
			||||||
                ).unwrap_or_else(|| {
 | 
					                    &key.keycodes,
 | 
				
			||||||
                    eprintln!("BUG: Clicked button has no position?");
 | 
					                    PressType::Released,
 | 
				
			||||||
                    c::Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 }
 | 
					                    time,
 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                ::popover::show(
 | 
					 | 
				
			||||||
                    ui_keyboard,
 | 
					 | 
				
			||||||
                    widget_to_layout.reverse_bounds(bounds)
 | 
					 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }
 | 
					            Action::SetView(view) => {
 | 
				
			||||||
        
 | 
					                handle_set_view(layout, view)
 | 
				
			||||||
        procedures::release_ui_buttons(view, key, ui_keyboard);
 | 
					            },
 | 
				
			||||||
 | 
					            Action::LockView { lock, unlock } => {
 | 
				
			||||||
 | 
					                // The button that triggered this will be in the right state
 | 
				
			||||||
 | 
					                // due to commit at the end.
 | 
				
			||||||
 | 
					                set_all_unlocked(layout);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                match key.locked {
 | 
				
			||||||
 | 
					                    true => {
 | 
				
			||||||
 | 
					                        layout.lock_view(lock.clone(), unlock).map_err(|e|
 | 
				
			||||||
 | 
					                            eprintln!("Bad view {} ({}), ignoring", lock, e)
 | 
				
			||||||
 | 
					                        ).ok();
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    false => {
 | 
				
			||||||
 | 
					                        layout.unlock_view(unlock.clone()).map_err(|e| {
 | 
				
			||||||
 | 
					                            eprintln!(
 | 
				
			||||||
 | 
					                                "BUG: Bad id {} ({}), resetting locks",
 | 
				
			||||||
 | 
					                                unlock, e
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                            layout.set_view("base".into()).unwrap()
 | 
				
			||||||
 | 
					                        }).ok();
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    // TODO: stuck => stick_view(lock, unlock)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Action::ShowPreferences => if let Some(ui) = &ui {
 | 
				
			||||||
 | 
					                let view = layout.get_current_view();
 | 
				
			||||||
 | 
					                let paths = ::layout::procedures::find_key_paths(
 | 
				
			||||||
 | 
					                    view, &rckey
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                // Getting first item will cause mispositioning
 | 
				
			||||||
 | 
					                // with more than one button with the same key
 | 
				
			||||||
 | 
					                // on the keyboard.
 | 
				
			||||||
 | 
					                if let Some((row, button)) = paths.get(0) {
 | 
				
			||||||
 | 
					                    let bounds = ::layout::procedures::get_button_bounds(
 | 
				
			||||||
 | 
					                        view, row, button
 | 
				
			||||||
 | 
					                    ).unwrap_or_else(|| {
 | 
				
			||||||
 | 
					                        eprintln!("BUG: Clicked button has no position?");
 | 
				
			||||||
 | 
					                        c::Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    ::popover::show(
 | 
				
			||||||
 | 
					                        ui.keyboard,
 | 
				
			||||||
 | 
					                        ui.widget_to_layout.reverse_bounds(bounds)
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            Action::SetModifier(_) => eprintln!("Modifiers unsupported"),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        //layout.release_key(virtual_keyboard, &mut key.clone(), time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(ui) = ui {
 | 
				
			||||||
 | 
					            let view = layout.get_current_view();
 | 
				
			||||||
 | 
					            procedures::release_ui_buttons(view, &rckey, ui.keyboard);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        // Commits activated button state changes
 | 
				
			||||||
 | 
					        RefCell::replace(rckey, key);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1065,7 +1223,7 @@ mod test {
 | 
				
			|||||||
            pressed: PressType::Released,
 | 
					            pressed: PressType::Released,
 | 
				
			||||||
            locked: false,
 | 
					            locked: false,
 | 
				
			||||||
            keycodes: Vec::new(),
 | 
					            keycodes: Vec::new(),
 | 
				
			||||||
            action: Action::SetLevel("default".into()),
 | 
					            action: Action::SetView("default".into()),
 | 
				
			||||||
        }))
 | 
					        }))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/*! Managing the events belonging to virtual-keyboard interface. */
 | 
					/*! Managing the events belonging to virtual-keyboard interface. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ::keyboard::{ KeyState, PressType };
 | 
					use ::keyboard::{ KeyCode, PressType };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Gathers stuff defined in C or called by C
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
pub mod c {
 | 
					pub mod c {
 | 
				
			||||||
@ -33,16 +33,14 @@ impl VirtualKeyboard {
 | 
				
			|||||||
    // TODO: split out keyboard state management
 | 
					    // TODO: split out keyboard state management
 | 
				
			||||||
    pub fn switch(
 | 
					    pub fn switch(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        key: &mut KeyState,
 | 
					        keycodes: &Vec<KeyCode>,
 | 
				
			||||||
        action: PressType,
 | 
					        action: PressType,
 | 
				
			||||||
        timestamp: Timestamp,
 | 
					        timestamp: Timestamp,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        key.pressed = action.clone();
 | 
					        let keycodes_count = keycodes.len();
 | 
				
			||||||
 | 
					        for keycode in keycodes.iter() {
 | 
				
			||||||
        let keycodes_count = key.keycodes.len();
 | 
					 | 
				
			||||||
        for keycode in key.keycodes.iter() {
 | 
					 | 
				
			||||||
            let keycode = keycode - 8;
 | 
					            let keycode = keycode - 8;
 | 
				
			||||||
            match (&key.pressed, keycodes_count) {
 | 
					            match (action, keycodes_count) {
 | 
				
			||||||
                // Pressing a key made out of a single keycode is simple:
 | 
					                // Pressing a key made out of a single keycode is simple:
 | 
				
			||||||
                // press on press, release on release.
 | 
					                // press on press, release on release.
 | 
				
			||||||
                (_, 1) => unsafe {
 | 
					                (_, 1) => unsafe {
 | 
				
			||||||
 | 
				
			|||||||
@ -198,6 +198,9 @@ pub trait WarningHandler {
 | 
				
			|||||||
    fn handle(&mut self, warning: &str);
 | 
					    fn handle(&mut self, warning: &str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// TODO: only allow indexing, push, peek, and pop
 | 
				
			||||||
 | 
					pub type Stack<T> = Vec<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user