使用本机操作系统的默认 KeyMap

发布于 2024-08-13 18:44:18 字数 313 浏览 5 评论 0 原文

在 Java 中,通过使用非默认系统外观和感觉,我们将拥有不同的键盘映射。

例如 我使用的是 Mac OS X 并使用 Substance 外观(非默认系统外观)。 结果是我失去了用于选择文本组件上所有内容的“元”键 在 mac os x 中应该是“meta + a”,但是使用 Substance 我们必须使用“ctrl + a”(还有更多,例如“下一个单词”、“上一个单词”、“结束行”、“开始行”) ETC) 因此,通过使用非默认系统外观(Substance 外观和感觉),我们没有 mac os x 的感觉。

有没有办法使用非默认系统外观和感觉但使用系统(本机)键盘映射?

In Java, by using non-default system look and feel we will have different keymap.

For example
I'm using Mac OS X and use Substance look and feel (non-default system look and feel).
The effect is I'm loosing my "meta" key for select all on text component
In mac os x should be "meta + a", but using Substance we have to use "ctrl + a" (and a lot more such as "next word", "prev word", "end line, "begin line", etc)
So we didn't have the mac os x feel by using non-default system look and feel (Substance look and feel).

Is there a way to use non-default system look and feel but use system (native) keymap?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

汹涌人海 2024-08-20 18:44:19

解决方法

一个不太优雅的解决方案,您可以尝试添加一个按键监听器,通过实现 keyPressed 方法来覆盖默认的“ctrl + a”行为(请注意,以下示例不会禁止“ctrl + a”只是添加了对“meta + a”的支持):

@Override
public void keyPressed(final KeyEvent e) {
  // Get the default toolkit shortcut mask ("meta" for OSX).
  int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

  // You could also check modifiers against KeyEvent.META_MASK...
  if (e.getModifiers() == keyMask && e.getKeyCode() == KeyEvent.VK_A) {
    // Select everything (assumes member of child text component class).
    this.selectAll();

    // We handled this keystroke, 'a' will be ignored by underlying text component.
    e.consume(); 
  }
}

更好的替代方案是使用 inputMaps(请参阅下面 uudashr 的评论)。


对根本原因的思考

不幸的是,正如类名称所示,外观和感觉(或LAF)是外观的组合,即外观,如以及“系统行为”,即感觉。如果您挖掘物质来源,SubstanceLookAndFeel 覆盖 BasicLookAndFeel 随 swing 一起提供。看起来好像在 BasicLookAndFeel 中,违规行为是在 initComponentDefaults 中设置的。您应该能够通过调用 getDefaults() 从 LAF 获取 UIDefaults。

这里的问题是:

  • 您希望更改的“系统行为”与您希望保持不变的外观设置混合在一起。
  • 我也无法找到任何简单的方法将这些默认值注入到 LAF 级别的实质内容中......有人对此有其他想法吗?

The work around

A less elegant solution, you could try adding a key listener to override the default "ctrl + a" behavior by implementing a keyPressed method (please note that the following sample does not disallow "ctrl + a" just adds support for "meta + a"):

@Override
public void keyPressed(final KeyEvent e) {
  // Get the default toolkit shortcut mask ("meta" for OSX).
  int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

  // You could also check modifiers against KeyEvent.META_MASK...
  if (e.getModifiers() == keyMask && e.getKeyCode() == KeyEvent.VK_A) {
    // Select everything (assumes member of child text component class).
    this.selectAll();

    // We handled this keystroke, 'a' will be ignored by underlying text component.
    e.consume(); 
  }
}

A better alternative would be to use inputMaps (see comment by uudashr below).


Thoughts on the root cause

Unfortunately, as the class name suggests the look and feel (or LAF) is a combination of appearance i.e. look, as well as "system behavior", i.e. feel. If you dig around the substance source, the SubstanceLookAndFeel overrides the BasicLookAndFeel that ships with swing. It looks as though it is within the BasicLookAndFeel the offending behavior is set in initComponentDefaults. You should be able to get the UIDefaults from the LAF by calling getDefaults().

Problems from here are:

  • "System behaviors" which you wish to change are intermingled with appearance settings you wish to leave untouched.
  • I have also been unable to find any easy way to inject these defaults into substance at the LAF level... Anyone with other ideas on this?
绮烟 2024-08-20 18:44:19

一种可能性是将 META 键事件转换为 CTRL 键事件。因此,当 OS X 上的用户按下 META 键时,它会被转换为 CTRL 键。对于仅在 LAF 之间交换 CTRL 和 META 的快捷键,这应该可以正常工作。如果还有其他更复杂的组合,您总是可以进行更复杂的匹配和翻译。进行基本翻译的代码如下,我使用带有 CTRL+O 键加速器的 JMenuItem 对其进行了测试,因此现在 META+O 激活加速器。

java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            public void eventDispatched(AWTEvent event) {
                KeyEvent kev = (KeyEvent) event;
                if (kev.getID() == KeyEvent.KEY_PRESSED || kev.getID() == KeyEvent.KEY_RELEASED || kev.getID() == KeyEvent.KEY_PRESSED) {
                    if ((kev.getModifiersEx() & KeyEvent.META_DOWN_MASK) != 0 && !((kev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) {
                        kev.consume(); // Drop the original event, this is really optional.
                        KeyEvent fake = new KeyEvent(kev.getComponent(),
                                kev.getID(),
                                kev.getWhen(),
                                (kev.getModifiersEx() & ~KeyEvent.META_DOWN_MASK) | KeyEvent.CTRL_DOWN_MASK,
                                kev.getKeyCode(), kev.getKeyChar());
                        java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(fake);
                    }
                }
            }
        }, KeyEvent.KEY_EVENT_MASK);

这会在 AWTEvent 队列上安装 AWTEventListener,并将影响所有按键事件。

One possibility is to translate META key events to CTRL key events. So when a user on OS X presses the META key it is translated to a CTRL key instead. This should work correctly for key shortcuts that only have CTRL and META swapped between LAF's. If there are other combos that are more complicated you could always do more complex matching and translation. Code to do the basic translation is below, I tested it with a JMenuItem with a key accelerator of CTRL+O, so now META+O activates the accelerator.

java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            public void eventDispatched(AWTEvent event) {
                KeyEvent kev = (KeyEvent) event;
                if (kev.getID() == KeyEvent.KEY_PRESSED || kev.getID() == KeyEvent.KEY_RELEASED || kev.getID() == KeyEvent.KEY_PRESSED) {
                    if ((kev.getModifiersEx() & KeyEvent.META_DOWN_MASK) != 0 && !((kev.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) {
                        kev.consume(); // Drop the original event, this is really optional.
                        KeyEvent fake = new KeyEvent(kev.getComponent(),
                                kev.getID(),
                                kev.getWhen(),
                                (kev.getModifiersEx() & ~KeyEvent.META_DOWN_MASK) | KeyEvent.CTRL_DOWN_MASK,
                                kev.getKeyCode(), kev.getKeyChar());
                        java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(fake);
                    }
                }
            }
        }, KeyEvent.KEY_EVENT_MASK);

This installs an AWTEventListener on the AWTEvent queue, and will affect all key events.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文