-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Fix Japanese IME input handling in message composer #30324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -104,6 +104,13 @@ | |
onPaste?(event: Event | SyntheticEvent, data: DataTransfer, model: EditorModel): boolean; | ||
} | ||
|
||
interface IPlatformInfo { | ||
isElectron: boolean; | ||
isWindows: boolean; | ||
isMac: boolean; | ||
isSafari: boolean; | ||
} | ||
|
||
interface IState { | ||
useMarkdown: boolean; | ||
showPillAvatar: boolean; | ||
|
@@ -122,7 +129,7 @@ | |
private modifiedFlag = false; | ||
private isIMEComposing = false; | ||
private hasTextSelected = false; | ||
private readonly isSafari: boolean; | ||
private readonly platformInfo: IPlatformInfo; | ||
|
||
private _isCaretAtEnd = false; | ||
private lastCaret!: DocumentOffset; | ||
|
@@ -143,11 +150,22 @@ | |
showVisualBell: false, | ||
}; | ||
|
||
const ua = navigator.userAgent.toLowerCase(); | ||
this.isSafari = ua.includes("safari/") && !ua.includes("chrome/"); | ||
this.platformInfo = this.detectPlatform(); | ||
this.configureEmoticonAutoReplace(); | ||
} | ||
|
||
private detectPlatform(): IPlatformInfo { | ||
const ua = navigator.userAgent.toLowerCase(); | ||
const platform = navigator.platform || ""; | ||
|
||
return { | ||
isElectron: !!(window as any).electron || ua.includes('electron'), | ||
isWindows: ua.includes('win') || platform.includes('Win'), | ||
isMac: ua.includes('mac') || platform.includes('Mac'), | ||
isSafari: ua.includes("safari/") && !ua.includes("chrome/"), | ||
}; | ||
} | ||
|
||
Comment on lines
+157
to
+168
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is mixing platform, browser etc |
||
public componentDidUpdate(prevProps: IProps): void { | ||
// We need to re-check the placeholder when the enabled state changes because it causes the | ||
// placeholder element to remount, which gets rid of the `::before` class. Re-evaluating the | ||
|
@@ -275,32 +293,36 @@ | |
|
||
private onCompositionEnd = (): void => { | ||
this.isIMEComposing = false; | ||
// some browsers (Chrome) don't fire an input event after ending a composition, | ||
// so trigger a model update after the composition is done by calling the input handler. | ||
|
||
// however, modifying the DOM (caused by the editor model update) from the compositionend handler seems | ||
// to confuse the IME in Chrome, likely causing https://github.com/vector-im/element-web/issues/10913 , | ||
// so we do it async | ||
|
||
// however, doing this async seems to break things in Safari for some reason, so browser sniff. | ||
|
||
if (this.isSafari) { | ||
// IME確定後の入力イベントをプラットフォームに応じて処理 | ||
|
||
Comment on lines
+296
to
+297
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep the previous comment. Also the comments should be in english |
||
const triggerInput = (): void => { | ||
this.onInput({ inputType: "insertCompositionText" }); | ||
}; | ||
|
||
if (this.platformInfo.isMac && this.platformInfo.isSafari) { | ||
// Safariでは同期実行 | ||
triggerInput(); | ||
} else if (this.platformInfo.isElectron) { | ||
// Electronでは確実に非同期実行 | ||
setTimeout(triggerInput, 0); | ||
Comment on lines
+305
to
+307
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to do that? |
||
} else { | ||
Promise.resolve().then(() => { | ||
this.onInput({ inputType: "insertCompositionText" }); | ||
}); | ||
// その他のブラウザはPromiseで非同期実行 | ||
Promise.resolve().then(triggerInput); | ||
} | ||
}; | ||
|
||
public isComposing(event: React.KeyboardEvent): boolean { | ||
// 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)); | ||
// IME composition状態の統合的な判定 | ||
const nativeEvent = event.nativeEvent; | ||
const isNativeComposing = nativeEvent && nativeEvent.isComposing; | ||
|
||
// プラットフォーム固有の追加チェック | ||
const isPlatformSpecificComposing = ( | ||
(this.platformInfo.isMac && this.platformInfo.isSafari && event.which === 229) || | ||
((this.platformInfo.isWindows || this.platformInfo.isElectron) && event.which === 229) | ||
); | ||
|
||
return !!(this.isIMEComposing || isNativeComposing || isPlatformSpecificComposing); | ||
Comment on lines
+315
to
+325
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the original comments and please explain why is it needed |
||
} | ||
|
||
private onCutCopy = (event: ClipboardEvent, type: string): void => { | ||
|
@@ -378,10 +400,12 @@ | |
|
||
private onInput = (event: Partial<InputEvent>): void => { | ||
if (!this.editorRef.current) return; | ||
// ignore any input while doing IME compositions | ||
if (this.isIMEComposing) { | ||
|
||
// IME composition中は確定イベント以外を無視 | ||
if (this.isIMEComposing && event.inputType !== "insertCompositionText") { | ||
Comment on lines
+404
to
+405
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
return; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unneeded space change |
||
this.modifiedFlag = true; | ||
const sel = document.getSelection()!; | ||
const { caret, text } = getCaretOffsetAndText(this.editorRef.current, sel); | ||
|
@@ -479,11 +503,25 @@ | |
|
||
private onKeyDown = (event: React.KeyboardEvent): void => { | ||
if (!this.editorRef.current) return; | ||
if (this.isSafari && event.which == 229) { | ||
// Swallow the extra keyDown by Safari | ||
|
||
// IME composition中は全てのキーイベントを無視 | ||
if (this.isComposing(event)) { | ||
return; | ||
} | ||
|
||
// プラットフォーム固有のIME処理 | ||
if (this.platformInfo.isMac && this.platformInfo.isSafari && event.which === 229) { | ||
// Safariの追加のkeyDownを無視 | ||
event.stopPropagation(); | ||
return; | ||
} | ||
|
||
// Windows/ElectronでのIMEキーコード229処理 | ||
if ((this.platformInfo.isWindows || this.platformInfo.isElectron) && event.which === 229) { | ||
// Windows IMEのキーコード229を適切に処理 | ||
return; | ||
} | ||
Comment on lines
+507
to
+523
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
|
||
const model = this.props.model; | ||
let handled = false; | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.