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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use errors::*;
use gdk::DeviceExt;
use gdk;
use gdk_sys;
use glib::translate::*;
use gtk::prelude::*;
use gtk;
use gtk_sys;
use libc::c_uint;
use std;
pub struct HotkeyDialog {
hotkey_dialog: gtk::Dialog,
key_pressed_label: gtk::Label,
}
impl HotkeyDialog {
pub fn new<P>(parent: &P, hotkey: String) -> HotkeyDialog
where P: IsA<gtk::Window>
{
let builder =
gtk::Builder::new_from_string(include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
"/data/ui/hotkey-dialog.glade")));
let hotkey_dialog: gtk::Dialog = builder.get_object("hotkey_dialog")
.unwrap();
let instruction_label: gtk::Label = builder.get_object("instruction_label")
.unwrap();
let key_pressed_label: gtk::Label = builder.get_object("key_pressed_label")
.unwrap();
hotkey_dialog.set_title(format!("Set {} HotKey", hotkey).as_str());
instruction_label.set_markup(format!("Press new HotKey for <b>{}</b>",
hotkey)
.as_str());
hotkey_dialog.set_transient_for(parent);
{
let key_pressed_label = key_pressed_label.clone();
hotkey_dialog.connect_key_press_event(move |_, e| {
let mut state = e.get_state();
unsafe {
let mut keyval: c_uint = 0;
let mut consumed: gdk_sys::GdkModifierType =
gdk_sys::GdkModifierType::empty();
gdk_sys::gdk_keymap_translate_keyboard_state(
gdk_sys::gdk_keymap_get_default(),
e.get_hardware_keycode() as u32,
state.to_glib(),
e.get_group() as i32,
&mut keyval as *mut c_uint,
std::ptr::null_mut(),
std::ptr::null_mut(),
&mut consumed as *mut gdk_sys::GdkModifierType);
let consumed: gdk::ModifierType = from_glib(!consumed);
state = state & consumed;
state = state & gtk::accelerator_get_default_mod_mask();
let key_text = gtk::accelerator_name(keyval, state);
key_pressed_label.set_text(key_text
.unwrap_or(String::from("(None)"))
.as_str());
};
return Inhibit(false);
});
}
hotkey_dialog.connect_key_release_event(move |w, _| {
w.response(gtk_sys::GtkResponseType::Ok as i32);
return Inhibit(false);
});
return HotkeyDialog {
hotkey_dialog,
key_pressed_label,
};
}
pub fn run(&self) -> Result<String> {
self.hotkey_dialog.show_now();
let device = gtk::get_current_event_device()
.ok_or("Could not get current device")?;
let window = self.hotkey_dialog
.get_window()
.ok_or("Could not get window")?;
let m_grab_status =
device.grab(&window,
gdk::GrabOwnership::Application,
true,
gdk::KEY_PRESS_MASK,
None,
gdk_sys::GDK_CURRENT_TIME as u32);
if m_grab_status != gdk::GrabStatus::Success {
bail!("Could not grab the keyboard");
}
let resp = self.hotkey_dialog.run();
device.ungrab(gdk_sys::GDK_CURRENT_TIME as u32);
if resp != gtk::ResponseType::Ok.into() {
bail!(ErrorKind::GtkResponseCancel(String::from("not assigning hotkey")));
}
return Ok(self.key_pressed_label
.get_text()
.ok_or("Could not get text")?);
}
}
impl Drop for HotkeyDialog {
fn drop(&mut self) {
self.hotkey_dialog.destroy();
}
}