Skip to content

Commit

Permalink
Add the active modifiers to the mouse event
Browse files Browse the repository at this point in the history
This would solve the most important use case for RustAudio#116. Only the Linux
version has been tested, but the Windows should work perfectly fine, and
I don't know anything about macOS programming but that version also
compiles so it should be fine.
  • Loading branch information
robbert-vdh committed Mar 11, 2022
1 parent fe18131 commit 39b2f75
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 46 deletions.
29 changes: 25 additions & 4 deletions src/event.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use keyboard_types::KeyboardEvent;
use keyboard_types::{KeyboardEvent, Modifiers};

use crate::{Point, WindowInfo};

Expand Down Expand Up @@ -38,21 +38,42 @@ pub enum MouseEvent {
CursorMoved {
/// The logical coordinates of the mouse position
position: Point,
/// The modifiers that were held down just before the event.
modifiers: Modifiers,
},

/// A mouse button was pressed.
ButtonPressed(MouseButton),
ButtonPressed {
/// The button that was pressed.
button: MouseButton,
/// The modifiers that were held down just before the event.
modifiers: Modifiers,
},

/// A mouse button was released.
ButtonReleased(MouseButton),
ButtonReleased {
/// The button that was released.
button: MouseButton,
/// The modifiers that were held down just before the event.
modifiers: Modifiers,
},

/// The mouse wheel was scrolled.
WheelScrolled(ScrollDelta),
WheelScrolled {
/// How much was scrolled, in factional lines.
delta: ScrollDelta,
/// The modifiers that were held down just before the event.
modifiers: Modifiers,
},

/// The mouse cursor entered the window.
///
/// May not be available on all platforms.
CursorEntered,

/// The mouse cursor left the window.
///
/// May not be available on all platforms.
CursorLeft,
}

Expand Down
44 changes: 37 additions & 7 deletions src/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
WindowOpenOptions,
};

use super::keyboard::make_modifiers;
use super::window::WindowState;

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

/// Similar to [add_simple_mouse_class_method!], but this creates its own event object for the
/// press/release event and adds the active modifier keys to that event.
macro_rules! add_mouse_button_class_method {
($class:ident, $sel:ident, $event_ty:ident, $button:expr) => {
#[allow(non_snake_case)]
extern "C" fn $sel(this: &Object, _: Sel, event: id){
let state: &mut WindowState = unsafe {
WindowState::from_field(this)
};

let modifiers = unsafe { NSEvent::modifierFlags(event) };

state.trigger_event(Event::Mouse($event_ty {
button: $button,
modifiers: make_modifiers(modifiers),
}));
}

$class.add_method(
sel!($sel:),
$sel as extern "C" fn(&Object, Sel, id),
);
};
}

macro_rules! add_simple_keyboard_class_method {
($class:ident, $sel:ident) => {
#[allow(non_snake_case)]
Expand Down Expand Up @@ -126,12 +152,12 @@ unsafe fn create_view_class() -> &'static Class {
view_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
);

add_simple_mouse_class_method!(class, mouseDown, ButtonPressed(MouseButton::Left));
add_simple_mouse_class_method!(class, mouseUp, ButtonReleased(MouseButton::Left));
add_simple_mouse_class_method!(class, rightMouseDown, ButtonPressed(MouseButton::Right));
add_simple_mouse_class_method!(class, rightMouseUp, ButtonReleased(MouseButton::Right));
add_simple_mouse_class_method!(class, otherMouseDown, ButtonPressed(MouseButton::Middle));
add_simple_mouse_class_method!(class, otherMouseUp, ButtonReleased(MouseButton::Middle));
add_mouse_button_class_method!(class, mouseDown, ButtonPressed, MouseButton::Left);
add_mouse_button_class_method!(class, mouseUp, ButtonReleased, MouseButton::Left);
add_mouse_button_class_method!(class, rightMouseDown, ButtonPressed, MouseButton::Right);
add_mouse_button_class_method!(class, rightMouseUp, ButtonReleased, MouseButton::Right);
add_mouse_button_class_method!(class, otherMouseDown, ButtonPressed, MouseButton::Middle);
add_mouse_button_class_method!(class, otherMouseUp, ButtonReleased, MouseButton::Middle);
add_simple_mouse_class_method!(class, mouseEntered, MouseEvent::CursorEntered);
add_simple_mouse_class_method!(class, mouseExited, MouseEvent::CursorLeft);

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

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

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

state.trigger_event(Event::Mouse(MouseEvent::CursorMoved { position }));
state.trigger_event(Event::Mouse(MouseEvent::CursorMoved {
position,
modifiers: make_modifiers(modifiers),
}));
}
40 changes: 32 additions & 8 deletions src/win/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ use winapi::shared::ntdef::SHORT;
use winapi::shared::windef::HWND;
use winapi::um::winuser::{
GetKeyState, GetKeyboardLayout, MapVirtualKeyExW, PeekMessageW, ToUnicodeEx, MAPVK_VK_TO_CHAR,
MAPVK_VSC_TO_VK_EX, PM_NOREMOVE, VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN, VK_BACK, VK_BROWSER_BACK,
VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD, VK_BROWSER_HOME, VK_BROWSER_REFRESH,
VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_CANCEL, VK_CAPITAL, VK_CLEAR, VK_CONTROL, VK_CONVERT,
VK_CRSEL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF, VK_ESCAPE, VK_EXECUTE,
VK_EXSEL, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8,
VK_F9, VK_FINAL, VK_HELP, VK_HOME, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI, VK_LAUNCH_APP1,
VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL, VK_LEFT, VK_LMENU,
VK_LSHIFT, VK_LWIN, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK,
MAPVK_VSC_TO_VK_EX, MK_CONTROL, MK_SHIFT, PM_NOREMOVE, VK_ACCEPT, VK_ADD, VK_APPS, VK_ATTN,
VK_BACK, VK_BROWSER_BACK, VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD, VK_BROWSER_HOME,
VK_BROWSER_REFRESH, VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_CANCEL, VK_CAPITAL, VK_CLEAR,
VK_CONTROL, VK_CONVERT, VK_CRSEL, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN, VK_END, VK_EREOF,
VK_ESCAPE, VK_EXECUTE, VK_EXSEL, VK_F1, VK_F10, VK_F11, VK_F12, VK_F2, VK_F3, VK_F4, VK_F5,
VK_F6, VK_F7, VK_F8, VK_F9, VK_FINAL, VK_HELP, VK_HOME, VK_INSERT, VK_JUNJA, VK_KANA, VK_KANJI,
VK_LAUNCH_APP1, VK_LAUNCH_APP2, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL, VK_LEFT,
VK_LMENU, VK_LSHIFT, VK_LWIN, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE, VK_MEDIA_PREV_TRACK,
VK_MEDIA_STOP, VK_MENU, VK_MODECHANGE, VK_MULTIPLY, VK_NEXT, VK_NONCONVERT, VK_NUMLOCK,
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_OEM_ATTN, VK_OEM_CLEAR, VK_PAUSE, VK_PLAY, VK_PRINT, VK_PRIOR,
Expand Down Expand Up @@ -562,6 +562,30 @@ impl KeyboardState {
}
}

/// The same as [Self::get_modifiers()], but it reads the Ctrl and Shift state from a mouse
/// event's wParam parameter. Saves two calls to [GetKeyState()].
pub(crate) fn get_modifiers_from_mouse_wparam(&self, wparam: WPARAM) -> Modifiers {
unsafe {
let mut modifiers = Modifiers::empty();
for &(vk, modifier, mask) in MODIFIER_MAP {
let modifier_active = match modifier {
Modifiers::CONTROL => wparam & MK_CONTROL != 0,
Modifiers::SHIFT => wparam & MK_SHIFT != 0,
_ => GetKeyState(vk) & mask != 0,
};

if modifier_active {
modifiers |= modifier;
}
}
if self.has_altgr && GetKeyState(VK_RMENU) & 0x80 != 0 {
modifiers |= Modifiers::ALT_GRAPH;
modifiers &= !(Modifiers::CONTROL | Modifiers::ALT);
}
modifiers
}
}

/// Load a keyboard layout.
///
/// We need to retain a map of virtual key codes in various modifier
Expand Down
39 changes: 25 additions & 14 deletions src/win/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,14 @@ unsafe extern "system" fn wnd_proc(
let y = ((lparam >> 16) & 0xFFFF) as i16 as i32;

let physical_pos = PhyPoint { x, y };

let logical_pos = physical_pos.to_logical(&window_state.window_info);
let event = Event::Mouse(MouseEvent::CursorMoved {
position: logical_pos,
modifiers: window_state.keyboard_state.get_modifiers_from_mouse_wparam(wparam),
});

window_state.handler.on_event(&mut window, event);

window_state.handler.on_event(
&mut window,
Event::Mouse(MouseEvent::CursorMoved { position: logical_pos }),
);
return 0;
}
WM_MOUSEWHEEL => {
Expand All @@ -158,13 +159,13 @@ unsafe extern "system" fn wnd_proc(
let value = value as i32;
let value = value as f32 / WHEEL_DELTA as f32;

window_state.handler.on_event(
&mut window,
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
x: 0.0,
y: value,
})),
);
let event = Event::Mouse(MouseEvent::WheelScrolled {
delta: ScrollDelta::Lines { x: 0.0, y: value },
modifiers: window_state.keyboard_state.get_modifiers_from_mouse_wparam(wparam),
});

window_state.handler.on_event(&mut window, event);

return 0;
}
WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN
Expand Down Expand Up @@ -193,7 +194,12 @@ unsafe extern "system" fn wnd_proc(
// Capture the mouse cursor on button down
mouse_button_counter = mouse_button_counter.saturating_add(1);
SetCapture(hwnd);
MouseEvent::ButtonPressed(button)
MouseEvent::ButtonPressed {
button,
modifiers: window_state
.keyboard_state
.get_modifiers_from_mouse_wparam(wparam),
}
}
WM_LBUTTONUP | WM_MBUTTONUP | WM_RBUTTONUP | WM_XBUTTONUP => {
// Release the mouse cursor capture when all buttons are released
Expand All @@ -202,7 +208,12 @@ unsafe extern "system" fn wnd_proc(
ReleaseCapture();
}

MouseEvent::ButtonReleased(button)
MouseEvent::ButtonReleased {
button,
modifiers: window_state
.keyboard_state
.get_modifiers_from_mouse_wparam(wparam),
}
}
_ => {
unreachable!()
Expand Down
2 changes: 1 addition & 1 deletion src/x11/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ fn hardware_keycode_to_code(hw_keycode: u16) -> Code {

// Extracts the keyboard modifiers from, e.g., the `state` field of
// `xcb::xproto::ButtonPressEvent`
fn key_mods(mods: u16) -> Modifiers {
pub(super) fn key_mods(mods: u16) -> Modifiers {
let mut ret = Modifiers::default();
let mut key_masks = [
(xproto::MOD_MASK_SHIFT, Modifiers::SHIFT),
Expand Down
33 changes: 21 additions & 12 deletions src/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy,
};

use super::keyboard::{convert_key_press_event, convert_key_release_event};
use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};

#[cfg(feature = "opengl")]
use crate::{
Expand Down Expand Up @@ -580,7 +580,10 @@ impl Window {

handler.on_event(
&mut crate::Window::new(self),
Event::Mouse(MouseEvent::CursorMoved { position: logical_pos }),
Event::Mouse(MouseEvent::CursorMoved {
position: logical_pos,
modifiers: key_mods(event.state()),
}),
);
}
}
Expand All @@ -593,26 +596,29 @@ impl Window {
4 => {
handler.on_event(
&mut crate::Window::new(self),
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
x: 0.0,
y: 1.0,
})),
Event::Mouse(MouseEvent::WheelScrolled {
delta: ScrollDelta::Lines { x: 0.0, y: 1.0 },
modifiers: key_mods(event.state()),
}),
);
}
5 => {
handler.on_event(
&mut crate::Window::new(self),
Event::Mouse(MouseEvent::WheelScrolled(ScrollDelta::Lines {
x: 0.0,
y: -1.0,
})),
Event::Mouse(MouseEvent::WheelScrolled {
delta: ScrollDelta::Lines { x: 0.0, y: -1.0 },
modifiers: key_mods(event.state()),
}),
);
}
detail => {
let button_id = mouse_id(detail);
handler.on_event(
&mut crate::Window::new(self),
Event::Mouse(MouseEvent::ButtonPressed(button_id)),
Event::Mouse(MouseEvent::ButtonPressed {
button: button_id,
modifiers: key_mods(event.state()),
}),
);
}
}
Expand All @@ -626,7 +632,10 @@ impl Window {
let button_id = mouse_id(detail);
handler.on_event(
&mut crate::Window::new(self),
Event::Mouse(MouseEvent::ButtonReleased(button_id)),
Event::Mouse(MouseEvent::ButtonReleased {
button: button_id,
modifiers: key_mods(event.state()),
}),
);
}
}
Expand Down

0 comments on commit 39b2f75

Please sign in to comment.