diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 2d21e9f616..061dfe2703 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -129,6 +129,7 @@ export default class BasicMessageEditor extends React.Component private modifiedFlag = false; private isIMEComposing = false; private hasTextSelected = false; + private readonly isSafari: boolean; private _isCaretAtEnd = false; private lastCaret!: DocumentOffset; @@ -149,6 +150,9 @@ export default class BasicMessageEditor extends React.Component showVisualBell: false, }; + const ua = navigator.userAgent.toLowerCase(); + this.isSafari = ua.includes("safari/") && !ua.includes("chrome/"); + this.useMarkdownHandle = SettingsStore.watchSetting( "MessageComposerInput.useMarkdown", null, @@ -308,10 +312,7 @@ export default class BasicMessageEditor extends React.Component // however, doing this async seems to break things in Safari for some reason, so browser sniff. - const ua = navigator.userAgent.toLowerCase(); - const isSafari = ua.includes("safari/") && !ua.includes("chrome/"); - - if (isSafari) { + if (this.isSafari) { this.onInput({ inputType: "insertCompositionText" }); } else { Promise.resolve().then(() => { @@ -324,6 +325,9 @@ export default class BasicMessageEditor extends React.Component // checking the event.isComposing flag just in case any browser out there // emits events related to the composition after compositionend // has been fired + + // From https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/ + // Safari emits an additional keyDown after compositionend return !!(this.isIMEComposing || (event.nativeEvent && event.nativeEvent.isComposing)); } @@ -503,6 +507,11 @@ export default class BasicMessageEditor extends React.Component private onKeyDown = (event: React.KeyboardEvent): void => { if (!this.editorRef.current) return; + if (this.isSafari && event.which == 229) { + // Swallow the extra keyDown by Safari + event.stopPropagation(); + return; + } const model = this.props.model; let handled = false;