You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从ActionMap的AbstractAction中获取按键码

问题:从ActionMap的AbstractAction中获取按键码

我想从动作映射(ActionMap)中的AbstractAction获取对应按键码,目前正在尝试把所有按键的按下状态存储在KeyInputManager内部的HashMap中。已经遍历有效按键码并为每个按键注册了AbstractAction,但在actionPerformed方法里无法获取对应按键码来更新状态。

原实现代码

遍历注册Action的代码:

for (int key = 37; key <= 122; key++) {
    this.key = key;

    if(!KeyEvent.getKeyText(key).contains("Unknown keyCode")) {
                
        if(KeyInputManager.getInputManager().getOrDefault(key, null) == null)
            KeyInputManager.getInputManager().put(key, true);
                
        component.getActionMap().put(KeyEvent.getKeyText(key), new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                    int keyCode = // TODO: GET KEY CODE HERE
                    KeyInputManager.getInputManager().replace(keyCode, true);
            }
        });
        component.getInputMap().put(KeyStroke.getKeyStroke(key, 0, false), KeyEvent.getKeyText(key));
    }
}

KeyInputManager代码:

public class KeyInputManager {
    private static final HashMap<Integer, Boolean> keysDown = new HashMap<Integer, Boolean>();
    
    public static final boolean keyDown(int keyCode) {
        return keysDown.getOrDefault(keyCode, false);
    }
    
    public static HashMap<Integer, Boolean> getInputManager() {
        return keysDown;
    }
}

解决方案

方案1:使用Effectively Final变量

匿名内部类只能访问final或**实际不可变(effectively final)**的外部变量,所以在循环内将key赋值给一个局部final变量,即可在action中直接引用:

for (int key = 37; key <= 122; key++) {
    // 定义实际不可变的局部变量,供匿名内部类访问
    final int currentKey = key;

    if(!KeyEvent.getKeyText(currentKey).contains("Unknown keyCode")) {
                
        if(KeyInputManager.getInputManager().getOrDefault(currentKey, null) == null)
            KeyInputManager.getInputManager().put(currentKey, true);
                
        component.getActionMap().put(KeyEvent.getKeyText(currentKey), new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int keyCode = currentKey; // 直接使用final变量获取按键码
                KeyInputManager.getInputManager().replace(keyCode, true);
            }
        });
        component.getInputMap().put(KeyStroke.getKeyStroke(currentKey, 0, false), KeyEvent.getKeyText(currentKey));
    }
}

方案2:自定义带按键码的Action类

如果需要更灵活的扩展,可以自定义继承AbstractAction的类,在构造时传入按键码:

// 自定义Action类,携带按键码
class KeyPressAction extends AbstractAction {
    private final int keyCode;

    public KeyPressAction(int keyCode) {
        this.keyCode = keyCode;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        KeyInputManager.getInputManager().replace(keyCode, true);
    }
}

循环中使用自定义Action:

for (int key = 37; key <= 122; key++) {
    if(!KeyEvent.getKeyText(key).contains("Unknown keyCode")) {
                
        if(KeyInputManager.getInputManager().getOrDefault(key, null) == null)
            KeyInputManager.getInputManager().put(key, true);
                
        // 传入当前按键码创建Action实例
        component.getActionMap().put(KeyEvent.getKeyText(key), new KeyPressAction(key));
        component.getInputMap().put(KeyStroke.getKeyStroke(key, 0, false), KeyEvent.getKeyText(key));
    }
}

额外优化:封装KeyInputManager的状态修改

直接返回HashMap引用会导致外部可以随意修改内部状态,建议添加封装方法替代暴露整个Map:

public class KeyInputManager {
    private static final HashMap<Integer, Boolean> keysDown = new HashMap<>();
    
    public static boolean keyDown(int keyCode) {
        return keysDown.getOrDefault(keyCode, false);
    }
    
    // 封装状态修改方法,避免暴露内部Map
    public static void setKeyDown(int keyCode, boolean isDown) {
        keysDown.put(keyCode, isDown);
    }
}

此时Action中调用修改方法即可:

// 在actionPerformed中替换为
KeyInputManager.setKeyDown(keyCode, true);

内容的提问来源于stack exchange,提问作者user17820402

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:08:30