当从SWT 3切换到SWT 4时,JAVA SWT KeyDown事件触发3次而不是1次

当从SWT 3切换到SWT 4时,JAVA SWT KeyDown事件触发3次而不是1次,java,browser,swt,listener,keydown,Java,Browser,Swt,Listener,Keydown,以下问题让我感到困惑:我有一个SWT Java应用程序,在以下情况下,从SWT 3切换到SWT 4会导致KeyDown事件的奇怪行为: 我有一个包含浏览器小部件的shell。我通过Display对象上的一个过滤器在Java级别监听KeyDown事件,如下所示。当检测到这样的事件时,我会调用浏览器小部件的execute()函数来执行一些javascript。我选择在全局java级别检测KeyDown事件,而不是直接在javascript中检测,因为此时浏览器可能不一定有焦点 预期行为:应检测一次按

以下问题让我感到困惑:我有一个SWT Java应用程序,在以下情况下,从SWT 3切换到SWT 4会导致KeyDown事件的奇怪行为:

我有一个包含浏览器小部件的shell。我通过Display对象上的一个过滤器在Java级别监听KeyDown事件,如下所示。当检测到这样的事件时,我会调用浏览器小部件的execute()函数来执行一些javascript。我选择在全局java级别检测KeyDown事件,而不是直接在javascript中检测,因为此时浏览器可能不一定有焦点

预期行为:应检测一次按键事件

实际行为:检测到三次按键事件

到目前为止我所尝试和学到的: 1) 该问题仅在使用浏览器小部件时发生。 2) 问题不仅发生在执行某些javascript时,如果我简单地设置浏览器的内容(br.setText(“…”),也会发生,因此浏览器上的任何操作似乎都会触发问题。 3) SWT3.836没有出现这个问题。它发生在SWT4.924上

恢复到SWT3并不是一个理想的选择,因为它由于libwebkitgtk而导致了很多崩溃,并且我摆脱了那些使用SWT4的人

配置:Ubuntu 18.04,Java openjdk 11 adm64,SWT 4.924(从Eclipse下载页面下载最新稳定版本4.14M1)

代码如下:

public static void main(String[] args) {
    System.out.println("Launching test application");

    Display display = new Display();
    Shell shell = new Shell(display);

    Browser br = new Browser(shell,SWT.NONE);
    br.setSize(500,500);

    display.addFilter(SWT.KeyDown, new Listener() {

        @Override
        public void handleEvent(Event event) {
            System.out.println(event.keyCode);
            //Try either of the following two lines to reproduce the problem. If you comment both lines, the problem disappears
            br.execute("javascript:alert('hello')");
            //br.setText("<html><head></head><body>TEST</body></html>");
        }
    });

    shell.open();

    while (!shell.isDisposed()) {
        if (!display.readAndDispatch())
         {
            display.sleep();
         }
    }
}
publicstaticvoidmain(字符串[]args){
System.out.println(“启动测试应用程序”);
显示=新显示();
外壳=新外壳(显示);
浏览器br=新浏览器(shell,SWT.NONE);
br.设置大小(500500);
display.addFilter(SWT.KeyDown,newlistener()){
@凌驾
公共无效handleEvent(事件){
System.out.println(event.keyCode);
//尝试以下两行中的任何一行来重现问题。如果您对这两行都进行了注释,问题就会消失
br.execute(“javascript:alert('hello')”);
//br.setText(“测试”);
}
});
shell.open();
而(!shell.isDisposed()){
如果(!display.readAndDispatch())
{
display.sleep();
}
}
}

有什么提示吗?提前谢谢

我已经在Windows 10和SWT 4.924上测试了您的代码,我收到了两次事件

我猜
浏览器
也在与过滤器交互,导致多个事件(请参阅此旧注释,不确定是否相关:)

此外,似乎只有当
浏览器
具有焦点时,问题才会发生,并且当其他控件具有焦点时,问题才能正常工作

因此,作为一种解决方法,当浏览器没有焦点时,您可以使用过滤器,否则,当浏览器有焦点时,您可以在
浏览器上使用标准键侦听器

例如:

br.addKeyListener(keyPressedAdapter(event -> {
    handleBrowserKeyEvent(br, event.keyCode);
}));

display.addFilter(SWT.KeyDown, new Listener() {
    @Override
    public void handleEvent(Event event) {
        // when the browser has focus, use his key listener instead of this filter 
        if (br.isFocusControl()) {
            return;
        }
        handleBrowserKeyEvent(br, event.keyCode);
    }
});
handleBrowserKeyEvent
中放置处理逻辑


注意,在我的例子中,我还必须放置一个
shell.forceFocus()紧跟在
shell.open()之后,否则浏览器键侦听器将无法立即工作(我不知道为什么)。

处理此问题的一种快速而肮脏的方法是计数事件的数量,并在每3个事件中输入2个,如下所示:

display.addFilter(SWT.KeyDown, new Listener() {
        int i = 0;
        @Override
        public void handleEvent(Event event) {

            if (i<2) {
                i++;
            }else {
                System.out.println(event.keyCode);
                i=0;
            }
        }
    });
display.addFilter(SWT.KeyDown,newlistener()){
int i=0;
@凌驾
公共无效handleEvent(事件){

如果(iOn macOS),除非我使用某些内容初始化浏览器,否则此代码根本不会生成任何按键关闭事件,那么它只会给出1个事件加上“按键未被接受”的蜂鸣音。感谢您的回复。实际上,在我的Linux配置中,KeyListener直接连接到浏览器(br.addKeyListener)同时触发事件3次。有趣的是,可以看到一些swt元素在不同平台上的行为是如何不同的,而它应该是跨平台的。