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

问题描述 投票:0回答:1

我想让键盘快捷键适用于尽可能多的键盘布局,包括其他字母表。

我知道就拉丁键盘而言,最好使用

KeyboardEvent.key
属性 - 因此,无论键盘布局如何,都知道用户按下了代表字母“L”的键。这似乎与操作系统和其他应用程序的做法一致,因为我刚刚通过暂时切换到 Dvorak 布局来测试它。

我很确定这种方法不适用于非拉丁键盘,即西里尔字母。

我正在寻找一种处理其他字母表的通用方法,而不必深入研究每种语言的本地化。

例如,如果我想要 Ctrl+L(或 Mac 上的 Cmd+L)操作,我希望它能够在尽可能多的键盘布局上工作,即使这些布局没有字母L. 获取键盘布局上相当于 L 的字符。

我也想尊重最基本的操作系统命令:Ctrl+C、Ctrl+A、Ctrl+V、Ctrl+X - 所以我很好奇操作系统是否以同样的方式执行此操作,即在西里尔字母键盘上粘贴操作按 Ctrl +(相当于西里尔文中的 V)发生,还是取决于区域设置?

javascript localization keyboard accessibility keyboard-shortcuts
1个回答
3
投票

2024 年更新

我写了一篇关于它的博客文章,并发布了一个键盘快捷键库,可以开箱即用地处理它。以下功能也可用于从 shocut/shortcut_key

直接导入(无需库)

原答案

事实证明,大多数非拉丁键盘都印有 2 个字母,拉丁字母和它自己的字母 - 用户可以在布局之间切换。

因此,如果用户处于拉丁布局模式,

KeyboardEvent.key
应该可以开箱即用。问题是,当用户处于非拉丁模式时,键盘命令将不起作用,因为
KeyboardEvent.key
将是该字母表中的字母。

幸运的是,大多数键盘都遵循标准 Qwerty 布局,因此

KeyboardEvent.code
可以作为引用拉丁字符的后备。

我创建了一个函数,如果检测到非拉丁字符,给定

KeyboardEvent.key
KeyboardEvent.code
应回退到绝对 Qwerty 代码值。

许可证:麻省理工学院

/**
 * 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();
}

使用示例:

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

测试:

  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('Ž');
    });
  });


替代方案:

  1. 可以使用
    Keyboard.getLayoutMap()
    来确定布局是否是非拉丁语,这也可以使 KeyQ 正常工作。然而,它是一个实验性 API,不受 Firefox 和 Safari 支持(而且可能永远不会支持,因为 Firefox 目前在隐私条款 - 指纹识别方面拒绝了它)。这也是一个缺点,因为该 API 不是同步的,并且如果需要的话,不可能在键盘事件上调用
    e.preventDefault()
  2. 在 Electron 应用程序中,
    keyboard-layout
    npm 模块可以允许更高级的实现,而不会受到相同的限制。

其他事情

至于复制、粘贴、撤消等操作系统快捷键,它似乎就在你所期望的地方(至少这是我在 Mac 操作系统上切换键盘布局后得到的印象)。

对于一些一般性提示,请避免使用键盘快捷键符号。它们无处不在,甚至在拉丁 Qwerty 布局中也是如此。

© www.soinside.com 2019 - 2024. All rights reserved.