mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 07:28:11 +08:00
Add a temporary solution to non-Latin keyboards being unusable
This commit is contained in:
+342
-10
@@ -37,37 +37,41 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
// Don't redirect when a modal is covering the workspace
|
// Don't redirect when a modal is covering the workspace
|
||||||
if (dialog.dialogIsVisible()) return false;
|
if (dialog.dialogIsVisible()) return false;
|
||||||
|
|
||||||
|
const key = getLatinKey(e);
|
||||||
|
|
||||||
// Don't redirect a fullscreen request
|
// Don't redirect a fullscreen request
|
||||||
if (e.key.toLowerCase() === "f11" && e.type === "keydown" && !e.repeat) {
|
if (key === "f11" && e.type === "keydown" && !e.repeat) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
fullscreen.toggleFullscreen();
|
fullscreen.toggleFullscreen();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't redirect a reload request
|
// Don't redirect a reload request
|
||||||
if (e.key.toLowerCase() === "f5") return false;
|
if (key === "f5") return false;
|
||||||
|
|
||||||
// Don't redirect debugging tools
|
// Don't redirect debugging tools
|
||||||
if (e.key.toLowerCase() === "f12") return false;
|
if (key === "f12") return false;
|
||||||
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "c") return false;
|
if (e.ctrlKey && e.shiftKey && key === "c") return false;
|
||||||
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "i") return false;
|
if (e.ctrlKey && e.shiftKey && key === "i") return false;
|
||||||
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "j") return false;
|
if (e.ctrlKey && e.shiftKey && key === "j") return false;
|
||||||
|
|
||||||
// Redirect to the backend
|
// Redirect to the backend
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const key = getLatinKey(e);
|
||||||
|
|
||||||
if (shouldRedirectKeyboardEventToBackend(e)) {
|
if (shouldRedirectKeyboardEventToBackend(e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const modifiers = makeModifiersBitfield(e);
|
const modifiers = makeModifiersBitfield(e);
|
||||||
editor.instance.on_key_down(e.key, modifiers);
|
editor.instance.on_key_down(key, modifiers);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialog.dialogIsVisible()) {
|
if (dialog.dialogIsVisible()) {
|
||||||
if (e.key === "Escape") dialog.dismissDialog();
|
if (key === "escape") dialog.dismissDialog();
|
||||||
if (e.key === "Enter") {
|
if (key === "enter") {
|
||||||
dialog.submitDialog();
|
dialog.submitDialog();
|
||||||
|
|
||||||
// Prevent the Enter key from acting like a click on the last clicked button, which might reopen the dialog
|
// Prevent the Enter key from acting like a click on the last clicked button, which might reopen the dialog
|
||||||
@@ -77,10 +81,12 @@ export function createInputManager(editor: EditorState, container: HTMLElement,
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onKeyUp = (e: KeyboardEvent) => {
|
const onKeyUp = (e: KeyboardEvent) => {
|
||||||
|
const key = getLatinKey(e);
|
||||||
|
|
||||||
if (shouldRedirectKeyboardEventToBackend(e)) {
|
if (shouldRedirectKeyboardEventToBackend(e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const modifiers = makeModifiersBitfield(e);
|
const modifiers = makeModifiersBitfield(e);
|
||||||
editor.instance.on_key_up(e.key, modifiers);
|
editor.instance.on_key_up(key, modifiers);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -196,3 +202,329 @@ export type InputManager = ReturnType<typeof createInputManager>;
|
|||||||
export function makeModifiersBitfield(e: WheelEvent | PointerEvent | KeyboardEvent): number {
|
export function makeModifiersBitfield(e: WheelEvent | PointerEvent | KeyboardEvent): number {
|
||||||
return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2);
|
return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is a naive, temporary solution to allow non-Latin keyboards to fall back on the physical QWERTY layout
|
||||||
|
function getLatinKey(e: KeyboardEvent): string {
|
||||||
|
const key = e.key.toLowerCase();
|
||||||
|
const isPrintable = isKeyPrintable(e.key);
|
||||||
|
|
||||||
|
// Control (non-printable) characters are handled normally
|
||||||
|
if (!isPrintable) return key;
|
||||||
|
|
||||||
|
// These non-Latin characters should fall back to the Latin equivalent at the key location
|
||||||
|
const LAST_LATIN_UNICODE_CHAR = 0x024f;
|
||||||
|
if (key.length > 1 || key.charCodeAt(0) > LAST_LATIN_UNICODE_CHAR) return e.code.toLowerCase();
|
||||||
|
|
||||||
|
// Otherwise, ths is a printable Latin character
|
||||||
|
return e.key.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isKeyPrintable(key: string): boolean {
|
||||||
|
const allPrintableKeys: string[] = [
|
||||||
|
// Modifier
|
||||||
|
"Alt",
|
||||||
|
"AltGraph",
|
||||||
|
"CapsLock",
|
||||||
|
"Control",
|
||||||
|
"Fn",
|
||||||
|
"FnLock",
|
||||||
|
"Meta",
|
||||||
|
"NumLock",
|
||||||
|
"ScrollLock",
|
||||||
|
"Shift",
|
||||||
|
"Symbol",
|
||||||
|
"SymbolLock",
|
||||||
|
// Legacy modifier
|
||||||
|
"Hyper",
|
||||||
|
"Super",
|
||||||
|
// White space
|
||||||
|
"Enter",
|
||||||
|
"Tab",
|
||||||
|
// Navigation
|
||||||
|
"ArrowDown",
|
||||||
|
"ArrowLeft",
|
||||||
|
"ArrowRight",
|
||||||
|
"ArrowUp",
|
||||||
|
"End",
|
||||||
|
"Home",
|
||||||
|
"PageDown",
|
||||||
|
"PageUp",
|
||||||
|
// Editing
|
||||||
|
"Backspace",
|
||||||
|
"Clear",
|
||||||
|
"Copy",
|
||||||
|
"CrSel",
|
||||||
|
"Cut",
|
||||||
|
"Delete",
|
||||||
|
"EraseEof",
|
||||||
|
"ExSel",
|
||||||
|
"Insert",
|
||||||
|
"Paste",
|
||||||
|
"Redo",
|
||||||
|
"Undo",
|
||||||
|
// UI
|
||||||
|
"Accept",
|
||||||
|
"Again",
|
||||||
|
"Attn",
|
||||||
|
"Cancel",
|
||||||
|
"ContextMenu",
|
||||||
|
"Escape",
|
||||||
|
"Execute",
|
||||||
|
"Find",
|
||||||
|
"Help",
|
||||||
|
"Pause",
|
||||||
|
"Play",
|
||||||
|
"Props",
|
||||||
|
"Select",
|
||||||
|
"ZoomIn",
|
||||||
|
"ZoomOut",
|
||||||
|
// Device
|
||||||
|
"BrightnessDown",
|
||||||
|
"BrightnessUp",
|
||||||
|
"Eject",
|
||||||
|
"LogOff",
|
||||||
|
"Power",
|
||||||
|
"PowerOff",
|
||||||
|
"PrintScreen",
|
||||||
|
"Hibernate",
|
||||||
|
"Standby",
|
||||||
|
"WakeUp",
|
||||||
|
// IME composition keys
|
||||||
|
"AllCandidates",
|
||||||
|
"Alphanumeric",
|
||||||
|
"CodeInput",
|
||||||
|
"Compose",
|
||||||
|
"Convert",
|
||||||
|
"Dead",
|
||||||
|
"FinalMode",
|
||||||
|
"GroupFirst",
|
||||||
|
"GroupLast",
|
||||||
|
"GroupNext",
|
||||||
|
"GroupPrevious",
|
||||||
|
"ModeChange",
|
||||||
|
"NextCandidate",
|
||||||
|
"NonConvert",
|
||||||
|
"PreviousCandidate",
|
||||||
|
"Process",
|
||||||
|
"SingleCandidate",
|
||||||
|
// Korean-specific
|
||||||
|
"HangulMode",
|
||||||
|
"HanjaMode",
|
||||||
|
"JunjaMode",
|
||||||
|
// Japanese-specific
|
||||||
|
"Eisu",
|
||||||
|
"Hankaku",
|
||||||
|
"Hiragana",
|
||||||
|
"HiraganaKatakana",
|
||||||
|
"KanaMode",
|
||||||
|
"KanjiMode",
|
||||||
|
"Katakana",
|
||||||
|
"Romaji",
|
||||||
|
"Zenkaku",
|
||||||
|
"ZenkakuHankaku",
|
||||||
|
// Common function
|
||||||
|
"F1",
|
||||||
|
"F2",
|
||||||
|
"F3",
|
||||||
|
"F4",
|
||||||
|
"F5",
|
||||||
|
"F6",
|
||||||
|
"F7",
|
||||||
|
"F8",
|
||||||
|
"F9",
|
||||||
|
"F10",
|
||||||
|
"F11",
|
||||||
|
"F12",
|
||||||
|
"Soft1",
|
||||||
|
"Soft2",
|
||||||
|
"Soft3",
|
||||||
|
"Soft4",
|
||||||
|
// Multimedia
|
||||||
|
"ChannelDown",
|
||||||
|
"ChannelUp",
|
||||||
|
"Close",
|
||||||
|
"MailForward",
|
||||||
|
"MailReply",
|
||||||
|
"MailSend",
|
||||||
|
"MediaClose",
|
||||||
|
"MediaFastForward",
|
||||||
|
"MediaPause",
|
||||||
|
"MediaPlay",
|
||||||
|
"MediaPlayPause",
|
||||||
|
"MediaRecord",
|
||||||
|
"MediaRewind",
|
||||||
|
"MediaStop",
|
||||||
|
"MediaTrackNext",
|
||||||
|
"MediaTrackPrevious",
|
||||||
|
"New",
|
||||||
|
"Open",
|
||||||
|
"Print",
|
||||||
|
"Save",
|
||||||
|
"SpellCheck",
|
||||||
|
// Multimedia numpad
|
||||||
|
"Key11",
|
||||||
|
"Key12",
|
||||||
|
// Audio
|
||||||
|
"AudioBalanceLeft",
|
||||||
|
"AudioBalanceRight",
|
||||||
|
"AudioBassBoostDown",
|
||||||
|
"AudioBassBoostToggle",
|
||||||
|
"AudioBassBoostUp",
|
||||||
|
"AudioFaderFront",
|
||||||
|
"AudioFaderRear",
|
||||||
|
"AudioSurroundModeNext",
|
||||||
|
"AudioTrebleDown",
|
||||||
|
"AudioTrebleUp",
|
||||||
|
"AudioVolumeDown",
|
||||||
|
"AudioVolumeUp",
|
||||||
|
"AudioVolumeMute",
|
||||||
|
"MicrophoneToggle",
|
||||||
|
"MicrophoneVolumeDown",
|
||||||
|
"MicrophoneVolumeUp",
|
||||||
|
"MicrophoneVolumeMute",
|
||||||
|
// Speech
|
||||||
|
"SpeechCorrectionList",
|
||||||
|
"SpeechInputToggle",
|
||||||
|
// Application
|
||||||
|
"LaunchApplication1",
|
||||||
|
"LaunchApplication2",
|
||||||
|
"LaunchCalendar",
|
||||||
|
"LaunchContacts",
|
||||||
|
"LaunchMail",
|
||||||
|
"LaunchMediaPlayer",
|
||||||
|
"LaunchMusicPlayer",
|
||||||
|
"LaunchPhone",
|
||||||
|
"LaunchScreenSaver",
|
||||||
|
"LaunchSpreadsheet",
|
||||||
|
"LaunchWebBrowser",
|
||||||
|
"LaunchWebCam",
|
||||||
|
"LaunchWordProcessor",
|
||||||
|
// Browser
|
||||||
|
"BrowserBack",
|
||||||
|
"BrowserFavorites",
|
||||||
|
"BrowserForward",
|
||||||
|
"BrowserHome",
|
||||||
|
"BrowserRefresh",
|
||||||
|
"BrowserSearch",
|
||||||
|
"BrowserStop",
|
||||||
|
// Mobile phone
|
||||||
|
"AppSwitch",
|
||||||
|
"Call",
|
||||||
|
"Camera",
|
||||||
|
"CameraFocus",
|
||||||
|
"EndCall",
|
||||||
|
"GoBack",
|
||||||
|
"GoHome",
|
||||||
|
"HeadsetHook",
|
||||||
|
"LastNumberRedial",
|
||||||
|
"Notification",
|
||||||
|
"MannerMode",
|
||||||
|
"VoiceDial",
|
||||||
|
// TV
|
||||||
|
"TV",
|
||||||
|
"TV3DMode",
|
||||||
|
"TVAntennaCable",
|
||||||
|
"TVAudioDescription",
|
||||||
|
"TVAudioDescriptionMixDown",
|
||||||
|
"TVAudioDescriptionMixUp",
|
||||||
|
"TVContentsMenu",
|
||||||
|
"TVDataService",
|
||||||
|
"TVInput",
|
||||||
|
"TVInputComponent1",
|
||||||
|
"TVInputComponent2",
|
||||||
|
"TVInputComposite1",
|
||||||
|
"TVInputComposite2",
|
||||||
|
"TVInputHDMI1",
|
||||||
|
"TVInputHDMI2",
|
||||||
|
"TVInputHDMI3",
|
||||||
|
"TVInputHDMI4",
|
||||||
|
"TVInputVGA1",
|
||||||
|
"TVMediaContext",
|
||||||
|
"TVNetwork",
|
||||||
|
"TVNumberEntry",
|
||||||
|
"TVPower",
|
||||||
|
"TVRadioService",
|
||||||
|
"TVSatellite",
|
||||||
|
"TVSatelliteBS",
|
||||||
|
"TVSatelliteCS",
|
||||||
|
"TVSatelliteToggle",
|
||||||
|
"TVTerrestrialAnalog",
|
||||||
|
"TVTerrestrialDigital",
|
||||||
|
"TVTimer",
|
||||||
|
// Media controls
|
||||||
|
"AVRInput",
|
||||||
|
"AVRPower",
|
||||||
|
"ColorF0Red",
|
||||||
|
"ColorF1Green",
|
||||||
|
"ColorF2Yellow",
|
||||||
|
"ColorF3Blue",
|
||||||
|
"ColorF4Grey",
|
||||||
|
"ColorF5Brown",
|
||||||
|
"ClosedCaptionToggle",
|
||||||
|
"Dimmer",
|
||||||
|
"DisplaySwap",
|
||||||
|
"DVR",
|
||||||
|
"Exit",
|
||||||
|
"FavoriteClear0",
|
||||||
|
"FavoriteClear1",
|
||||||
|
"FavoriteClear2",
|
||||||
|
"FavoriteClear3",
|
||||||
|
"FavoriteRecall0",
|
||||||
|
"FavoriteRecall1",
|
||||||
|
"FavoriteRecall2",
|
||||||
|
"FavoriteRecall3",
|
||||||
|
"FavoriteStore0",
|
||||||
|
"FavoriteStore1",
|
||||||
|
"FavoriteStore2",
|
||||||
|
"FavoriteStore3",
|
||||||
|
"Guide",
|
||||||
|
"GuideNextDay",
|
||||||
|
"GuidePreviousDay",
|
||||||
|
"Info",
|
||||||
|
"InstantReplay",
|
||||||
|
"Link",
|
||||||
|
"ListProgram",
|
||||||
|
"LiveContent",
|
||||||
|
"Lock",
|
||||||
|
"MediaApps",
|
||||||
|
"MediaAudioTrack",
|
||||||
|
"MediaLast",
|
||||||
|
"MediaSkipBackward",
|
||||||
|
"MediaSkipForward",
|
||||||
|
"MediaStepBackward",
|
||||||
|
"MediaStepForward",
|
||||||
|
"MediaTopMenu",
|
||||||
|
"NavigateIn",
|
||||||
|
"NavigateNext",
|
||||||
|
"NavigateOut",
|
||||||
|
"NavigatePrevious",
|
||||||
|
"NextFavoriteChannel",
|
||||||
|
"NextUserProfile",
|
||||||
|
"OnDemand",
|
||||||
|
"Pairing",
|
||||||
|
"PinPDown",
|
||||||
|
"PinPMove",
|
||||||
|
"PinPToggle",
|
||||||
|
"PinPUp",
|
||||||
|
"PlaySpeedDown",
|
||||||
|
"PlaySpeedReset",
|
||||||
|
"PlaySpeedUp",
|
||||||
|
"RandomToggle",
|
||||||
|
"RcLowBattery",
|
||||||
|
"RecordSpeedNext",
|
||||||
|
"RfBypass",
|
||||||
|
"ScanChannelsToggle",
|
||||||
|
"ScreenModeNext",
|
||||||
|
"Settings",
|
||||||
|
"SplitScreenToggle",
|
||||||
|
"STBInput",
|
||||||
|
"STBPower",
|
||||||
|
"Subtitle",
|
||||||
|
"Teletext",
|
||||||
|
"VideoModeNext",
|
||||||
|
"Wink",
|
||||||
|
"ZoomToggle",
|
||||||
|
];
|
||||||
|
|
||||||
|
return !allPrintableKeys.includes(key);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user