use crate ::action ::Action ;
use crate ::client ::WMClient ;
use crate ::config ::application ::OnlyOrNot ;
use crate ::config ::key_press ::{ KeyPress , Modifier } ;
use crate ::config ::keymap ::{ build_override_table , OverrideEntry } ;
use crate ::config ::keymap_action ::KeymapAction ;
use crate ::config ::modmap_action ::{ Keys , ModmapAction , MultiPurposeKey , PressReleaseKey } ;
use crate ::config ::remap ::Remap ;
use crate ::device ::InputDeviceInfo ;
use crate ::event ::{ Event , KeyEvent , RelativeEvent } ;
use crate ::{ config , Config } ;
use evdev ::Key ;
use lazy_static ::lazy_static ;
use log ::debug ;
use nix ::sys ::time ::TimeSpec ;
use nix ::sys ::timerfd ::{ Expiration , TimerFd , TimerSetTimeFlags } ;
use std ::cmp ::Ordering ;
use std ::collections ::{ HashMap , HashSet } ;
use std ::error ::Error ;
use std ::time ::{ Duration , Instant } ;
// This const is a value used to offset RELATIVE events' scancodes
// so that they correspond to the custom aliases created in config::key::parse_key.
// This offset also prevents resulting scancodes from corresponding to non-Xremap scancodes,
// to prevent conflating disguised relative events with other events.
pub const DISGUISED_EVENT_OFFSETTER : u16 = 59974 ;
pub struct EventHandler {
// Currently pressed modifier keys
modifiers : HashSet < Key > ,
// Modifiers that are currently pressed but not in the source KeyPress
extra_modifiers : HashSet < Key > ,
// Make sure the original event is released even if remapping changes while holding the key
pressed_keys : HashMap < Key , Key > ,
// Check the currently active application
application_client : WMClient ,
application_cache : Option < String > ,
title_cache : Option < String > ,
// State machine for multi-purpose keys
multi_purpose_keys : HashMap < Key , MultiPurposeKeyState > ,
// Current nested remaps
override_remaps : Vec < HashMap < Key , Vec < OverrideEntry > > > ,
// Key triggered on a timeout of nested remaps
override_timeout_key : Option < Key > ,
// Trigger a timeout of nested remaps through select(2)
override_timer : TimerFd ,
// { set_mode: String }
mode : String ,
// { set_mark: true }
mark_set : bool ,
// { escape_next_key: true }
escape_next_key : bool ,
// keypress_delay_ms
keypress_delay : Duration ,
// Buffered actions to be dispatched. TODO: Just return actions from each function instead of using this.
actions : Vec < Action > ,
}
struct TaggedAction {
action : KeymapAction ,
exact_match : bool ,
}
impl EventHandler {
pub fn new ( timer : TimerFd , mode : & str , keypress_delay : Duration , application_client : WMClient ) -> EventHandler {
EventHandler {
modifiers : HashSet ::new ( ) ,
extra_modifiers : HashSet ::new ( ) ,
pressed_keys : HashMap ::new ( ) ,
application_client ,
application_cache : None ,
title_cache : None ,
multi_purpose_keys : HashMap ::new ( ) ,
override_remaps : vec ! [ ] ,
override_timeout_key : None ,
override_timer : timer ,
mode : mode . to_string ( ) ,
mark_set : false ,
escape_next_key : false ,
keypress_delay ,
actions : vec ! [ ] ,
}
}
// Handle an Event and return Actions. This should be the only public method of EventHandler.
pub fn on_events ( & mut self , events : & Vec < Event > , config : & Config ) -> Result < Vec < Action > , Box < dyn Error > > {
// a vector to collect mouse movement events to be able to send them all at once as one MouseMovementEventCollection.
let mut mouse_movement_collection : Vec < RelativeEvent > = Vec ::new ( ) ;
for event in events {
match event {
Event ::KeyEvent ( device , key_event ) = > {
self . on_key_event ( key_event , config , device ) ? ;
( )
}
Event ::RelativeEvent ( device , relative_event ) = > {
self . on_relative_event ( relative_event , & mut mouse_movement_collection , config , device ) ?
}
Event ::OtherEvents ( event ) = > self . send_action ( Action ::InputEvent ( * event ) ) ,
Event ::OverrideTimeout = > self . timeout_override ( ) ? ,
} ;
}
// if there is at least one mouse movement event, sending all of them as one MouseMovementEventCollection
if mouse_movement_collection . len ( ) > 0 {
self . send_action ( Action ::MouseMovementEventCollection ( mouse_movement_collection ) ) ;
}
Ok ( self . actions . drain ( .. ) . collect ( ) )
}
// Handle EventType::KEY
fn on_key_event (
& mut self ,
event : & KeyEvent ,
config : & Config ,
device : & InputDeviceInfo ,
) -> Result < bool , Box < dyn Error > > {
self . application_cache = None ; // expire cache
self . title_cache = None ; // expire cache
let key = Key ::new ( event . code ( ) ) ;
debug ! ( "=> {}: {:?}" , event . value ( ) , & key ) ;
// Apply modmap
let mut key_values = if let Some ( key_action ) = self . find_modmap ( config , & key , device ) {
self . dispatch_keys ( key_action , key , event . value ( ) ) ?
} else {
vec! [ ( key , event . value ( ) ) ]
} ;
self . maintain_pressed_keys ( key , event . value ( ) , & mut key_values ) ;
if ! self . multi_purpose_keys . is_empty ( ) {
key_values = self . flush_timeout_keys ( key_values ) ;
}
let mut send_original_relative_event = false ;
// Apply keymap
for ( key , value ) in key_values . into_iter ( ) {
if config . virtual_modifiers . contains ( & key ) {
self . update_modifier ( key , value ) ;
continue ;
} else if MODIFIER_KEYS . contains ( & key ) {
self . update_modifier ( key , value ) ;
} else if is_pressed ( value ) {
if self . escape_next_key {
self . escape_next_key = false
} else if let Some ( actions ) = self . find_keymap ( config , & key , device ) ? {
self . dispatch_actions ( & actions , & key ) ? ;
continue ;
}
}
// checking if there's a "disguised" key version of a relative event,
// (scancodes equal to and over DISGUISED_EVENT_OFFSETTER are only "disguised" custom events)
// and also if it's the same "key" and value as the one that came in.
if key . code ( ) > = DISGUISED_EVENT_OFFSETTER & & ( key . code ( ) , value ) = = ( event . code ( ) , event . value ( ) ) {
// if it is, setting send_original_relative_event to true to later tell on_relative_event to send the original event.
send_original_relative_event = true ;
continue ;
}
self . send_key ( & key , value ) ;
}
// Using the Ok() to send a boolean to on_relative_event, which will be used to decide whether to send the original relative event.
// (True = send the original relative event, false = don't send it.)
Ok ( send_original_relative_event )
}
// Handle EventType::RELATIVE
fn on_relative_event (
& mut self ,
event : & RelativeEvent ,
mouse_movement_collection : & mut Vec < RelativeEvent > ,
config : & Config ,
device : & InputDeviceInfo ,
) -> Result < ( ) , Box < dyn Error > > {
// Because a "full" RELATIVE event is only one event,
// it doesn't translate very well into a KEY event (because those have a "press" event and an "unpress" event).
// The solution used here is to send two events for each relative event :
// one for the press "event" and one for the "unpress" event.
// These consts are used because 'RELEASE'/'PRESS' are better than '0'/'1' at indicating a button release/press.
const RELEASE : i32 = 0 ;
const PRESS : i32 = 1 ;
// All relative events (except maybe those i haven't found information about (REL_DIAL, REL_MISC and REL_RESERVED))
// can have either a positive value or a negative value.
// A negative value is associated with a different action than the positive value.
// Specifically, negative values are associated with the opposite of the action that would emit a positive value.
// For example, a positive value for a scroll event (REL_WHEEL) comes from an upscroll, while a negative value comes from a downscroll.
let key = match event . value {
// Positive and negative values can be really high because the events are relative,
// so their values are variable, meaning we have to match with all positive/negative values.
// Not sure if there is any relative event with a fixed value.
1 ..= i32 ::MAX = > ( event . code * 2 ) + DISGUISED_EVENT_OFFSETTER ,
// While some events may appear to have a fixed value,
// events like scrolling will have higher values with more "agressive" scrolling.
// *2 to create a "gap" between events (since multiplying by two means that all resulting values will be even, the odd numbers between will be missing),
// +1 if the event has a negative value to "fill" the gap (since adding one shifts the parity from even to odd),
// and adding DISGUISED_EVENT_OFFSETTER,
// so that the total as a keycode corresponds to one of the custom aliases that
// are created in config::key::parse_key specifically for these "disguised" relative events.
i32 ::MIN ..= - 1 = > ( event . code * 2 ) + 1 + DISGUISED_EVENT_OFFSETTER ,
0 = > {
println! ( "This event has a value of zero : {:?}" , event ) ;
// A value of zero would be unexpected for a relative event,
// since changing something by zero is kinda useless.
// Just in case it can actually happen (and also because match arms need the same output type),
// we'll just act like the value of the event was a positive.
( event . code * 2 ) + DISGUISED_EVENT_OFFSETTER
}
} ;
// Sending a RELATIVE event "disguised" as a "fake" KEY event press to on_key_event.
match self . on_key_event ( & KeyEvent ::new_with ( key , PRESS ) , config , & device ) ? {
// the boolean value is from a variable at the end of on_key_event from event_handler,
// used to indicate whether the event got through unchanged.
true = > {
// Sending the original RELATIVE event if the "press" version of the "fake" KEY event got through on_key_event unchanged.
let action = RelativeEvent ::new_with ( event . code , event . value ) ;
if event . code < = 2 {
// If it's a mouse movement event (event.code <= 2),
// it is added to mouse_movement_collection to later be sent alongside all other mouse movement event,
// as a single MouseMovementEventCollection instead of potentially multiple RelativeEvent .
// Mouse movement events need to be sent all at once because they would otherwise be separated by a synchronization event¹,
// which the OS handles differently from two unseparated mouse movement events.
// For example, a REL_X event², followed by a SYNCHRONIZATION event, followed by a REL_Y event³, followed by a SYNCHRONIZATION event,
// will move the mouse cursor by a different amount than a REL_X followed by a REL_Y followed by a SYNCHRONIZATION.
// ¹Because Xremap usually sends events one by one through evdev's "emit" function, which adds a synchronization event during each call.
// ²Mouse movement along the X (horizontal) axis.
// ³Mouse movement along the Y (vertical) axis.
mouse_movement_collection . push ( action ) ;
} else {
// Otherwise, the event is directly sent as a relative event, to be dispatched like other events.
self . send_action ( Action ::RelativeEvent ( action ) ) ;
}
}
false = > { }
}
// Sending the "unpressed" version of the "fake" KEY event.
self . on_key_event ( & KeyEvent ::new_with ( key , RELEASE ) , config , & device ) ? ;
Ok ( ( ) )
}
fn timeout_override ( & mut self ) -> Result < ( ) , Box < dyn Error > > {
if let Some ( key ) = self . override_timeout_key {
self . send_key ( & key , PRESS ) ;
self . send_key ( & key , RELEASE ) ;
}
self . remove_override ( )
}
fn remove_override ( & mut self ) -> Result < ( ) , Box < dyn Error > > {
self . override_timer . unset ( ) ? ;
self . override_remaps . clear ( ) ;
self . override_timeout_key = None ;
Ok ( ( ) )
}
fn send_keys ( & mut self , keys : & Vec < Key > , value : i32 ) {
for key in keys {
self . send_key ( key , value ) ;
}
}
fn send_key ( & mut self , key : & Key , value : i32 ) {
// let event = InputEvent::new(EventType::KEY, key.code(), value);
let event = KeyEvent ::new_with ( key . code ( ) , value ) ;
self . send_action ( Action ::KeyEvent ( event ) ) ;
}
fn send_action ( & mut self , action : Action ) {
self . actions . push ( action ) ;
}
// Repeat/Release what's originally pressed even if remapping changes while holding it
fn maintain_pressed_keys ( & mut self , key : Key , value : i32 , events : & mut Vec < ( Key , i32 ) > ) {
// Not handling multi-purpose keysfor now; too complicated
if events . len ( ) ! = 1 | | value ! = events [ 0 ] . 1 {
return ;
}
let event = events [ 0 ] ;
if value = = PRESS {
self . pressed_keys . insert ( key , event . 0 ) ;
} else {
if let Some ( original_key ) = self . pressed_keys . get ( & key ) {
events [ 0 ] . 0 = * original_key ;
}
if value = = RELEASE {
self . pressed_keys . remove ( & key ) ;
}
}
}
fn dispatch_keys (
& mut self ,
key_action : ModmapAction ,
key : Key ,
value : i32 ,
) -> Result < Vec < ( Key , i32 ) > , Box < dyn Error > > {
let keys = match key_action {
ModmapAction ::Key ( modmap_key ) = > vec! [ ( modmap_key , value ) ] ,
ModmapAction ::MultiPurposeKey ( MultiPurposeKey {
held ,
alone ,
alone_timeout ,
} ) = > {
if value = = PRESS {
self . multi_purpose_keys . insert (
key ,
MultiPurposeKeyState {
held ,
alone ,
alone_timeout_at : Some ( Instant ::now ( ) + alone_timeout ) ,
} ,
) ;
return Ok ( vec! [ ] ) ; // delay the press
} else if value = = REPEAT {
if let Some ( state ) = self . multi_purpose_keys . get_mut ( & key ) {
return Ok ( state . repeat ( ) ) ;
}
} else if value = = RELEASE {
if let Some ( state ) = self . multi_purpose_keys . remove ( & key ) {
return Ok ( state . release ( ) ) ;
}
} else {
panic! ( "unexpected key event value: {}" , value ) ;
}
// fallthrough on state discrepancy
vec! [ ( key , value ) ]
}
ModmapAction ::PressReleaseKey ( PressReleaseKey {
skip_key_event ,
press ,
release ,
} ) = > {
// Just hook actions, and then emit the original event. We might want to
// support reordering the key event and dispatched actions later.
if value = = PRESS | | value = = RELEASE {
self . dispatch_actions (
& ( if value = = PRESS { press } else { release } )
. into_iter ( )
. map ( | action | TaggedAction {
action ,
exact_match : false ,
} )
. collect ( ) ,
& key ,
) ? ;
}
if skip_key_event {
// Do not dispatch the original key
vec! [ ]
} else {
// dispatch the original key
vec! [ ( key , value ) ]
}
}
} ;
Ok ( keys )
}
fn flush_timeout_keys ( & mut self , key_values : Vec < ( Key , i32 ) > ) -> Vec < ( Key , i32 ) > {
let mut flush = false ;
for ( _ , value ) in key_values . iter ( ) {
if * value = = PRESS {
flush = true ;
break ;
}
}
if flush {
let mut flushed : Vec < ( Key , i32 ) > = vec! [ ] ;
for ( _ , state ) in self . multi_purpose_keys . iter_mut ( ) {
flushed . extend ( state . force_held ( ) ) ;
}
flushed . extend ( key_values ) ;
flushed
} else {
key_values
}
}
fn find_modmap ( & mut self , config : & Config , key : & Key , device : & InputDeviceInfo ) -> Option < ModmapAction > {
for modmap in & config . modmap {
if let Some ( key_action ) = modmap . remap . get ( key ) {
if let Some ( window_matcher ) = & modmap . window {
if ! self . match_window ( window_matcher ) {
continue ;
}
}
if let Some ( application_matcher ) = & modmap . application {
if ! self . match_application ( application_matcher ) {
continue ;
}
}
if let Some ( device_matcher ) = & modmap . device {
if ! self . match_device ( device_matcher , device ) {
continue ;
}
}
return Some ( key_action . clone ( ) ) ;
}
}
None
}
fn find_keymap (
& mut self ,
config : & Config ,
key : & Key ,
device : & InputDeviceInfo ,
) -> Result < Option < Vec < TaggedAction > > , Box < dyn Error > > {
if ! self . override_remaps . is_empty ( ) {
let entries : Vec < OverrideEntry > = self
. override_remaps
. iter ( )
. flat_map ( | map | map . get ( key ) . cloned ( ) . unwrap_or_default ( ) )
. collect ( ) ;
if ! entries . is_empty ( ) {
self . remove_override ( ) ? ;
for exact_match in [ true , false ] {
let mut remaps = vec! [ ] ;
for entry in & entries {
if entry . exact_match & & ! exact_match {
continue ;
}
let ( extra_modifiers , missing_modifiers ) = self . diff_modifiers ( & entry . modifiers ) ;
if ( exact_match & & extra_modifiers . len ( ) > 0 ) | | missing_modifiers . len ( ) > 0 {
continue ;
}
let actions = with_extra_modifiers ( & entry . actions , & extra_modifiers , entry . exact_match ) ;
let is_remap = is_remap ( & entry . actions ) ;
// If the first/top match was a remap, continue to find rest of the eligible remaps for this key
if remaps . is_empty ( ) & & ! is_remap {
return Ok ( Some ( actions ) ) ;
} else if is_remap {
remaps . extend ( actions ) ;
}
}
if ! remaps . is_empty ( ) {
return Ok ( Some ( remaps ) ) ;
}
}
}
// An override remap is set but not used. Flush the pending key.
self . timeout_override ( ) ? ;
}
if let Some ( entries ) = config . keymap_table . get ( key ) {
for exact_match in [ true , false ] {
let mut remaps = vec! [ ] ;
for entry in entries {
if entry . exact_match & & ! exact_match {
continue ;
}
let ( extra_modifiers , missing_modifiers ) = self . diff_modifiers ( & entry . modifiers ) ;
if ( exact_match & & extra_modifiers . len ( ) > 0 ) | | missing_modifiers . len ( ) > 0 {
continue ;
}
if let Some ( window_matcher ) = & entry . title {
if ! self . match_window ( window_matcher ) {
continue ;
}
}
if let Some ( application_matcher ) = & entry . application {
if ! self . match_application ( application_matcher ) {
continue ;
}
}
if let Some ( device_matcher ) = & entry . device {
if ! self . match_device ( device_matcher , device ) {
continue ;
}
}
if let Some ( modes ) = & entry . mode {
if ! modes . contains ( & self . mode ) {
continue ;
}
}
let actions = with_extra_modifiers ( & entry . actions , & extra_modifiers , entry . exact_match ) ;
let is_remap = is_remap ( & entry . actions ) ;
// If the first/top match was a remap, continue to find rest of the eligible remaps for this key
if remaps . is_empty ( ) & & ! is_remap {
return Ok ( Some ( actions ) ) ;
} else if is_remap {
remaps . extend ( actions )
}
}
if ! remaps . is_empty ( ) {
return Ok ( Some ( remaps ) ) ;
}
}
}
Ok ( None )
}
fn dispatch_actions ( & mut self , actions : & Vec < TaggedAction > , key : & Key ) -> Result < ( ) , Box < dyn Error > > {
for action in actions {
self . dispatch_action ( action , key ) ? ;
}
Ok ( ( ) )
}
fn dispatch_action ( & mut self , action : & TaggedAction , key : & Key ) -> Result < ( ) , Box < dyn Error > > {
match & action . action {
KeymapAction ::KeyPress ( key_press ) = > self . send_key_press ( key_press ) ,
KeymapAction ::Remap ( Remap {
remap ,
timeout ,
timeout_key ,
} ) = > {
let set_timeout = self . override_remaps . is_empty ( ) ;
self . override_remaps
. push ( build_override_table ( remap , action . exact_match ) ) ;
// Set timeout only if this is the first of multiple eligible remaps,
// so the behaviour is consistent with how current normal keymap override works
if set_timeout {
if let Some ( timeout ) = timeout {
let expiration = Expiration ::OneShot ( TimeSpec ::from_duration ( * timeout ) ) ;
// TODO: Consider handling the timer in ActionDispatcher
self . override_timer . unset ( ) ? ;
self . override_timer . set ( expiration , TimerSetTimeFlags ::empty ( ) ) ? ;
self . override_timeout_key = timeout_key . or_else ( | | Some ( * key ) ) ;
}
}
}
KeymapAction ::Launch ( command ) = > self . run_command ( command . clone ( ) ) ,
KeymapAction ::SetMode ( mode ) = > {
self . mode = mode . clone ( ) ;
println! ( "mode: {}" , mode ) ;
}
KeymapAction ::SetMark ( set ) = > self . mark_set = * set ,
KeymapAction ::WithMark ( key_press ) = > self . send_key_press ( & self . with_mark ( key_press ) ) ,
KeymapAction ::EscapeNextKey ( escape_next_key ) = > self . escape_next_key = * escape_next_key ,
KeymapAction ::SetExtraModifiers ( keys ) = > {
self . extra_modifiers . clear ( ) ;
for key in keys {
self . extra_modifiers . insert ( * key ) ;
}
}
}
Ok ( ( ) )
}
fn send_key_press ( & mut self , key_press : & KeyPress ) {
// Build extra or missing modifiers. Note that only MODIFIER_KEYS are handled
// because logical modifiers shouldn't make an impact outside xremap.
let ( mut extra_modifiers , mut missing_modifiers ) = self . diff_modifiers ( & key_press . modifiers ) ;
extra_modifiers . retain ( | key | MODIFIER_KEYS . contains ( & key ) & & ! self . extra_modifiers . contains ( & key ) ) ;
missing_modifiers . retain ( | key | MODIFIER_KEYS . contains ( & key ) ) ;
// Emulate the modifiers of KeyPress
self . send_keys ( & missing_modifiers , PRESS ) ;
self . send_keys ( & extra_modifiers , RELEASE ) ;
// Press the main key
self . send_key ( & key_press . key , PRESS ) ;
self . send_key ( & key_press . key , RELEASE ) ;
self . send_action ( Action ::Delay ( self . keypress_delay ) ) ;
// Resurrect the original modifiers
self . send_keys ( & extra_modifiers , PRESS ) ;
self . send_action ( Action ::Delay ( self . keypress_delay ) ) ;
self . send_keys ( & missing_modifiers , RELEASE ) ;
}
fn with_mark ( & self , key_press : & KeyPress ) -> KeyPress {
if self . mark_set & & ! self . match_modifier ( & Modifier ::Shift ) {
let mut modifiers = key_press . modifiers . clone ( ) ;
modifiers . push ( Modifier ::Shift ) ;
KeyPress {
key : key_press . key ,
modifiers ,
}
} else {
key_press . clone ( )
}
}
fn run_command ( & mut self , command : Vec < String > ) {
self . send_action ( Action ::Command ( command ) ) ;
}
// Return (extra_modifiers, missing_modifiers)
fn diff_modifiers ( & self , modifiers : & Vec < Modifier > ) -> ( Vec < Key > , Vec < Key > ) {
let extra_modifiers : Vec < Key > = self
. modifiers
. iter ( )
. filter ( | modifier | ! contains_modifier ( modifiers , modifier ) )
. map ( | modifier | modifier . clone ( ) )
. collect ( ) ;
let missing_modifiers : Vec < Key > = modifiers
. iter ( )
. filter_map ( | modifier | {
if self . match_modifier ( modifier ) {
None
} else {
match modifier {
Modifier ::Shift = > Some ( Key ::KEY_LEFTSHIFT ) ,
Modifier ::Control = > Some ( Key ::KEY_LEFTCTRL ) ,
Modifier ::Alt = > Some ( Key ::KEY_LEFTALT ) ,
Modifier ::Windows = > Some ( Key ::KEY_LEFTMETA ) ,
Modifier ::Key ( key ) = > Some ( * key ) ,
}
}
} )
. collect ( ) ;
return ( extra_modifiers , missing_modifiers ) ;
}
fn match_modifier ( & self , modifier : & Modifier ) -> bool {
match modifier {
Modifier ::Shift = > {
self . modifiers . contains ( & Key ::KEY_LEFTSHIFT ) | | self . modifiers . contains ( & Key ::KEY_RIGHTSHIFT )
}
Modifier ::Control = > {
self . modifiers . contains ( & Key ::KEY_LEFTCTRL ) | | self . modifiers . contains ( & Key ::KEY_RIGHTCTRL )
}
Modifier ::Alt = > self . modifiers . contains ( & Key ::KEY_LEFTALT ) | | self . modifiers . contains ( & Key ::KEY_RIGHTALT ) ,
Modifier ::Windows = > {
self . modifiers . contains ( & Key ::KEY_LEFTMETA ) | | self . modifiers . contains ( & Key ::KEY_RIGHTMETA )
}
Modifier ::Key ( key ) = > self . modifiers . contains ( key ) ,
}
}
fn match_window ( & mut self , window_matcher : & OnlyOrNot ) -> bool {
// Lazily fill the wm_class cache
if self . title_cache . is_none ( ) {
match self . application_client . current_window ( ) {
Some ( title ) = > self . title_cache = Some ( title ) ,
None = > self . title_cache = Some ( String ::new ( ) ) ,
}
}
if let Some ( title ) = & self . title_cache {
if let Some ( title_only ) = & window_matcher . only {
return title_only . iter ( ) . any ( | m | m . matches ( title ) ) ;
}
if let Some ( title_not ) = & window_matcher . not {
return title_not . iter ( ) . all ( | m | ! m . matches ( title ) ) ;
}
}
false
}
fn match_application ( & mut self , application_matcher : & OnlyOrNot ) -> bool {
// Lazily fill the wm_class cache
if self . application_cache . is_none ( ) {
match self . application_client . current_application ( ) {
Some ( application ) = > self . application_cache = Some ( application ) ,
None = > self . application_cache = Some ( String ::new ( ) ) ,
}
}
if let Some ( application ) = & self . application_cache {
if let Some ( application_only ) = & application_matcher . only {
return application_only . iter ( ) . any ( | m | m . matches ( application ) ) ;
}
if let Some ( application_not ) = & application_matcher . not {
return application_not . iter ( ) . all ( | m | ! m . matches ( application ) ) ;
}
}
false
}
fn match_device ( & self , device_matcher : & config ::device ::Device , device : & InputDeviceInfo ) -> bool {
if let Some ( device_only ) = & device_matcher . only {
return device_only . iter ( ) . any ( | m | device . matches ( m ) ) ;
}
if let Some ( device_not ) = & device_matcher . not {
return device_not . iter ( ) . all ( | m | ! device . matches ( m ) ) ;
}
false
}
fn update_modifier ( & mut self , key : Key , value : i32 ) {
if value = = PRESS {
self . modifiers . insert ( key ) ;
} else if value = = RELEASE {
self . modifiers . remove ( & key ) ;
}
}
}
fn is_remap ( actions : & Vec < KeymapAction > ) -> bool {
actions . iter ( ) . all ( | x | match x {
KeymapAction ::Remap ( .. ) = > true ,
_ = > false ,
} )
}
fn with_extra_modifiers (
actions : & Vec < KeymapAction > ,
extra_modifiers : & Vec < Key > ,
exact_match : bool ,
) -> Vec < TaggedAction > {
let mut result : Vec < TaggedAction > = vec! [ ] ;
if extra_modifiers . len ( ) > 0 {
// Virtually release extra modifiers so that they won't be physically released on KeyPress
result . push ( TaggedAction {
action : KeymapAction ::SetExtraModifiers ( extra_modifiers . clone ( ) ) ,
exact_match ,
} ) ;
}
result . extend ( actions . iter ( ) . map ( | action | TaggedAction {
action : action . clone ( ) ,
exact_match ,
} ) ) ;
if extra_modifiers . len ( ) > 0 {
// Resurrect the modifier status
result . push ( TaggedAction {
action : KeymapAction ::SetExtraModifiers ( vec! [ ] ) ,
exact_match ,
} ) ;
}
return result ;
}
fn contains_modifier ( modifiers : & Vec < Modifier > , key : & Key ) -> bool {
for modifier in modifiers {
if match modifier {
Modifier ::Shift = > key = = & Key ::KEY_LEFTSHIFT | | key = = & Key ::KEY_RIGHTSHIFT ,
Modifier ::Control = > key = = & Key ::KEY_LEFTCTRL | | key = = & Key ::KEY_RIGHTCTRL ,
Modifier ::Alt = > key = = & Key ::KEY_LEFTALT | | key = = & Key ::KEY_RIGHTALT ,
Modifier ::Windows = > key = = & Key ::KEY_LEFTMETA | | key = = & Key ::KEY_RIGHTMETA ,
Modifier ::Key ( modifier_key ) = > key = = modifier_key ,
} {
return true ;
}
}
false
}
lazy_static ! {
static ref MODIFIER_KEYS : [ Key ; 8 ] = [
// Shift
Key ::KEY_LEFTSHIFT ,
Key ::KEY_RIGHTSHIFT ,
// Control
Key ::KEY_LEFTCTRL ,
Key ::KEY_RIGHTCTRL ,
// Alt
Key ::KEY_LEFTALT ,
Key ::KEY_RIGHTALT ,
// Windows
Key ::KEY_LEFTMETA ,
Key ::KEY_RIGHTMETA ,
] ;
}
// ---
fn is_pressed ( value : i32 ) -> bool {
value = = PRESS | | value = = REPEAT
}
// InputEvent#value
static RELEASE : i32 = 0 ;
static PRESS : i32 = 1 ;
static REPEAT : i32 = 2 ;
// ---
#[ derive(Debug) ]
struct MultiPurposeKeyState {
held : Keys ,
alone : Keys ,
// Some if the first press is still delayed, None if already considered held.
alone_timeout_at : Option < Instant > ,
}
impl MultiPurposeKeyState {
fn repeat ( & mut self ) -> Vec < ( Key , i32 ) > {
if let Some ( alone_timeout_at ) = & self . alone_timeout_at {
if Instant ::now ( ) < * alone_timeout_at {
vec! [ ] // still delay the press
} else {
self . alone_timeout_at = None ; // timeout
let mut keys = self . held . clone ( ) . into_vec ( ) ;
keys . sort_by ( modifiers_first ) ;
keys . into_iter ( ) . map ( | key | ( key , PRESS ) ) . collect ( )
}
} else {
let mut keys = self . held . clone ( ) . into_vec ( ) ;
keys . sort_by ( modifiers_first ) ;
keys . into_iter ( ) . map ( | key | ( key , REPEAT ) ) . collect ( )
}
}
fn release ( & self ) -> Vec < ( Key , i32 ) > {
if let Some ( alone_timeout_at ) = & self . alone_timeout_at {
if Instant ::now ( ) < * alone_timeout_at {
// dispatch the delayed press and this release
let mut release_keys = self . alone . clone ( ) . into_vec ( ) ;
release_keys . sort_by ( modifiers_last ) ;
let release_keys : Vec < ( Key , i32 ) > = release_keys . into_iter ( ) . map ( | key | ( key , RELEASE ) ) . collect ( ) ;
let mut keys = self . alone . clone ( ) . into_vec ( ) ;
keys . sort_by ( modifiers_first ) ;
let mut keys : Vec < ( Key , i32 ) > = keys . into_iter ( ) . map ( | key | ( key , PRESS ) ) . collect ( ) ;
keys . extend ( release_keys ) ;
keys
} else {
// dispatch the delayed press and this release
let mut release_keys = self . held . clone ( ) . into_vec ( ) ;
release_keys . sort_by ( modifiers_last ) ;
let release_keys : Vec < ( Key , i32 ) > = release_keys . into_iter ( ) . map ( | key | ( key , RELEASE ) ) . collect ( ) ;
let mut keys = self . held . clone ( ) . into_vec ( ) ;
keys . sort_by ( modifiers_first ) ;
let mut keys : Vec < ( Key , i32 ) > = keys . into_iter ( ) . map ( | key | ( key , PRESS ) ) . collect ( ) ;
keys . extend ( release_keys ) ;
keys
}
} else {
let mut release_keys = self . held . clone ( ) . into_vec ( ) ;
release_keys . sort_by ( modifiers_last ) ;
release_keys . into_iter ( ) . map ( | key | ( key , RELEASE ) ) . collect ( )
}
}
fn force_held ( & mut self ) -> Vec < ( Key , i32 ) > {
if self . alone_timeout_at . is_some ( ) {
self . alone_timeout_at = None ;
let mut keys = self . held . clone ( ) . into_vec ( ) ;
keys . sort_by ( modifiers_last ) ;
keys . into_iter ( ) . map ( | key | ( key , PRESS ) ) . collect ( )
} else {
vec! [ ]
}
}
}
/// Orders modifier keys ahead of non-modifier keys.
/// Unfortunately the underlying type doesn't allow direct
/// comparison, but that's ok for our purposes.
fn modifiers_first ( a : & Key , b : & Key ) -> Ordering {
if MODIFIER_KEYS . contains ( a ) {
if MODIFIER_KEYS . contains ( b ) {
Ordering ::Equal
} else {
Ordering ::Less
}
} else if MODIFIER_KEYS . contains ( b ) {
Ordering ::Greater
} else {
// Neither are modifiers
Ordering ::Equal
}
}
fn modifiers_last ( a : & Key , b : & Key ) -> Ordering {
modifiers_first ( a , b ) . reverse ( )
}