1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use core::cmp::Reverse;
use std::collections::HashMap;
use std::sync::Arc;
use crate::input::state::{HookState, WindowState};
use crate::input::{Hook, InputHookCtrl, InputHookID, Key, NO_HOOK_WEIGHT};
use crate::interval::Interval;
use crate::window::WindowID;
pub(in crate::input) fn release(
interval: &Arc<Interval>,
hooks: &mut HashMap<InputHookID, Hook>,
win_state: &mut HashMap<WindowID, WindowState>,
win: WindowID,
key: Key,
) {
let window_state = win_state
.entry(win)
.or_insert_with(|| WindowState::new(win));
if window_state.update_key(key, false) {
let focused_bin_id = window_state.focused_bin_id();
let mut remove_hooks: Vec<InputHookID> = Vec::new();
let mut call_release_on: Vec<_> = hooks
.iter_mut()
.filter_map(|(hook_id, hook)| {
if hook.is_for_window_id(win)
|| (focused_bin_id.is_some() && hook.is_for_bin_id(focused_bin_id.unwrap()))
{
match &mut hook.state {
HookState::Release {
state,
pressed,
weight,
..
} => {
if state.is_involved(key) && !state.update(key, false) && *pressed {
*pressed = false;
Some((*weight, (hook_id, hook)))
} else {
None
}
},
HookState::Press {
state, ..
} => {
state.update(key, false);
None
},
HookState::Hold {
state,
pressed,
intvl_id,
..
} => {
if state.is_involved(key) && !state.update(key, false) && *pressed {
*pressed = false;
interval.pause(*intvl_id);
}
None
},
_ => None,
}
} else {
None
}
})
.collect();
call_release_on.sort_by_key(|(weight, _)| Reverse(*weight));
for (weight, (hook_id, hook)) in call_release_on {
let hook_target = match hook.target_wk.upgrade() {
Some(some) => some,
None => {
remove_hooks.push(*hook_id);
continue;
},
};
if let HookState::Release {
state,
method,
..
} = &mut hook.state
{
match method(hook_target, window_state, state) {
InputHookCtrl::Retain => (),
InputHookCtrl::RetainNoPass => {
if weight != NO_HOOK_WEIGHT {
break;
}
},
InputHookCtrl::Remove => {
remove_hooks.push(*hook_id);
},
InputHookCtrl::RemoveNoPass => {
remove_hooks.push(*hook_id);
if weight != NO_HOOK_WEIGHT {
break;
}
},
}
} else {
unreachable!()
}
}
}
}