Skip to content

Commit eae4033

Browse files
authored
Merge pull request #117 from robbert-vdh/feature/mouse-event-modifiers
Add the active keyboard modifiers to the mouse events
2 parents b371263 + 5b57af2 commit eae4033

File tree

6 files changed

+141
-57
lines changed

6 files changed

+141
-57
lines changed

src/event.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use keyboard_types::KeyboardEvent;
1+
use keyboard_types::{KeyboardEvent, Modifiers};
22

33
use crate::{Point, WindowInfo};
44

@@ -32,38 +32,48 @@ pub enum ScrollDelta {
3232
},
3333
}
3434

35-
#[derive(Debug, Copy, Clone, PartialEq)]
36-
pub struct MouseClick {
37-
pub button: MouseButton,
38-
pub click_count: usize,
39-
/// The logical coordinates of the mouse position
40-
pub position: Point,
41-
}
42-
4335
#[derive(Debug, Clone, Copy, PartialEq)]
4436
pub enum MouseEvent {
4537
/// The mouse cursor was moved
4638
CursorMoved {
4739
/// The logical coordinates of the mouse position
4840
position: Point,
41+
/// The modifiers that were held down just before the event.
42+
modifiers: Modifiers,
4943
},
5044

5145
/// A mouse button was pressed.
52-
ButtonPressed(MouseButton),
46+
ButtonPressed {
47+
/// The button that was pressed.
48+
button: MouseButton,
49+
/// The modifiers that were held down just before the event.
50+
modifiers: Modifiers,
51+
},
5352

5453
/// A mouse button was released.
55-
ButtonReleased(MouseButton),
56-
57-
/// A mouse button was clicked.
58-
Click(MouseClick),
54+
ButtonReleased {
55+
/// The button that was released.
56+
button: MouseButton,
57+
/// The modifiers that were held down just before the event.
58+
modifiers: Modifiers,
59+
},
5960

6061
/// The mouse wheel was scrolled.
61-
WheelScrolled(ScrollDelta),
62+
WheelScrolled {
63+
/// How much was scrolled, in factional lines.
64+
delta: ScrollDelta,
65+
/// The modifiers that were held down just before the event.
66+
modifiers: Modifiers,
67+
},
6268

6369
/// The mouse cursor entered the window.
70+
///
71+
/// May not be available on all platforms.
6472
CursorEntered,
6573

6674
/// The mouse cursor left the window.
75+
///
76+
/// May not be available on all platforms.
6777
CursorLeft,
6878
}
6979

src/macos/view.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::{
1919
WindowOpenOptions,
2020
};
2121

22+
use super::keyboard::make_modifiers;
2223
use super::window::WindowState;
2324

2425
/// Name of the field used to store the `WindowState` pointer.
@@ -42,6 +43,31 @@ macro_rules! add_simple_mouse_class_method {
4243
};
4344
}
4445

46+
/// Similar to [add_simple_mouse_class_method!], but this creates its own event object for the
47+
/// press/release event and adds the active modifier keys to that event.
48+
macro_rules! add_mouse_button_class_method {
49+
($class:ident, $sel:ident, $event_ty:ident, $button:expr) => {
50+
#[allow(non_snake_case)]
51+
extern "C" fn $sel(this: &Object, _: Sel, event: id){
52+
let state: &mut WindowState = unsafe {
53+
WindowState::from_field(this)
54+
};
55+
56+
let modifiers = unsafe { NSEvent::modifierFlags(event) };
57+
58+
state.trigger_event(Event::Mouse($event_ty {
59+
button: $button,
60+
modifiers: make_modifiers(modifiers),
61+
}));
62+
}
63+
64+
$class.add_method(
65+
sel!($sel:),
66+
$sel as extern "C" fn(&Object, Sel, id),
67+
);
68+
};
69+
}
70+
4571
macro_rules! add_simple_keyboard_class_method {
4672
($class:ident, $sel:ident) => {
4773
#[allow(non_snake_case)]
@@ -126,12 +152,12 @@ unsafe fn create_view_class() -> &'static Class {
126152
view_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
127153
);
128154

129-
add_simple_mouse_class_method!(class, mouseDown, ButtonPressed(MouseButton::Left));
130-
add_simple_mouse_class_method!(class, mouseUp, ButtonReleased(MouseButton::Left));
131-
add_simple_mouse_class_method!(class, rightMouseDown, ButtonPressed(MouseButton::Right));
132-
add_simple_mouse_class_method!(class, rightMouseUp, ButtonReleased(MouseButton::Right));
133-
add_simple_mouse_class_method!(class, otherMouseDown, ButtonPressed(MouseButton::Middle));
134-
add_simple_mouse_class_method!(class, otherMouseUp, ButtonReleased(MouseButton::Middle));
155+
add_mouse_button_class_method!(class, mouseDown, ButtonPressed, MouseButton::Left);
156+
add_mouse_button_class_method!(class, mouseUp, ButtonReleased, MouseButton::Left);
157+
add_mouse_button_class_method!(class, rightMouseDown, ButtonPressed, MouseButton::Right);
158+
add_mouse_button_class_method!(class, rightMouseUp, ButtonReleased, MouseButton::Right);
159+
add_mouse_button_class_method!(class, otherMouseDown, ButtonPressed, MouseButton::Middle);
160+
add_mouse_button_class_method!(class, otherMouseUp, ButtonReleased, MouseButton::Middle);
135161
add_simple_mouse_class_method!(class, mouseEntered, MouseEvent::CursorEntered);
136162
add_simple_mouse_class_method!(class, mouseExited, MouseEvent::CursorLeft);
137163

@@ -308,8 +334,12 @@ extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
308334

309335
msg_send![this, convertPoint:point fromView:nil]
310336
};
337+
let modifiers = unsafe { NSEvent::modifierFlags(event) };
311338

312339
let position = Point { x: point.x, y: point.y };
313340

314-
state.trigger_event(Event::Mouse(MouseEvent::CursorMoved { position }));
341+
state.trigger_event(Event::Mouse(MouseEvent::CursorMoved {
342+
position,
343+
modifiers: make_modifiers(modifiers),
344+
}));
315345
}

src/win/keyboard.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ use winapi::shared::ntdef::SHORT;
2929
use winapi::shared::windef::HWND;
3030
use winapi::um::winuser::{
3131
GetKeyState, GetKeyboardLayout, MapVirtualKeyExW, PeekMessageW, ToUnicodeEx, MAPVK_VK_TO_CHAR,
32-
MAPVK_VSC_TO_VK_EX, PM_NOREMOVE, VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN, VK_BACK, VK_BROWSER_BACK,
33-
VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD, VK_BROWSER_HOME, VK_BROWSER_REFRESH,
34-
VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_CANCEL, VK_CAPITAL, VK_CLEAR, VK_CONTROL, VK_CONVERT,
35-
VK_CRSEL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF, VK_ESCAPE, VK_EXECUTE,
36-
VK_EXSEL, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8,
37-
VK_F9, VK_FINAL, VK_HELP, VK_HOME, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI, VK_LAUNCH_APP1,
38-
VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL, VK_LEFT, VK_LMENU,
39-
VK_LSHIFT, VK_LWIN, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK,
32+
MAPVK_VSC_TO_VK_EX, MK_CONTROL, MK_SHIFT, PM_NOREMOVE, VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN,
33+
VK_BACK, VK_BROWSER_BACK, VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD, VK_BROWSER_HOME,
34+
VK_BROWSER_REFRESH, VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_CANCEL, VK_CAPITAL, VK_CLEAR,
35+
VK_CONTROL, VK_CONVERT, VK_CRSEL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF,
36+
VK_ESCAPE, VK_EXECUTE, VK_EXSEL, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5,
37+
VK_F6, VK_F7, VK_F8, VK_F9, VK_FINAL, VK_HELP, VK_HOME, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI,
38+
VK_LAUNCH_APP1, VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL, VK_LEFT,
39+
VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK,
4040
VK_MEDIA_STOP, VK_MENU, VK_MODECHANGE, VK_MULTIPLY, VK_NEXT, VK_NONCONVERT, VK_NUMLOCK,
4141
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
4242
VK_NUMPAD8, VK_NUMPAD9, VK_OEM_ATTN, VK_OEM_CLEAR, VK_PAUSE, VK_PLAY, VK_PRINT, VK_PRIOR,
@@ -562,6 +562,30 @@ impl KeyboardState {
562562
}
563563
}
564564

565+
/// The same as [Self::get_modifiers()], but it reads the Ctrl and Shift state from a mouse
566+
/// event's wParam parameter. Saves two calls to [GetKeyState()].
567+
pub(crate) fn get_modifiers_from_mouse_wparam(&self, wparam: WPARAM) -> Modifiers {
568+
unsafe {
569+
let mut modifiers = Modifiers::empty();
570+
for &(vk, modifier, mask) in MODIFIER_MAP {
571+
let modifier_active = match modifier {
572+
Modifiers::CONTROL => wparam & MK_CONTROL != 0,
573+
Modifiers::SHIFT => wparam & MK_SHIFT != 0,
574+
_ => GetKeyState(vk) & mask != 0,
575+
};
576+
577+
if modifier_active {
578+
modifiers |= modifier;
579+
}
580+
}
581+
if self.has_altgr && GetKeyState(VK_RMENU) & 0x80 != 0 {
582+
modifiers |= Modifiers::ALT_GRAPH;
583+
modifiers &= !(Modifiers::CONTROL | Modifiers::ALT);
584+
}
585+
modifiers
586+
}
587+
}
588+
565589
/// Load a keyboard layout.
566590
///
567591
/// We need to retain a map of virtual key codes in various modifier

src/win/window.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,14 @@ unsafe extern "system" fn wnd_proc(
137137
let y = ((lparam >> 16) & 0xFFFF) as i16 as i32;
138138

139139
let physical_pos = PhyPoint { x, y };
140-
141140
let logical_pos = physical_pos.to_logical(&window_state.window_info);
141+
let event = Event::Mouse(MouseEvent::CursorMoved {
142+
position: logical_pos,
143+
modifiers: window_state.keyboard_state.get_modifiers_from_mouse_wparam(wparam),
144+
});
145+
146+
window_state.handler.on_event(&mut window, event);
142147

143-
window_state.handler.on_event(
144-
&mut window,
145-
Event::Mouse(MouseEvent::CursorMoved { position: logical_pos }),
146-
);
147148
return 0;
148149
}
149150
WM_MOUSEWHEEL => {
@@ -155,13 +156,13 @@ unsafe extern "system" fn wnd_proc(
155156
let value = value as i32;
156157
let value = value as f32 / WHEEL_DELTA as f32;
157158

158-
window_state.handler.on_event(
159-
&mut window,
160-
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
161-
x: 0.0,
162-
y: value,
163-
})),
164-
);
159+
let event = Event::Mouse(MouseEvent::WheelScrolled {
160+
delta: ScrollDelta::Lines { x: 0.0, y: value },
161+
modifiers: window_state.keyboard_state.get_modifiers_from_mouse_wparam(wparam),
162+
});
163+
164+
window_state.handler.on_event(&mut window, event);
165+
165166
return 0;
166167
}
167168
WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN
@@ -190,7 +191,12 @@ unsafe extern "system" fn wnd_proc(
190191
// Capture the mouse cursor on button down
191192
mouse_button_counter = mouse_button_counter.saturating_add(1);
192193
SetCapture(hwnd);
193-
MouseEvent::ButtonPressed(button)
194+
MouseEvent::ButtonPressed {
195+
button,
196+
modifiers: window_state
197+
.keyboard_state
198+
.get_modifiers_from_mouse_wparam(wparam),
199+
}
194200
}
195201
WM_LBUTTONUP | WM_MBUTTONUP | WM_RBUTTONUP | WM_XBUTTONUP => {
196202
// Release the mouse cursor capture when all buttons are released
@@ -199,7 +205,12 @@ unsafe extern "system" fn wnd_proc(
199205
ReleaseCapture();
200206
}
201207

202-
MouseEvent::ButtonReleased(button)
208+
MouseEvent::ButtonReleased {
209+
button,
210+
modifiers: window_state
211+
.keyboard_state
212+
.get_modifiers_from_mouse_wparam(wparam),
213+
}
203214
}
204215
_ => {
205216
unreachable!()

src/x11/keyboard.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn hardware_keycode_to_code(hw_keycode: u16) -> Code {
362362

363363
// Extracts the keyboard modifiers from, e.g., the `state` field of
364364
// `xcb::xproto::ButtonPressEvent`
365-
fn key_mods(mods: u16) -> Modifiers {
365+
pub(super) fn key_mods(mods: u16) -> Modifiers {
366366
let mut ret = Modifiers::default();
367367
let mut key_masks = [
368368
(xproto::MOD_MASK_SHIFT, Modifiers::SHIFT),

src/x11/window.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy,
1717
};
1818

19-
use super::keyboard::{convert_key_press_event, convert_key_release_event};
19+
use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};
2020

2121
#[cfg(feature = "opengl")]
2222
use crate::{
@@ -580,7 +580,10 @@ impl Window {
580580

581581
handler.on_event(
582582
&mut crate::Window::new(self),
583-
Event::Mouse(MouseEvent::CursorMoved { position: logical_pos }),
583+
Event::Mouse(MouseEvent::CursorMoved {
584+
position: logical_pos,
585+
modifiers: key_mods(event.state()),
586+
}),
584587
);
585588
}
586589
}
@@ -593,26 +596,29 @@ impl Window {
593596
4 => {
594597
handler.on_event(
595598
&mut crate::Window::new(self),
596-
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
597-
x: 0.0,
598-
y: 1.0,
599-
})),
599+
Event::Mouse(MouseEvent::WheelScrolled {
600+
delta: ScrollDelta::Lines { x: 0.0, y: 1.0 },
601+
modifiers: key_mods(event.state()),
602+
}),
600603
);
601604
}
602605
5 => {
603606
handler.on_event(
604607
&mut crate::Window::new(self),
605-
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
606-
x: 0.0,
607-
y: -1.0,
608-
})),
608+
Event::Mouse(MouseEvent::WheelScrolled {
609+
delta: ScrollDelta::Lines { x: 0.0, y: -1.0 },
610+
modifiers: key_mods(event.state()),
611+
}),
609612
);
610613
}
611614
detail => {
612615
let button_id = mouse_id(detail);
613616
handler.on_event(
614617
&mut crate::Window::new(self),
615-
Event::Mouse(MouseEvent::ButtonPressed(button_id)),
618+
Event::Mouse(MouseEvent::ButtonPressed {
619+
button: button_id,
620+
modifiers: key_mods(event.state()),
621+
}),
616622
);
617623
}
618624
}
@@ -626,7 +632,10 @@ impl Window {
626632
let button_id = mouse_id(detail);
627633
handler.on_event(
628634
&mut crate::Window::new(self),
629-
Event::Mouse(MouseEvent::ButtonReleased(button_id)),
635+
Event::Mouse(MouseEvent::ButtonReleased {
636+
button: button_id,
637+
modifiers: key_mods(event.state()),
638+
}),
630639
);
631640
}
632641
}

0 commit comments

Comments
 (0)