mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
fix(shortcuts): try to fix ime composition checks (#6851)
This commit is contained in:
commit
145f89eded
@ -1,5 +1,5 @@
|
||||
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
||||
import shortcuts, { keyMatches, matchesShortcut } from "./shortcuts.js";
|
||||
import shortcuts, { keyMatches, matchesShortcut, isIMEComposing } from "./shortcuts.js";
|
||||
|
||||
// Mock utils module
|
||||
vi.mock("./utils.js", () => ({
|
||||
@ -320,4 +320,36 @@ describe("shortcuts", () => {
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isIMEComposing', () => {
|
||||
it('should return true when event.isComposing is true', () => {
|
||||
const event = { isComposing: true, keyCode: 65 } as KeyboardEvent;
|
||||
expect(isIMEComposing(event)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when keyCode is 229', () => {
|
||||
const event = { isComposing: false, keyCode: 229 } as KeyboardEvent;
|
||||
expect(isIMEComposing(event)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when both isComposing is true and keyCode is 229', () => {
|
||||
const event = { isComposing: true, keyCode: 229 } as KeyboardEvent;
|
||||
expect(isIMEComposing(event)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for normal keys', () => {
|
||||
const event = { isComposing: false, keyCode: 65 } as KeyboardEvent;
|
||||
expect(isIMEComposing(event)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when isComposing is undefined and keyCode is not 229', () => {
|
||||
const event = { keyCode: 13 } as KeyboardEvent;
|
||||
expect(isIMEComposing(event)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle null/undefined events gracefully', () => {
|
||||
expect(isIMEComposing(null as any)).toBe(false);
|
||||
expect(isIMEComposing(undefined as any)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -40,6 +40,24 @@ for (let i = 1; i <= 19; i++) {
|
||||
keyMap[`f${i}`] = [`F${i}`];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if IME (Input Method Editor) is composing
|
||||
* This is used to prevent keyboard shortcuts from firing during IME composition
|
||||
* @param e - The keyboard event to check
|
||||
* @returns true if IME is currently composing, false otherwise
|
||||
*/
|
||||
export function isIMEComposing(e: KeyboardEvent): boolean {
|
||||
// Handle null/undefined events gracefully
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Standard check for composition state
|
||||
// e.isComposing is true when IME is actively composing
|
||||
// e.keyCode === 229 is a fallback for older browsers where 229 indicates IME processing
|
||||
return e.isComposing || e.keyCode === 229;
|
||||
}
|
||||
|
||||
function removeGlobalShortcut(namespace: string) {
|
||||
bindGlobalShortcut("", null, namespace);
|
||||
}
|
||||
@ -68,6 +86,13 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
|
||||
}
|
||||
|
||||
const e = evt as KeyboardEvent;
|
||||
|
||||
// Skip processing if IME is composing to prevent shortcuts from
|
||||
// interfering with text input in CJK languages
|
||||
if (isIMEComposing(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (matchesShortcut(e, keyboardShortcut)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -8,6 +8,7 @@ import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||
import attributeService from "../services/attributes.js";
|
||||
import FindInText from "./find_in_text.js";
|
||||
import FindInCode from "./find_in_code.js";
|
||||
import { isIMEComposing } from "../services/shortcuts.js";
|
||||
import FindInHtml from "./find_in_html.js";
|
||||
import type { EventData } from "../components/app_context.js";
|
||||
|
||||
@ -162,6 +163,11 @@ export default class FindWidget extends NoteContextAwareWidget {
|
||||
this.$replaceButton.on("click", () => this.replace());
|
||||
|
||||
this.$input.on("keydown", async (e) => {
|
||||
// Skip processing during IME composition
|
||||
if (isIMEComposing(e.originalEvent as KeyboardEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((e.metaKey || e.ctrlKey) && (e.key === "F" || e.key === "f")) {
|
||||
// If ctrl+f is pressed when the findbox is shown, select the
|
||||
// whole input to find
|
||||
|
@ -8,6 +8,7 @@ import "./note_title.css";
|
||||
import { isLaunchBarConfig } from "../services/utils";
|
||||
import appContext from "../components/app_context";
|
||||
import branches from "../services/branches";
|
||||
import { isIMEComposing } from "../services/shortcuts";
|
||||
|
||||
export default function NoteTitleWidget() {
|
||||
const { note, noteId, componentId, viewScope, noteContext, parentComponent } = useNoteContext();
|
||||
@ -78,6 +79,12 @@ export default function NoteTitleWidget() {
|
||||
spacedUpdate.scheduleUpdate();
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
// Skip processing if IME is composing to prevent interference
|
||||
// with text input in CJK languages
|
||||
if (isIMEComposing(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus on the note content when pressing enter.
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
@ -4,7 +4,7 @@ import linkService from "../services/link.js";
|
||||
import froca from "../services/froca.js";
|
||||
import utils from "../services/utils.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
import shortcutService from "../services/shortcuts.js";
|
||||
import shortcutService, { isIMEComposing } from "../services/shortcuts.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import { Dropdown, Tooltip } from "bootstrap";
|
||||
|
||||
@ -180,6 +180,14 @@ export default class QuickSearchWidget extends BasicWidget {
|
||||
|
||||
if (utils.isMobile()) {
|
||||
this.$searchString.keydown((e) => {
|
||||
// Skip processing if IME is composing to prevent interference
|
||||
// with text input in CJK languages
|
||||
// Note: jQuery wraps the native event, so we access originalEvent
|
||||
const originalEvent = e.originalEvent as KeyboardEvent;
|
||||
if (originalEvent && isIMEComposing(originalEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.which === 13) {
|
||||
if (this.$dropdownMenu.is(":visible")) {
|
||||
this.search(); // just update already visible dropdown
|
||||
|
@ -13,6 +13,7 @@ import attribute_parser, { Attribute } from "../../../services/attribute_parser"
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import { escapeQuotes, getErrorMessage } from "../../../services/utils";
|
||||
import link from "../../../services/link";
|
||||
import { isIMEComposing } from "../../../services/shortcuts";
|
||||
import froca from "../../../services/froca";
|
||||
import contextMenu from "../../../menus/context_menu";
|
||||
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
|
||||
@ -287,6 +288,11 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
||||
ref={wrapperRef}
|
||||
style="position: relative; padding-top: 10px; padding-bottom: 10px"
|
||||
onKeyDown={(e) => {
|
||||
// Skip processing during IME composition
|
||||
if (isIMEComposing(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === "Enter") {
|
||||
// allow autocomplete to fill the result textarea
|
||||
setTimeout(() => save(), 100);
|
||||
|
Loading…
x
Reference in New Issue
Block a user