Skip to content

Commit

Permalink
Support dead keys and AltGr on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmekon committed Aug 24, 2017
1 parent b92ba65 commit eeb8d10
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ lto = true
debug = true

[replace]
"winit:0.7.5" = { git = "https://github.com/tomaka/winit", branch = "master" }
"winit:0.7.5" = { git = "https://github.com/mrmekon/winit.git", branch = "macos_dead_key" }
10 changes: 10 additions & 0 deletions alacritty.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,16 @@ visual_bell:
# Background opacity
background_opacity: 1.0

# Internationalization
#
# Set 'altgr' to true if your keyboard has an AltGr key, or if you want to use
# the Right Alt/Option key as AltGr instead. This is commonly desired on Macs,
# even for U.S. keyboard layouts. If enabled, the Right Alt/Option will not be
# used for key bindings.
#
# internationalization:
# altgr: true

# Key bindings
#
# Each binding is defined as an object with some properties. Most of the
Expand Down
25 changes: 25 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ pub enum VisualBellAnimation {
Linear,
}

#[derive(Default, Clone, Debug, Deserialize)]
pub struct InternationalizationConfig {
/// Right alt key is AltGr modifier
altgr: bool,
}

impl InternationalizationConfig {
/// Right alt key is AltGr modifier
#[inline]
pub fn altgr(&self) -> bool {
self.altgr
}
}

#[derive(Debug, Deserialize)]
pub struct VisualBellConfig {
/// Visual bell animation function
Expand Down Expand Up @@ -274,6 +288,10 @@ pub struct Config {
#[serde(default)]
visual_bell: VisualBellConfig,

/// Internationalization configuration
#[serde(default)]
internationalization: InternationalizationConfig,

/// Hide cursor when typing
#[serde(default)]
hide_cursor_when_typing: bool,
Expand Down Expand Up @@ -327,6 +345,7 @@ impl Default for Config {
shell: None,
config_path: None,
visual_bell: Default::default(),
internationalization: Default::default(),
env: Default::default(),
hide_cursor_when_typing: Default::default(),
padding: default_padding(),
Expand Down Expand Up @@ -1140,6 +1159,12 @@ impl Config {
&self.visual_bell
}

/// Get internationalization config
#[inline]
pub fn internationalization(&self) -> &InternationalizationConfig {
&self.internationalization
}

/// Should show render timer
#[inline]
pub fn render_timer(&self) -> bool {
Expand Down
23 changes: 22 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::time::{Instant};

use serde_json as json;
use parking_lot::MutexGuard;
use glutin::{self, ModifiersState, Event, ElementState};
use glutin::{self, ModifiersState, Event, ElementState, VirtualKeyCode};
use copypasta::{Clipboard, Load, Store};

use config::{self, Config};
Expand Down Expand Up @@ -39,7 +39,9 @@ pub struct ActionContext<'a, N: 'a> {
pub selection_modified: bool,
pub received_count: &'a mut usize,
pub suppress_chars: &'a mut bool,
pub suppress_alt: &'a mut bool,
pub last_modifiers: &'a mut ModifiersState,
pub last_virtual_key: &'a mut Option<VirtualKeyCode>,
}

impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
Expand Down Expand Up @@ -122,10 +124,20 @@ impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
&mut self.suppress_chars
}

#[inline]
fn suppress_alt(&mut self) -> &mut bool {
&mut self.suppress_alt
}

#[inline]
fn last_modifiers(&mut self) -> &mut ModifiersState {
&mut self.last_modifiers
}

#[inline]
fn last_virtual_key(&mut self) -> &mut Option<VirtualKeyCode> {
&mut self.last_virtual_key
}
}

pub enum ClickState {
Expand Down Expand Up @@ -172,6 +184,7 @@ pub struct Processor<N> {
key_bindings: Vec<KeyBinding>,
mouse_bindings: Vec<MouseBinding>,
mouse_config: config::Mouse,
international_config: config::InternationalizationConfig,
print_events: bool,
wait_for_event: bool,
notifier: N,
Expand All @@ -184,7 +197,9 @@ pub struct Processor<N> {
hide_cursor: bool,
received_count: usize,
suppress_chars: bool,
suppress_alt: bool,
last_modifiers: ModifiersState,
last_virtual_key: Option<VirtualKeyCode>,
pending_events: Vec<Event>,
}

Expand Down Expand Up @@ -215,6 +230,7 @@ impl<N: Notify> Processor<N> {
key_bindings: config.key_bindings().to_vec(),
mouse_bindings: config.mouse_bindings().to_vec(),
mouse_config: config.mouse().to_owned(),
international_config: config.internationalization().to_owned(),
print_events: options.print_events,
wait_for_event: true,
notifier: notifier,
Expand All @@ -227,7 +243,9 @@ impl<N: Notify> Processor<N> {
hide_cursor: false,
received_count: 0,
suppress_chars: false,
suppress_alt: false,
last_modifiers: Default::default(),
last_virtual_key: None,
pending_events: Vec::with_capacity(4),
}
}
Expand Down Expand Up @@ -375,14 +393,17 @@ impl<N: Notify> Processor<N> {
selection_modified: false,
received_count: &mut self.received_count,
suppress_chars: &mut self.suppress_chars,
suppress_alt: &mut self.suppress_alt,
last_modifiers: &mut self.last_modifiers,
last_virtual_key: &mut self.last_virtual_key,
};

processor = input::Processor {
ctx: context,
mouse_config: &self.mouse_config,
key_bindings: &self.key_bindings[..],
mouse_bindings: &self.mouse_bindings[..],
international_config: &self.international_config,
};

// Scope needed to that hide_cursor isn't borrowed after the scope
Expand Down
42 changes: 41 additions & 1 deletion src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct Processor<'a, A: 'a> {
pub key_bindings: &'a [KeyBinding],
pub mouse_bindings: &'a [MouseBinding],
pub mouse_config: &'a config::Mouse,
pub international_config: &'a config::InternationalizationConfig,
pub ctx: A,
}

Expand All @@ -61,7 +62,9 @@ pub trait ActionContext {
fn mouse_coords(&self) -> Option<Point>;
fn received_count(&mut self) -> &mut usize;
fn suppress_chars(&mut self) -> &mut bool;
fn suppress_alt(&mut self) -> &mut bool;
fn last_modifiers(&mut self) -> &mut ModifiersState;
fn last_virtual_key(&mut self) -> &mut Option<VirtualKeyCode>;
}

/// Describes a state and action to take in that state
Expand Down Expand Up @@ -439,12 +442,27 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
*self.ctx.last_modifiers() = *mods;
*self.ctx.received_count() = 0;
*self.ctx.suppress_chars() = false;
*self.ctx.last_virtual_key() = Some(key);

// Allow right-alt to be mapped to AltGr
if key == VirtualKeyCode::RAlt && self.international_config.altgr() {
*self.ctx.suppress_alt() = true;
}
// If AltGr is pressed, don't treat it as 'alt'
if *self.ctx.suppress_alt() {
(*self.ctx.last_modifiers()).alt = false;
}
if self.process_key_bindings(&mods, key) {
*self.ctx.suppress_chars() = true;
}
},
(_, ElementState::Released) => *self.ctx.suppress_chars() = false,
(key, ElementState::Released) => {
*self.ctx.suppress_chars() = false;
*self.ctx.last_virtual_key() = key;
if key == Some(VirtualKeyCode::RAlt) {
*self.ctx.suppress_alt() = false;
}
},
_ => ()
}
}
Expand All @@ -467,6 +485,18 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {

self.ctx.write_to_pty(bytes);

match *self.ctx.last_virtual_key() {
Some(VirtualKeyCode::DeadKeyPlaceholder) => {
// Go back one character after printing dead-key to keep it highlighted
self.ctx.write_to_pty(b"\x1b[D".to_vec());
},
Some(VirtualKeyCode::DeadKeyGlyph) => {
// Delete temporary dead-key placeholder
self.ctx.write_to_pty(b"\x1b[3~".to_vec());
},
_ => {}
}

*self.ctx.received_count() += 1;
}
}
Expand Down Expand Up @@ -540,7 +570,9 @@ mod tests {
pub last_action: MultiClick,
pub received_count: usize,
pub suppress_chars: bool,
pub suppress_alt: bool,
pub last_modifiers: ModifiersState,
pub last_virtual_key: Option<VirtualKeyCode>,
}

impl <'a>super::ActionContext for ActionContext<'a> {
Expand Down Expand Up @@ -587,9 +619,15 @@ mod tests {
fn suppress_chars(&mut self) -> &mut bool {
&mut self.suppress_chars
}
fn suppress_alt(&mut self) -> &mut bool {
&mut self.suppress_alt
}
fn last_modifiers(&mut self) -> &mut ModifiersState {
&mut self.last_modifiers
}
fn last_virtual_key(&mut self) -> &mut Option<VirtualKeyCode> {
&mut self.last_virtual_key
}
}

macro_rules! test_clickstate {
Expand Down Expand Up @@ -627,7 +665,9 @@ mod tests {
last_action: MultiClick::None,
received_count: 0,
suppress_chars: false,
suppress_alt: false,
last_modifiers: ModifiersState::default(),
last_virtual_key: None,
};

let mut processor = Processor {
Expand Down

0 comments on commit eeb8d10

Please sign in to comment.