Alacritty: Inconsistent char output using Alt key binds in macOS

Created on 19 Jan 2019  Â·  50Comments  Â·  Source: alacritty/alacritty

Which operating system does the issue occur on? macOS (10.13.6)
Alacritty: 0.2.5

I have following in my settings file

  - { key: F,        mods: Alt,         chars: "\x1bf"                  }
  - { key: I,        mods: Alt,         chars: "\x1bi"                  }

Doing a /bin/cat and typing Option+F followed by a B produces ^[fb while Option +I followed by a B produces ^[iˆb

I came across this issue while using kakoune editor. I reported the issue there but it seems it is alacritty's issue (both iTerm & Terminal print ^[ib)

A - deps H - macos S - input S - winiglutin

Most helpful comment

I just found out about Alacritty, and while excited to use it, found that my fingers have the key bindings so ingrained in them. So, I fixed this problem solely in my alacritty.yml file. If this helps anyone else, here is my config. This makes Alacritty behave like Terminal.app. Key repeats and diacritics are all fixed.

env:
  TERM: xterm-24bits
key_bindings:
  - { key: N,           mods: Command,         action: SpawnNewInstance }
  - { key: PageUp,                             action: ScrollPageUp     }
  - { key: PageUp,      mode: Alt,             chars: "\x1B[5~"         }
  - { key: PageUp,      mods: Shift,           chars: "\x1B[5~"         }
  - { key: PageDown,                           action: ScrollPageDown   }
  - { key: PageDown,    mode: Alt,             chars: "\x1B[6~"         }
  - { key: PageDown,    mods: Shift,           chars: "\x1B[6~"         }
  - { key: Home,                               action: ScrollToTop      }
  - { key: Home,        mode: Alt,             chars: "\x1BOH"          }
  - { key: Home,        mods: Shift,           chars: "\x1B[H"          }
  - { key: End,                                action: ScrollToBottom   }
  - { key: End,         mode: Alt,             chars: "\x1BOF"          }
  - { key: End,         mods: Shift,           chars: "\x1B[F"          }
  - { key: Tab,         mods: Alt,             chars: "\x1B\t"          }
  - { key: Tab,         mods: Alt|Shift,       chars: "\x1B\x1B[Z"      }
  - { key: Back,                               chars: "\x7F"            }
  - { key: Back,        mods: Alt,             chars: "\x1B\x7F"        }
  - { key: Back,        mods: Alt|Shift,       chars: "\x1B\x08"        }
  - { key: Space,       mods: Control,         chars: "\x00"            }
  - { key: Space,       mods: Alt,             chars: "\x20"            }
  - { key: Left,        mods: Alt,             chars: "\x1Bb"           }
  - { key: Left,        mods: Alt|Shift,       chars: "\x1B\x1B[D"      }
  - { key: Right,       mods: Alt,             chars: "\x1Bf"           }
  - { key: Right,       mods: Alt|Shift,       chars: "\x1B\x1B[C"      }
  - { key: Down,        mods: Alt,             chars: "\x1B\x1B[B"      }
  - { key: Down,        mods: Alt|Shift,       chars: "\x1B\x1B[B"      }
  - { key: Up,          mods: Alt,             chars: "\x1B\x1B[A"      }
  - { key: Up,          mods: Alt|Shift,       chars: "\x1B\x1B[A"      }
  - { key: A,           mods: Alt,             chars: "\x1Ba"           }
  - { key: A,           mods: Alt|Shift,       chars: "\x1BA"           }
  - { key: B,           mods: Alt,             chars: "\x1Bb"           }
  - { key: B,           mods: Alt|Shift,       chars: "\x1BB"           }
  - { key: C,           mods: Alt,             chars: "\x1Bc"           }
  - { key: C,           mods: Alt|Shift,       chars: "\x1BC"           }
  - { key: D,           mods: Alt,             chars: "\x1Bd"           }
  - { key: D,           mods: Alt|Shift,       chars: "\x1BD"           }
  - { key: E,           mods: Alt,             chars: "\x1Be"           }
  - { key: E,           mods: Alt|Shift,       chars: "\x1BE"           }
  - { key: F,           mods: Alt,             chars: "\x1Bf"           }
  - { key: F,           mods: Alt|Shift,       chars: "\x1BF"           }
  - { key: G,           mods: Alt,             chars: "\x1Bg"           }
  - { key: G,           mods: Alt|Shift,       chars: "\x1BG"           }
  - { key: H,           mods: Alt,             chars: "\x1Bh"           }
  - { key: H,           mods: Alt|Shift,       chars: "\x1BH"           }
  - { key: I,           mods: Alt,             chars: "\x1Bi"           }
  - { key: I,           mods: Alt|Shift,       chars: "\x1BI"           }
  - { key: J,           mods: Alt,             chars: "\x1Bj"           }
  - { key: J,           mods: Alt|Shift,       chars: "\x1BJ"           }
  - { key: K,           mods: Alt,             chars: "\x1Bk"           }
  - { key: K,           mods: Alt|Shift,       chars: "\x1BK"           }
  - { key: L,           mods: Alt,             chars: "\x1Bl"           }
  - { key: L,           mods: Alt|Shift,       chars: "\x1BL"           }
  - { key: M,           mods: Alt,             chars: "\x1Bm"           }
  - { key: M,           mods: Alt|Shift,       chars: "\x1BM"           }
  - { key: N,           mods: Alt,             chars: "\x1Bn"           }
  - { key: N,           mods: Alt|Shift,       chars: "\x1BN"           }
  - { key: O,           mods: Alt,             chars: "\x1Bo"           }
  - { key: O,           mods: Alt|Shift,       chars: "\x1BO"           }
  - { key: P,           mods: Alt,             chars: "\x1Bp"           }
  - { key: P,           mods: Alt|Shift,       chars: "\x1BP"           }
  - { key: Q,           mods: Alt,             chars: "\x1Bq"           }
  - { key: Q,           mods: Alt|Shift,       chars: "\x1BQ"           }
  - { key: R,           mods: Alt,             chars: "\x1Br"           }
  - { key: R,           mods: Alt|Shift,       chars: "\x1BR"           }
  - { key: S,           mods: Alt,             chars: "\x1Bs"           }
  - { key: S,           mods: Alt|Shift,       chars: "\x1BS"           }
  - { key: T,           mods: Alt,             chars: "\x1Bt"           }
  - { key: T,           mods: Alt|Shift,       chars: "\x1BT"           }
  - { key: U,           mods: Alt,             chars: "\x1Bu"           }
  - { key: U,           mods: Alt|Shift,       chars: "\x1BU"           }
  - { key: V,           mods: Alt,             chars: "\x1Bv"           }
  - { key: V,           mods: Alt|Shift,       chars: "\x1BV"           }
  - { key: W,           mods: Alt,             chars: "\x1Bw"           }
  - { key: W,           mods: Alt|Shift,       chars: "\x1BW"           }
  - { key: X,           mods: Alt,             chars: "\x1Bx"           }
  - { key: X,           mods: Alt|Shift,       chars: "\x1BX"           }
  - { key: Y,           mods: Alt,             chars: "\x1By"           }
  - { key: Y,           mods: Alt|Shift,       chars: "\x1BY"           }
  - { key: Z,           mods: Alt,             chars: "\x1Bz"           }
  - { key: Z,           mods: Alt|Shift,       chars: "\x1BZ"           }
  - { key: Key1,        mods: Alt,             chars: "\x1B1"           }
  - { key: Key1,        mods: Alt|Shift,       chars: "\x1B!"           }
  - { key: Key2,        mods: Alt,             chars: "\x1B2"           }
  - { key: Key2,        mods: Alt|Shift,       chars: "\x1B#"           }
  - { key: Key3,        mods: Alt,             chars: "\x1B3"           }
  - { key: Key3,        mods: Alt|Shift,       chars: "\x1B#"           }
  - { key: Key4,        mods: Alt,             chars: "\x1B4"           }
  - { key: Key4,        mods: Alt|Shift,       chars: "\x1B$"           }
  - { key: Key5,        mods: Alt,             chars: "\x1B5"           }
  - { key: Key5,        mods: Alt|Shift,       chars: "\x1B%"           }
  - { key: Key6,        mods: Alt,             chars: "\x1B6"           }
  - { key: Key6,        mods: Alt|Shift,       chars: "\x1B^"           }
  - { key: Key7,        mods: Alt,             chars: "\x1B7"           }
  - { key: Key7,        mods: Alt|Shift,       chars: "\x1B&"           }
  - { key: Key8,        mods: Alt,             chars: "\x1B8"           }
  - { key: Key8,        mods: Alt|Shift,       chars: "\x1B*"           }
  - { key: Key9,        mods: Alt,             chars: "\x1B9"           }
  - { key: Key9,        mods: Alt|Shift,       chars: "\x1B("           }
  - { key: Key0,        mods: Alt,             chars: "\x1B0"           }
  - { key: Key0,        mods: Alt|Shift,       chars: "\x1B)"           }
  - { key: Minus,       mods: Alt,             chars: "\x1B-"           }
  - { key: Minus,       mods: Alt|Shift,       chars: "\x1B_"           }
  - { key: Equals,      mods: Alt,             chars: "\x1B="           }
  - { key: Equals,      mods: Alt|Shift,       chars: "\x1B+"           }
  - { key: LBracket,    mods: Alt,             chars: "\x1B["           }
  - { key: LBracket,    mods: Alt|Shift,       chars: "\x1B{"           }
  - { key: RBracket,    mods: Alt,             chars: "\x1B]"           }
  - { key: RBracket,    mods: Alt|Shift,       chars: "\x1B}"           }
  - { key: Backslash,   mods: Alt,             chars: "\x1B\\"          }
  - { key: Backslash,   mods: Alt|Shift,       chars: "\x1B|"           }
  - { key: Semicolon,   mods: Alt,             chars: "\x1B;"           }
  - { key: Semicolon,   mods: Alt|Shift,       chars: "\x1B:"           }
  - { key: Apostrophe,  mods: Alt,             chars: "\x1B'"           }
  - { key: Apostrophe,  mods: Alt|Shift,       chars: "\x1B\""          }
  - { key: Comma,       mods: Alt,             chars: "\x1B,"           }
  - { key: Comma,       mods: Alt|Shift,       chars: "\x1B<"           }
  - { key: Period,      mods: Alt,             chars: "\x1B."           }
  - { key: Period,      mods: Alt|Shift,       chars: "\x1B>"           }
  - { key: Slash,       mods: Alt,             chars: "\x1B/"           }
  - { key: Slash,       mods: Alt|Shift,       chars: "\x1B?"           }
  - { key: Grave,       mods: Alt,             chars: "\x1B`"           }
  - { key: Grave,       mods: Alt|Shift,       chars: "\x1B~"           }
alt_send_esc: false

There may be a few key combinations that others use, is there anyway we can make a standard MacOS config?

All 50 comments

What happens if you remove these bindings? This should be the case by default, since the alt modifier will automatically send escape codes.

Also does it produce ^[i^b or ^[i^B?

@chrisduerr with my settings it produced small letter b. Please note that the carrot before the small letter b (mentioned in my original post above) is different than actual character that you would get by pressing it on the keyboard!

I removed my alacrity.yml file & restarted, which I believe causes alacrity to start with alt_send_esc: true as default.
Option+F followed by B produces Æ’b
Option+I followed by B produces ˆb (again the carrot is not standard here)

So it seems, at least on my end, the recent changes to automatically send escape code is not working!

More examples (with default settings):
Option+O followed by B produces øb
Option+A followed by B produces åb

It should send ^[f and ^[i, can someone else repro this on macOS?

I just built alacrity on my laptop (macOS) too and it has the same issue as above!

Might be interesting to show the output of alacritty --print-events when those characters are input.

In theory, it should print that the alt key is held down.

Alacritty is run from iTerm with default settings:

Option+I followed by B produces this output (produces ˆb )

Option+F followed by B produces this output (produces Æ’b )

Alacritty is run from iTerm with my key bind settings:

Option+I followed by B produces this output (produces ^[iˆb )

Option+F followed by B produces this output (produces ^[fb )

@spamwax Is this with alt_send_esc: true in both scenarios?

in first one, I'm using the default settings where as you mentioned that setting is true.
in second one I do explicitly set it to true.

It shouldn't matter for the second one since keybindings automatically suppress alt escape characters anyways.

I've got a little diff which should help with debugging this. It prints the exact characters that are written to the pty and bypasses potential issues with shell/cat. I'm interested in what this outputs when you use the default config without modified key bindings.

diff --git a/src/input.rs b/src/input.rs
index 65b7b6c..a9d3207 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -748,7 +748,10 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
                 && self.ctx.last_modifiers().alt
                 && utf8_len == 1
             {
+                println!("WRITING ^[{}", c);
                 bytes.insert(0, b'\x1b');
+            } else {
+                println!("WRITING {}", c);
             }

             self.ctx.write_to_pty(bytes);

In theory this should print the following for you when pressing Option+I -> B:

WRITING ^[^
WRITING b

And I'd assume this is output when pressing Option+F -> B:

WRITING ^[f
WRITING b

I get identical outcomes! (Option+I -> B)

with default settings:

[2019-01-19 21:11] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140402958181952)), event: ReceivedCharacter('ˆ') }
WRITING ˆ
[2019-01-19 21:11] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140402958181952)), event: ReceivedCharacter('b') }
WRITING b

with my key bindings I get:

[2019-01-19 21:08] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140196043588400)), event: ReceivedCharacter('ˆ') }
WRITING ˆ
[2019-01-19 21:08] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140196043588400)), event: ReceivedCharacter('b') }
WRITING b

for Option+F -> B (default settings)

[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 58, state: Pressed, virtual_keycode: Some(LAlt), modifiers: ModifiersState { shift: false, ctrl: false, alt: true, logo: false } } } }
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 3, state: Pressed, virtual_keycode: Some(F), modifiers: ModifiersState { shift: false, ctrl: false, alt: true, logo: false } } } }
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: ReceivedCharacter('Æ’') }
WRITING Æ’
[2019-01-19 21:16] [INFO] glutin event: Awakened
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 3, state: Released, virtual_keycode: Some(F), modifiers: ModifiersState { shift: false, ctrl: false, alt: true, logo: false } } } }
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 58, state: Released, virtual_keycode: Some(LAlt), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } } }
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 11, state: Pressed, virtual_keycode: Some(B), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } } }
[2019-01-19 21:16] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140549080384736)), event: ReceivedCharacter('b') }
WRITING b

Option+F -> B (my settings)

[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 58, state: Pressed, virtual_keycode: Some(LAlt), modifiers: ModifiersState { shift: false, ctrl: false, alt: true, logo: false } } } }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 3, state: Pressed, virtual_keycode: Some(F), modifiers: ModifiersState { shift: false, ctrl: false, alt: true, logo: false } } } }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: ReceivedCharacter('Æ’') }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 58, state: Released, virtual_keycode: Some(LAlt), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } } }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 3, state: Released, virtual_keycode: Some(F), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } } }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 11, state: Pressed, virtual_keycode: Some(B), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } } }
[2019-01-19 21:17] [INFO] glutin event: WindowEvent { window_id: WindowId(Id(140313842782624)), event: ReceivedCharacter('b') }
WRITING b

Okay, so I can see two issues here.

The first issue is that the keys you're pressing are automatically being converted to modified keys. So LAlt + F -> Æ’. And LAlt + i -> ^. This is a more complicated issue and I'd like to put this on hold until I've figured out the other one.

The second issue is that for some reason alt isn't sending escape sequences. To figure out why exactly that's not the case, I've created another small diff which should print even more debug info in the case that no escapes are written:

diff --git a/src/input.rs b/src/input.rs
index 65b7b6c..b9efd0e 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -748,7 +748,14 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
                 && self.ctx.last_modifiers().alt
                 && utf8_len == 1
             {
+                println!("WRITING ^[{}", c);
                 bytes.insert(0, b'\x1b');
+            } else {
+                println!("RECEIVED COUNT: {}", self.ctx.received_count());
+                println!("ALT SEND ESC: {}", self.alt_send_esc);
+                println!("UTF8 LEN: {}", utf8_len);
+                println!("ALT: {}", self.ctx.last_modifiers().alt);
+                println!("WRITING {}", c);
             }

             self.ctx.write_to_pty(bytes);

Thanks a ton for your cooperation. Hopefully this can be quickly resolved.

while i apply the path, i'd like to mention that behavior like LAlt + F -> Æ’ seems to be mac specific and is related to diacritic as fas as I can tell. According to some, that PR has caused issues with Meta/Option key.

The issues discussed in #209 should be resolved with the new alt_send_esc option. Since that allows not sending an escape sequence anymore.

The problem with your setup though is that it's not actually sending f, but Æ’. And that it's sending no escape sequence. So I think it's a bit different, though I'm not super familiar with macOS.

Ideally we'd want it to send ^[Æ’, that much I would understand. Since you're pressing alt it should send the escape sequence. The Æ’ vs f issue would still be present, but that's something that might need discussion with the window library Alacritty is using.

Default settings:

Option+I -> B gives this
Option+F -> B gives this

Ah, so it turns out that these characters have a utf8 length of 2, so that's why the escape characters aren't printed.

So the problem is just that when pressing alt and hitting f/i, that it's putting down modified characters. I think the only way to resolve this problem would be to request with our window library to not send combined characters whenever the alt key is held down and the alt_send_esc option is enabled.

so other than filing a bug, what would help motivate them to resolve this faster? :)

I'm not sure if this is something that will be included in winit actually since most applications do not have this problem.

This is kinda a mess macOS has created by using alt instead of something like an AltGr key. I'm not sure if there's a good solution for this problem.

Reading through this whole thread again though, there are some new insights I have obtained. My main focus so far was making this work without having to add any key bindings, which should be the goal, however I kinda ignored that it didn't work with keybindings either.

In theory, this should work great when manually adding key bindings. However it clearly does not. Alacritty currently ignores all characters while a keybinding is triggered. However that doesn't seem to be working here.

This is the relevant part of your debug output (paraphrased):

LAlt Down
I Down, Alt pressed
I Up, Alt pressed
LAlt Up
B Down
Received character ˆ
Received character b

Looking at this, it seems like the weird ^ character is received after the B character has been pressed. However it should be received after I Down, Alt pressed has been received.

Would you mind verifying that this is really the case? That would be a separate issue in winit and I'm not sure what's going on. I'd assume it's true that Option + I is what should create the ^ character, right? Does the ReceivedCharacter('^') really only pop up when B is pressed? Or does it pop up when B is not pressed, but it's just always after LAlt Up?

Based on alacritty output, this is what's happening:

LAlt Down
I Down, Alt pressed
I Up, Alt pressed
LAlt Up
# No ReceivedCharacter message in output

at this point i waited one minute then pressed B, then this is what got printed:

B Down, No modifier
ReceivedCharacter('ˆ')
# ... your patch debug outputs
ReceivedCharacter('b')
# ... your patch debug outputs
B Up, No modifier

However you may be right that wininit is messing the order here, as in a native macOS app when I press Option+I, the app actually shows a weird ^ indicating it's waiting for next stroke:

untitled

So it seems wininit is following macOS convention and waiting for next key before actually sending stuff to its clients.

Okay, so I think I've got this figured out now. The ^ is actually a dead key which goes over other characters, so the only reason why the bindings won't work is because this character isn't received until the next one is pressed.

Since I now actually know what exactly is going on, I'll open an issue upstream and link it here. Maybe we can figure something out.

I've created an issue upstream to track a solution for this problem:
https://github.com/tomaka/winit/issues/768

This is a duplicate of #1610 .

@eraserhd Thanks a lot for letting me know. Closing the other issue as duplicate since this one contains a lot more information about the issue at hand.

I have this issue

Based on alacritty output, this is what's happening:

LAlt Down
I Down, Alt pressed
I Up, Alt pressed
LAlt Up
# No ReceivedCharacter message in output

at this point i waited one minute then pressed B, then this is what got printed:

B Down, No modifier
ReceivedCharacter('ˆ')
# ... your patch debug outputs
ReceivedCharacter('b')
# ... your patch debug outputs
B Up, No modifier

However you may be right that wininit is messing the order here, as in a native macOS app when I press Option+I, the app actually shows a weird ^ indicating it's waiting for next stroke:

untitled

So it seems wininit is following macOS convention and waiting for next key before actually sending stuff to its clients.

I can reproduce the same issue, but only when I have "ABC - Extended" keyboard layout selected. This is what apple formerly called "US ANSI - International" keyboard layout. It is similar, but a bit different than "US ANSI - International" on windows (not sure about Linux). For example, to apply an accent acute on the previous letter, you can press Opt+Shift+e, and so on. Other such shortcuts apparently prepare _for the next_ keystroke, as shown in the gif.

When I select "ABC", the issue goes away 😃

With ABC/US-ANSI, there are no such "next-keystroke-modifiers" sent, only straight keycodes but for other characters like Æ’ - these are no problem, IF the shortcut is overridden in alacritty.yml.

I just found out about Alacritty, and while excited to use it, found that my fingers have the key bindings so ingrained in them. So, I fixed this problem solely in my alacritty.yml file. If this helps anyone else, here is my config. This makes Alacritty behave like Terminal.app. Key repeats and diacritics are all fixed.

env:
  TERM: xterm-24bits
key_bindings:
  - { key: N,           mods: Command,         action: SpawnNewInstance }
  - { key: PageUp,                             action: ScrollPageUp     }
  - { key: PageUp,      mode: Alt,             chars: "\x1B[5~"         }
  - { key: PageUp,      mods: Shift,           chars: "\x1B[5~"         }
  - { key: PageDown,                           action: ScrollPageDown   }
  - { key: PageDown,    mode: Alt,             chars: "\x1B[6~"         }
  - { key: PageDown,    mods: Shift,           chars: "\x1B[6~"         }
  - { key: Home,                               action: ScrollToTop      }
  - { key: Home,        mode: Alt,             chars: "\x1BOH"          }
  - { key: Home,        mods: Shift,           chars: "\x1B[H"          }
  - { key: End,                                action: ScrollToBottom   }
  - { key: End,         mode: Alt,             chars: "\x1BOF"          }
  - { key: End,         mods: Shift,           chars: "\x1B[F"          }
  - { key: Tab,         mods: Alt,             chars: "\x1B\t"          }
  - { key: Tab,         mods: Alt|Shift,       chars: "\x1B\x1B[Z"      }
  - { key: Back,                               chars: "\x7F"            }
  - { key: Back,        mods: Alt,             chars: "\x1B\x7F"        }
  - { key: Back,        mods: Alt|Shift,       chars: "\x1B\x08"        }
  - { key: Space,       mods: Control,         chars: "\x00"            }
  - { key: Space,       mods: Alt,             chars: "\x20"            }
  - { key: Left,        mods: Alt,             chars: "\x1Bb"           }
  - { key: Left,        mods: Alt|Shift,       chars: "\x1B\x1B[D"      }
  - { key: Right,       mods: Alt,             chars: "\x1Bf"           }
  - { key: Right,       mods: Alt|Shift,       chars: "\x1B\x1B[C"      }
  - { key: Down,        mods: Alt,             chars: "\x1B\x1B[B"      }
  - { key: Down,        mods: Alt|Shift,       chars: "\x1B\x1B[B"      }
  - { key: Up,          mods: Alt,             chars: "\x1B\x1B[A"      }
  - { key: Up,          mods: Alt|Shift,       chars: "\x1B\x1B[A"      }
  - { key: A,           mods: Alt,             chars: "\x1Ba"           }
  - { key: A,           mods: Alt|Shift,       chars: "\x1BA"           }
  - { key: B,           mods: Alt,             chars: "\x1Bb"           }
  - { key: B,           mods: Alt|Shift,       chars: "\x1BB"           }
  - { key: C,           mods: Alt,             chars: "\x1Bc"           }
  - { key: C,           mods: Alt|Shift,       chars: "\x1BC"           }
  - { key: D,           mods: Alt,             chars: "\x1Bd"           }
  - { key: D,           mods: Alt|Shift,       chars: "\x1BD"           }
  - { key: E,           mods: Alt,             chars: "\x1Be"           }
  - { key: E,           mods: Alt|Shift,       chars: "\x1BE"           }
  - { key: F,           mods: Alt,             chars: "\x1Bf"           }
  - { key: F,           mods: Alt|Shift,       chars: "\x1BF"           }
  - { key: G,           mods: Alt,             chars: "\x1Bg"           }
  - { key: G,           mods: Alt|Shift,       chars: "\x1BG"           }
  - { key: H,           mods: Alt,             chars: "\x1Bh"           }
  - { key: H,           mods: Alt|Shift,       chars: "\x1BH"           }
  - { key: I,           mods: Alt,             chars: "\x1Bi"           }
  - { key: I,           mods: Alt|Shift,       chars: "\x1BI"           }
  - { key: J,           mods: Alt,             chars: "\x1Bj"           }
  - { key: J,           mods: Alt|Shift,       chars: "\x1BJ"           }
  - { key: K,           mods: Alt,             chars: "\x1Bk"           }
  - { key: K,           mods: Alt|Shift,       chars: "\x1BK"           }
  - { key: L,           mods: Alt,             chars: "\x1Bl"           }
  - { key: L,           mods: Alt|Shift,       chars: "\x1BL"           }
  - { key: M,           mods: Alt,             chars: "\x1Bm"           }
  - { key: M,           mods: Alt|Shift,       chars: "\x1BM"           }
  - { key: N,           mods: Alt,             chars: "\x1Bn"           }
  - { key: N,           mods: Alt|Shift,       chars: "\x1BN"           }
  - { key: O,           mods: Alt,             chars: "\x1Bo"           }
  - { key: O,           mods: Alt|Shift,       chars: "\x1BO"           }
  - { key: P,           mods: Alt,             chars: "\x1Bp"           }
  - { key: P,           mods: Alt|Shift,       chars: "\x1BP"           }
  - { key: Q,           mods: Alt,             chars: "\x1Bq"           }
  - { key: Q,           mods: Alt|Shift,       chars: "\x1BQ"           }
  - { key: R,           mods: Alt,             chars: "\x1Br"           }
  - { key: R,           mods: Alt|Shift,       chars: "\x1BR"           }
  - { key: S,           mods: Alt,             chars: "\x1Bs"           }
  - { key: S,           mods: Alt|Shift,       chars: "\x1BS"           }
  - { key: T,           mods: Alt,             chars: "\x1Bt"           }
  - { key: T,           mods: Alt|Shift,       chars: "\x1BT"           }
  - { key: U,           mods: Alt,             chars: "\x1Bu"           }
  - { key: U,           mods: Alt|Shift,       chars: "\x1BU"           }
  - { key: V,           mods: Alt,             chars: "\x1Bv"           }
  - { key: V,           mods: Alt|Shift,       chars: "\x1BV"           }
  - { key: W,           mods: Alt,             chars: "\x1Bw"           }
  - { key: W,           mods: Alt|Shift,       chars: "\x1BW"           }
  - { key: X,           mods: Alt,             chars: "\x1Bx"           }
  - { key: X,           mods: Alt|Shift,       chars: "\x1BX"           }
  - { key: Y,           mods: Alt,             chars: "\x1By"           }
  - { key: Y,           mods: Alt|Shift,       chars: "\x1BY"           }
  - { key: Z,           mods: Alt,             chars: "\x1Bz"           }
  - { key: Z,           mods: Alt|Shift,       chars: "\x1BZ"           }
  - { key: Key1,        mods: Alt,             chars: "\x1B1"           }
  - { key: Key1,        mods: Alt|Shift,       chars: "\x1B!"           }
  - { key: Key2,        mods: Alt,             chars: "\x1B2"           }
  - { key: Key2,        mods: Alt|Shift,       chars: "\x1B#"           }
  - { key: Key3,        mods: Alt,             chars: "\x1B3"           }
  - { key: Key3,        mods: Alt|Shift,       chars: "\x1B#"           }
  - { key: Key4,        mods: Alt,             chars: "\x1B4"           }
  - { key: Key4,        mods: Alt|Shift,       chars: "\x1B$"           }
  - { key: Key5,        mods: Alt,             chars: "\x1B5"           }
  - { key: Key5,        mods: Alt|Shift,       chars: "\x1B%"           }
  - { key: Key6,        mods: Alt,             chars: "\x1B6"           }
  - { key: Key6,        mods: Alt|Shift,       chars: "\x1B^"           }
  - { key: Key7,        mods: Alt,             chars: "\x1B7"           }
  - { key: Key7,        mods: Alt|Shift,       chars: "\x1B&"           }
  - { key: Key8,        mods: Alt,             chars: "\x1B8"           }
  - { key: Key8,        mods: Alt|Shift,       chars: "\x1B*"           }
  - { key: Key9,        mods: Alt,             chars: "\x1B9"           }
  - { key: Key9,        mods: Alt|Shift,       chars: "\x1B("           }
  - { key: Key0,        mods: Alt,             chars: "\x1B0"           }
  - { key: Key0,        mods: Alt|Shift,       chars: "\x1B)"           }
  - { key: Minus,       mods: Alt,             chars: "\x1B-"           }
  - { key: Minus,       mods: Alt|Shift,       chars: "\x1B_"           }
  - { key: Equals,      mods: Alt,             chars: "\x1B="           }
  - { key: Equals,      mods: Alt|Shift,       chars: "\x1B+"           }
  - { key: LBracket,    mods: Alt,             chars: "\x1B["           }
  - { key: LBracket,    mods: Alt|Shift,       chars: "\x1B{"           }
  - { key: RBracket,    mods: Alt,             chars: "\x1B]"           }
  - { key: RBracket,    mods: Alt|Shift,       chars: "\x1B}"           }
  - { key: Backslash,   mods: Alt,             chars: "\x1B\\"          }
  - { key: Backslash,   mods: Alt|Shift,       chars: "\x1B|"           }
  - { key: Semicolon,   mods: Alt,             chars: "\x1B;"           }
  - { key: Semicolon,   mods: Alt|Shift,       chars: "\x1B:"           }
  - { key: Apostrophe,  mods: Alt,             chars: "\x1B'"           }
  - { key: Apostrophe,  mods: Alt|Shift,       chars: "\x1B\""          }
  - { key: Comma,       mods: Alt,             chars: "\x1B,"           }
  - { key: Comma,       mods: Alt|Shift,       chars: "\x1B<"           }
  - { key: Period,      mods: Alt,             chars: "\x1B."           }
  - { key: Period,      mods: Alt|Shift,       chars: "\x1B>"           }
  - { key: Slash,       mods: Alt,             chars: "\x1B/"           }
  - { key: Slash,       mods: Alt|Shift,       chars: "\x1B?"           }
  - { key: Grave,       mods: Alt,             chars: "\x1B`"           }
  - { key: Grave,       mods: Alt|Shift,       chars: "\x1B~"           }
alt_send_esc: false

There may be a few key combinations that others use, is there anyway we can make a standard MacOS config?

Ah, I see now, when I read the original problem, and try kak out, I can see the problem. I think I see how to fix it in winit. Shall I take it up there?

There, I updated rust-windowing/winit#768. With that example pull request referenced, I indeed see ^[ib in kak now.

Does this help?

If anyone would like to test, the pull request went through a few rounds. I have an open pull request that fixes this issue:

https://github.com/rust-windowing/winit/pull/1449

If anyone can test to provide support for the pull request, there is a single change to alacritty:

diff --git a/alacritty/src/window.rs b/alacritty/src/window.rs
index 71327ba..7bc555a 100644
--- a/alacritty/src/window.rs
+++ b/alacritty/src/window.rs
@@ -265,7 +265,8 @@ impl Window {
             .with_title(title)
             .with_visible(false)
             .with_transparent(true)
-            .with_maximized(window_config.startup_mode() == StartupMode::Maximized);
+            .with_maximized(window_config.startup_mode() == StartupMode::Maximized)
+            .with_ignore_alt_modifier(true);

         match window_config.decorations {
             Decorations::Full => window,

To make alacritty use mentioned PR you should also apply

diff --git a/Cargo.toml b/Cargo.toml
index 415ceb9..e0db73b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,3 +13,4 @@ incremental = false

 [patch.crates-io]
 servo-freetype-sys = { path = "servo-freetype-proxy" }
+winit = { git = "https://github.com/kjmph/winit", branch = "fix-alt-modifier" }

@kjmph I am about to build the PR and run some tests, do you want the results of tests here or in the winit's PR?

@spamwax I'd recommend reporting feedback directly in the upstream PR.

@kjmph Would this prevent people from using the diacritics if they want to do that instead of remapping them? That seems like it would be a regression for some people. (Not to be annoying, as this patch is how I would need it.)

Would this prevent people from using the diacritics if they want to do that instead of remapping them? That seems like it would be a regression for some people. (Not to be annoying, as this patch is how I would need it.)

This would definitely be configurable.

@chrisduerr based on simple test the original issue reported here is fixed.
However I see some strange behavior in terminal programs such as neovim.
The small patches you provided here are no longer usable given the internal restructuring of the Alacritty's code.
is there any other test/patch you want me to run against before reporting the full results to upstream?

@spamwax are there any pointers you can give about the neovim behavior? It would be great if I can reproduce it.

@chrisduerr @kjmph In the attached video, I am just moving around in neovim and doing a simple search. Note the lack of coloring and also how random characters appear all over the code and bottom of vim as I am just moving the cursor around!
I am also including the non-patched version for comparison.

alac-nvim-patch

nvim-alac

Interesting part is that when I use [asciinema.org] to record what actually happens in terminal and then play it back, there are no character scrambling but it is still lacking color:

@spamwax the patch only affects input characters, etc. It doesn't do anything about colors, etc. How did you run alacritty? Are you running both of them with cargo run --release with and without patch applied from the same commit on master?

I tried searching in neovim using the patch locally, and I couldn't reproduce scrambling. I concur with @kchibisov that the patch in question only impacts input.

@kchibisov @kjmph
Yes, the issue was from my side. But not sure root cause for it:

  • I had used the Makefile which I believe does the --release version and creates a macOS app bundle
  • Also to run the patched version I was doing open ./target/release/osx/Alacritty.app

I did a make binary followed by make app and copied the bundle to /Application folder.
So far the issue with kakoune editor is resolved and doing some simple /bin/cat tests shows that it's working at intended.

Great news that your issue is fixed @spamwax! I had a request upstream to move the change into configuration, so that when option_as_alt set to true it will toggle this behavior on. I held on modifying the pull request till you had tested using the original with_ignore_alt_modifier patch. Are you good with me modifying the upstream pull request? There is no change to the event processing, it is purely a cosmetic change.

yes I am. thanks for your PR.
can winit distinguish between L-Option, R-Option?
If answer is yes, then maybe it's possible to keep both behavior of alt, i.e.
L-Option can be set to send alt and R-Option continue to modify characters before sending it to alacritty (more acting like a AltGr?

I don't believe it can distinguish at the event time. The ALT modifier is set when the alphanumeric characters are pressed, and to know if it was L-Option or R-Option there would need to be state captured; which is error prone. I'll go ahead and push to the winit PR.

I just found out about Alacritty, and while excited to use it, found that my fingers have the key bindings so ingrained in them. So, I fixed this problem solely in my alacritty.yml file. If this helps anyone else, here is my config. This makes Alacritty behave like Terminal.app. Key repeats and diacritics are all fixed.

There may be a few key combinations that others use, is there anyway we can make a standard MacOS config?

Hi there. Where are we with all this? I'm still rather confused and although the mappings listed in the referenced post work for most cases they don't cover all key-combos and I'm running into more and more things that don't work as expected (especially in emacs which relies heavily on all kinds of key combos).

Are the patches to the upstream library integrated yet? Is there a branch of this code that fixes things more permenently?

Thanks in advance for your help.

Jamie

Are the patches to the upstream library integrated yet? Is there a branch of this code that fixes things more permenently?

No to both of those. It's work in progress, but there's very little macOS development capacity.

Hello @jkp, I live in emacs and running the patch listed in rust-windowing/winit#1449 has covered all emacs bindings that I can realistically test as one person. Would you mind testing out the branch listed in the PR? I can always update against the latest master if you have problems building. I've been running the same custom binaries for most of this year, so the branch may need to be refreshed.

Hi

Very willing to build and test a version of Alacritty with your fixes
in. Can you give me clear instructions as to what I need to do to build
something with your patches in? I have the code checked out and rust
installed and have built master sucessfully. Which branch do I need to
checkout?

Thanks

Kyle Hubert notifications@github.com writes:

Hello @jkp, I live in emacs and running the patch listed in rust-windowing/
winit#1449 has covered all emacs bindings that I can realistically test as one
person. Would you mind testing out the branch listed in the PR? I can always
update against the latest master if you have problems building. I've been
running the same custom binaries for most of this year, so it may need to be
refreshed.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.*

OK I did three things to get a build with this patch included:

  • Pulled your branch of winit and merged in the v0.23.0 branch from the origin to make the library compatible with the version being used in the master branch of alacritty.
  • Added a patch to Cargo.toml to pull in the my locally patched winit branch.
  • Added the hard-coded line to window.rs (.with_ignore_alt_modifier(true);).

I've built the code and am running the binary but things still don't work as I expect. Maybe I just don't understand what you've done here (to be fair I haven't read the patches properly so I'm unversed). I'm expecting these fixes to make it possible to have my "alt" key act as a meta key (as per terminal.app). Do I need to do something in my config? Do I still need the key mappings that you originally listed above (those seemed like workarounds so i was assuming those could be removed once things work properly).

Thanks for the pointers. Would love to help get this tested and merged and am at your disposal to try to make that happen.

Jamie

OK - I added one more line to window.rs to hard code .set_option_as_alt(true) and now this works as expected and I can remove all the custom mappings in my config.

I'll run with this for a while but initially it looks good. One question that you may know the answer to @kjmph - I have some emacs bindings that use both ctl and meta (eg C-M-) but with this patch it seems that emacs only sees M-\ when I press all three keys together. I captured the events that alacritty sees and they look correct:

[2020-11-21 15:36:51.497506000] [INFO ] [alacritty] glutin event: WindowEvent { window_id: WindowId(Id(140448397406320)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 42, state: Pressed, virtual_keycode: Some(Backslash), modifiers: CTRL | ALT }, is_synthetic: false } }
[2020-11-21 15:36:51.584908000] [INFO ] [alacritty] glutin event: WindowEvent { window_id: WindowId(Id(140448397406320)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 42, state: Released, virtual_keycode: Some(Backslash), modifiers: CTRL | ALT }, is_synthetic: false } }
[2020-11-21 15:36:53.009238000] [INFO ] [alacritty] glutin event: WindowEvent { window_id: WindowId(Id(140448397406320)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 59, state: Released, virtual_keycode: Some(LControl), modifiers: ALT }, is_synthetic: false } }
[2020-11-21 15:36:53.014028000] [INFO ] [alacritty] glutin event: WindowEvent { window_id: WindowId(Id(140448397406320)), event: KeyboardInput { device_id: DeviceId(DeviceId), input: KeyboardInput { scancode: 58, state: Released, virtual_keycode: Some(LAlt), modifiers: (empty) }, is_synthetic: false } }

Any ideas whats going on?

Some further info pertinent to the issue i mentioned above.

  • This is certainly due to an issue in the terminal emulation layer. The cocoa emacs app behaves correctly, and it also works under iterm2.
  • I had some other issues under iterm2 and today I discovered an option to use a different library for keyboard event handling under that terminal emulator seems to have fixed _all_ my issues. Could it be worth looking at integrating it into alacritty? Details are here.

Thanks for the test case! I can reproduce it. It looks at first glance that if you have an Escape key on a Mac the escape key is sent through as ReceivedCharacter('\u{1b}') and then CTRL is a modifier for the \ input, yet sent through only as a modifiers: CTRL | ALT when Alt is used as Meta. Let me look into the code and see if this is a straight-forward change.

Sorry for the delay, day job.. The underlying problem is that when CTRL is used, the diacritical marks are not applied to the characters. LOGO and SHIFT don't exhibit this, so charactersIgnoringModifiers will return \ instead of \u{1c}. Thus, CTRL is a special case. emacs picks up the key combination with the latest commit I just pushed to the proposed branch.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NickeZ picture NickeZ  Â·  50Comments

net picture net  Â·  112Comments

multun picture multun  Â·  52Comments

theduke picture theduke  Â·  69Comments

fuine picture fuine  Â·  131Comments