Add WindowExtMacOS::{set_,}option_as_alt
This adds an ability to control left and right `Option` keys to be treated as `Alt`, thus not producing diacritical marks. Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
parent
13613931cf
commit
180a4c7a16
7 changed files with 236 additions and 6 deletions
|
|
@ -67,6 +67,35 @@ extern_methods!(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn keyEventWithType(
|
||||
type_: NSEventType,
|
||||
location: NSPoint,
|
||||
modifier_flags: NSEventModifierFlags,
|
||||
timestamp: NSTimeInterval,
|
||||
window_num: NSInteger,
|
||||
context: Option<&NSObject>,
|
||||
characters: &NSString,
|
||||
characters_ignoring_modifiers: &NSString,
|
||||
is_a_repeat: bool,
|
||||
scancode: c_ushort,
|
||||
) -> Id<Self, Shared> {
|
||||
unsafe {
|
||||
msg_send_id![
|
||||
Self::class(),
|
||||
keyEventWithType: type_,
|
||||
location: location,
|
||||
modifierFlags: modifier_flags,
|
||||
timestamp: timestamp,
|
||||
windowNumber: window_num,
|
||||
context: context,
|
||||
characters: characters,
|
||||
charactersIgnoringModifiers: characters_ignoring_modifiers,
|
||||
isARepeat: is_a_repeat,
|
||||
keyCode: scancode,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[sel(locationInWindow)]
|
||||
pub fn locationInWindow(&self) -> NSPoint;
|
||||
|
||||
|
|
@ -123,6 +152,15 @@ extern_methods!(
|
|||
#[sel(stage)]
|
||||
pub fn stage(&self) -> NSInteger;
|
||||
|
||||
#[sel(isARepeat)]
|
||||
pub fn is_a_repeat(&self) -> bool;
|
||||
|
||||
#[sel(windowNumber)]
|
||||
pub fn window_number(&self) -> NSInteger;
|
||||
|
||||
#[sel(timestamp)]
|
||||
pub fn timestamp(&self) -> NSTimeInterval;
|
||||
|
||||
pub fn characters(&self) -> Option<Id<NSString, Shared>> {
|
||||
unsafe { msg_send_id![self, characters] }
|
||||
}
|
||||
|
|
@ -130,6 +168,16 @@ extern_methods!(
|
|||
pub fn charactersIgnoringModifiers(&self) -> Option<Id<NSString, Shared>> {
|
||||
unsafe { msg_send_id![self, charactersIgnoringModifiers] }
|
||||
}
|
||||
|
||||
pub fn lalt_pressed(&self) -> bool {
|
||||
let raw_modifiers = self.modifierFlags().bits() as u32;
|
||||
raw_modifiers & NX_DEVICELALTKEYMASK != 0
|
||||
}
|
||||
|
||||
pub fn ralt_pressed(&self) -> bool {
|
||||
let raw_modifiers = self.modifierFlags().bits() as u32;
|
||||
raw_modifiers & NX_DEVICERALTKEYMASK != 0
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -138,6 +186,10 @@ unsafe impl NSCopying for NSEvent {
|
|||
type Output = NSEvent;
|
||||
}
|
||||
|
||||
// The values are from the https://github.com/apple-oss-distributions/IOHIDFamily/blob/19666c840a6d896468416ff0007040a10b7b46b8/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h#L258-L259
|
||||
const NX_DEVICELALTKEYMASK: u32 = 0x00000020;
|
||||
const NX_DEVICERALTKEYMASK: u32 = 0x00000040;
|
||||
|
||||
bitflags! {
|
||||
pub struct NSEventModifierFlags: NSUInteger {
|
||||
const NSAlphaShiftKeyMask = 1 << 16;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use super::appkit::{
|
|||
NSApp, NSCursor, NSEvent, NSEventModifierFlags, NSEventPhase, NSResponder, NSTrackingRectTag,
|
||||
NSView,
|
||||
};
|
||||
use crate::platform::macos::{OptionAsAlt, WindowExtMacOS};
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize},
|
||||
event::{
|
||||
|
|
@ -463,7 +464,17 @@ declare_class!(
|
|||
}
|
||||
let was_in_preedit = self.state.ime_state == ImeState::Preedit;
|
||||
|
||||
let characters = get_characters(event, false);
|
||||
// Get the characters from the event.
|
||||
let ev_mods = event_mods(event);
|
||||
let ignore_alt_characters = match self.window().option_as_alt() {
|
||||
OptionAsAlt::OnlyLeft if event.lalt_pressed() => true,
|
||||
OptionAsAlt::OnlyRight if event.ralt_pressed() => true,
|
||||
OptionAsAlt::Both if ev_mods.alt() => true,
|
||||
_ => false,
|
||||
} && !ev_mods.ctrl()
|
||||
&& !ev_mods.logo();
|
||||
|
||||
let characters = get_characters(event, ignore_alt_characters);
|
||||
self.state.forward_key_to_app = false;
|
||||
|
||||
// The `interpretKeyEvents` function might call
|
||||
|
|
@ -474,7 +485,13 @@ declare_class!(
|
|||
// is not handled by IME and should be handled by the application)
|
||||
let mut text_commited = false;
|
||||
if self.state.ime_allowed {
|
||||
let events_for_nsview = NSArray::from_slice(&[event.copy()]);
|
||||
let new_event = if ignore_alt_characters {
|
||||
replace_event_chars(event, &characters)
|
||||
} else {
|
||||
event.copy()
|
||||
};
|
||||
|
||||
let events_for_nsview = NSArray::from_slice(&[new_event]);
|
||||
unsafe { self.interpretKeyEvents(&events_for_nsview) };
|
||||
|
||||
// If the text was commited we must treat the next keyboard event as IME related.
|
||||
|
|
@ -501,7 +518,7 @@ declare_class!(
|
|||
state: ElementState::Pressed,
|
||||
scancode,
|
||||
virtual_keycode,
|
||||
modifiers: event_mods(event),
|
||||
modifiers: ev_mods,
|
||||
},
|
||||
is_synthetic: false,
|
||||
});
|
||||
|
|
@ -982,3 +999,21 @@ fn mouse_button(event: &NSEvent) -> MouseButton {
|
|||
n => MouseButton::Other(n as u16),
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_event_chars(event: &NSEvent, characters: &str) -> Id<NSEvent, Shared> {
|
||||
let ns_chars = NSString::from_str(characters);
|
||||
let chars_ignoring_mods = event.charactersIgnoringModifiers().unwrap();
|
||||
|
||||
NSEvent::keyEventWithType(
|
||||
event.type_(),
|
||||
event.locationInWindow(),
|
||||
event.modifierFlags(),
|
||||
event.timestamp(),
|
||||
event.window_number(),
|
||||
None,
|
||||
&ns_chars,
|
||||
&chars_ignoring_mods,
|
||||
event.is_a_repeat(),
|
||||
event.scancode(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
event::WindowEvent,
|
||||
icon::Icon,
|
||||
platform::macos::WindowExtMacOS,
|
||||
platform::macos::{OptionAsAlt, WindowExtMacOS},
|
||||
platform_impl::platform::{
|
||||
app_state::AppState,
|
||||
appkit::NSWindowOrderingMode,
|
||||
|
|
@ -85,6 +85,7 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
|||
pub disallow_hidpi: bool,
|
||||
pub has_shadow: bool,
|
||||
pub accepts_first_mouse: bool,
|
||||
pub option_as_alt: OptionAsAlt,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificWindowBuilderAttributes {
|
||||
|
|
@ -100,6 +101,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
|
|||
disallow_hidpi: false,
|
||||
has_shadow: true,
|
||||
accepts_first_mouse: true,
|
||||
option_as_alt: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -157,6 +159,9 @@ pub struct SharedState {
|
|||
/// transitioning back to borderless fullscreen.
|
||||
save_presentation_opts: Option<NSApplicationPresentationOptions>,
|
||||
pub current_theme: Option<Theme>,
|
||||
|
||||
/// The state of the `Option` as `Alt`.
|
||||
pub(crate) option_as_alt: OptionAsAlt,
|
||||
}
|
||||
|
||||
impl SharedState {
|
||||
|
|
@ -368,6 +373,8 @@ impl WinitWindow {
|
|||
this.center();
|
||||
}
|
||||
|
||||
this.set_option_as_alt(pl_attrs.option_as_alt);
|
||||
|
||||
Id::into_shared(this)
|
||||
})
|
||||
})
|
||||
|
|
@ -1349,6 +1356,16 @@ impl WindowExtMacOS for WinitWindow {
|
|||
fn set_document_edited(&self, edited: bool) {
|
||||
self.setDocumentEdited(edited)
|
||||
}
|
||||
|
||||
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
|
||||
let mut shared_state_lock = self.shared_state.lock().unwrap();
|
||||
shared_state_lock.option_as_alt = option_as_alt;
|
||||
}
|
||||
|
||||
fn option_as_alt(&self) -> OptionAsAlt {
|
||||
let shared_state_lock = self.shared_state.lock().unwrap();
|
||||
shared_state_lock.option_as_alt
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_ns_theme() -> Theme {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue