简体   繁体   English

非拉丁键盘上的键盘快捷键/命令 (JavaScript)

[英]Keyboard shortcuts / commands on non-Latin keyboards (JavaScript)

I'd like to make keyboard shortcuts work on as many keyboard layouts as possible, including non-Latin ones.我想让键盘快捷键适用于尽可能多的键盘布局,包括非拉丁语的。

I understand that as far as Latin keyboards go, it's best to use KeyboardEvent.key property - so it's known that user has pressed a key that represents letter "L" for instance, regardless of the keyboard layout.我知道,就拉丁键盘 go 而言,最好使用KeyboardEvent.key属性 - 因此,无论键盘布局如何,都知道用户按下了代表字母“L”的键。 This seems consistent with how OSes and other applications do it, as I just tested it by temporarily switching to Dvorak layout.这似乎与操作系统和其他应用程序的做法一致,因为我只是通过暂时切换到 Dvorak 布局对其进行了测试。

I'm pretty sure that this approach will not work with non-Latin keyboards, ie - Cyrillic.我很确定这种方法不适用于非拉丁键盘,即西里尔字母。

What I'm looking for is a general way to handle other alphabets without necessarily diving deep into localization for each language.我正在寻找的是一种处理其他字母的通用方法,而不必深入研究每种语言的本地化。

So for instance, if I want to have an action for Ctrl+L (or Cmd+L for Macs), I'd like it to work on as many keyboard layouts as possible, even if those layouts don't have the letter L. Sort of get the character on that keyboard layout that would be equivalent to L.因此,例如,如果我想对 Ctrl+L(或 Mac 的 Cmd+L)进行操作,我希望它可以在尽可能多的键盘布局上工作,即使这些布局没有字母 L . 在那个键盘布局上获得相当于 L 的字符。

I also want to respect the most basic OS commands: Ctrl+C, Ctrl+A, Ctrl+V, Ctrl+X - so I'm curious if operating systems do it the same way, ie on a Cyrillic keyboard, does paste action occur as Ctrl + (equivalent of V in Cyrillic) or does it depend on the locale?我还想尊重最基本的操作系统命令:Ctrl+C、Ctrl+A、Ctrl+V、Ctrl+X - 所以我很好奇操作系统是否以同样的方式执行此操作,即在西里尔字母键盘上,是否执行粘贴操作出现为 Ctrl + (相当于西里尔文中的 V )还是取决于语言环境?

It turns out that most non-Latin keyboards have 2 alphabets printed , Latin and its own - and the user can switch between layouts.事实证明, 大多数非拉丁键盘都印有 2 个字母,拉丁字母和它自己的字母 - 用户可以在布局之间切换。

So if the user is in Latin layout mode, KeyboardEvent.key should work out of the box.因此,如果用户处于拉丁布局模式,则KeyboardEvent.key应该开箱即用。 The problem is that while the user is in non-Latin mode, the keyboard commands would not work, because KeyboardEvent.key will be a letter from that alphabet.问题是当用户处于非拉丁模式时,键盘命令将不起作用,因为KeyboardEvent.key将是该字母表中的一个字母。

Fortunately, most of these keyboards follow the standard Qwerty layout, so KeyboardEvent.code can work as a fallback to reference Latin characters.幸运的是,这些键盘中的大多数都遵循标准的 Qwerty 布局,因此KeyboardEvent.code可以作为参考拉丁字符的后备。

I created a function that given a KeyboardEvent.key and KeyboardEvent.code should fallback to absolute Qwerty code values if a non-Latin character is detected.我创建了一个 function,如果检测到非拉丁字符,给定KeyboardEvent.keyKeyboardEvent.code应该回退到绝对 Qwerty 代码值。

License: MIT执照:麻省理工学院

/**
 * Gets key associated with a Keyboard event with a fallback to use absolute code value for
 * non-Latin keyboard layouts.
 *
 * Most commonly non-Latin keyboards have 2 sets of alphabets printed and 2 modes to switch between
 * them. The Latin mode usually follows the standard Qwerty layout so by falling back to use key
 * codes, a keyboard command can work even though the layout is in non-Latin mode.
 *
 * Limitations:
 * - some non-Latin layouts have a symbol on KeyQ which makes it impossible to distinguish it
 * (without checking the entire layout) from Latin Dvorak layout, therefore KeyQ will not work for
 * those
 * - if the Latin layout mode is not Qwerty some of the mappings will not be correct
 *
 * @returns if `key` is a non-Latin letter (unicode >= 880) and `code` represents a letter or a
 * digit on a Qwerty layout, it will return the corresponding letter (uppercase) or digit on a
 * Qwerty layout. Otherwise it will return `key` (transformed to uppercase if it's a letter).
 *
 * License: MIT; Copyright 2021 Maciej Krawczyk
 */
function getLatinKey(key, code) {
  if (key.length !== 1) {
    return key;
  }

  const capitalHetaCode = 880;
  const isNonLatin = key.charCodeAt(0) >= capitalHetaCode;

  if (isNonLatin) {
    if (code.indexOf('Key') === 0 && code.length === 4) { // i.e. 'KeyW'
      return code.charAt(3);
    }

    if (code.indexOf('Digit') === 0 && code.length === 6) { // i.e. 'Digit7'
      return code.charAt(5);
    }
  }

  return key.toUpperCase();
}

Sample usage:示例用法:

document.addEventListener('keydown', (e) => {
  if (e.ctrlKey && getLatinKey(e.key, e.code) === 'L') {
    alert('Ctrl+L');
  }
});

Test:测试:

  describe('getLatinKey', () => {
    it('gets a Latin letter', () => {
      expect(getLatinKey('A', 'irrelevant')).toBe('A');
    });

    it('gets a digit', () => {
      expect(getLatinKey('0', 'irrelevant')).toBe('0');
    });

    it('transforms letters to uppercase', () => {
      expect(getLatinKey('a', 'irrelevant')).toBe('A');
    });

    it('converts non-Latin letters to code values if available', () => {
      expect(getLatinKey('β', 'KeyB')).toBe('B');
      expect(getLatinKey('я', 'KeyZ')).toBe('Z');

      // Not a real-world example, but it tests getting digits.
      expect(getLatinKey('я', 'Digit1')).toBe('1');
    });

    it('does not convert non-Latin letters on special keys', () => {
      expect(getLatinKey('ё', 'Backquote')).toBe('Ё');
    });

    it('does not convert Latin diacritics', () => {
      expect(getLatinKey('ś', 'KeyS')).toBe('Ś');
      expect(getLatinKey('ü', 'KeyU')).toBe('Ü');
      expect(getLatinKey('ž', 'KeyZ')).toBe('Ž');
    });
  });


Alternatives:备择方案:

  1. It would be possible to use Keyboard.getLayoutMap() to determine if the layout is non-Latin, which can make KeyQ work as well.可以使用Keyboard.getLayoutMap()来确定布局是否为非拉丁语,这也可以使 KeyQ 工作。 However, it's an experimental API and is not supported by Firefox and Safari (and it may never be, as Firefox currently rejected it on privacy terms - fingerprinting). However, it's an experimental API and is not supported by Firefox and Safari (and it may never be, as Firefox currently rejected it on privacy terms - fingerprinting). It also would come as a drawback because that API is not synchronous and it would not be possible to call e.preventDefault() on the keyboard event if needed.这也是一个缺点,因为 API 不是同步的,如果需要,不可能在键盘事件上调用e.preventDefault()
  2. In an Electron app, keyboard-layout npm module could allow for a more advanced implementation which does not suffer from the same limitations.在 Electron 应用程序中, keyboard-layout npm 模块可以实现更高级的实现,而不会受到相同的限制。

Other things其他事情

As for OS shortcuts for copy, paste, undo it seems to be where you'd expect it (at least this is the impression I got after switching keyboard layout on Mac OS).至于复制、粘贴、撤消的操作系统快捷方式,它似乎是您所期望的(至少这是我在 Mac OS 上切换键盘布局后得到的印象)。

As for some general tips, avoid using symbols for keyboard shortcuts.至于一些一般提示,请避免使用符号作为键盘快捷键。 They are all over the place, even within Latin Qwerty layouts.它们到处都是,即使在拉丁 Qwerty 布局中也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM