令人困惑的按键压榨机案例 [英] Case of the confounding key press caper

查看:56
本文介绍了令人困惑的按键压榨机案例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

开发用于屏幕投射的基本的开放源代码键盘和鼠标在屏幕上显示桌面应用程序,称为

该应用程序使用

请确保在任何其他窗口中键入内容,以查看演示应用程序中按键的困惑.

环境

  • OpenJDK版本"14.0.1"2020-04-14,64位
  • XFCE
  • Arch Linux
  • JNativeHook 2.1.0

详细信息

JNativeHook在其自己的线程中运行,但是使用 invokeLater (或 invokeAndWait ?)应该在Swing的事件线程上发布UI更新.

disableNativeHookLogger()的调用无关紧要,只是在运行演示时保持控制台干净.

控制台输出

这是应用程序具有焦点时的控制台输出:

  Shift I空格A M空格I N S ID E空间T H E空间A P P许可期限 

这是应用程序失去焦点时的控制台输出:

  Shift I Space A M Space O U T SID空间T H E空间A P期间 

因此很明显,调用 nativeKeyPressed 时,不会丢失键盘事件,而不管应用程序是否具有焦点.也就是说,JNativeHook或通过JNI冒泡的事件似乎都不是罪魁祸首.

问题

需要进行哪些更改,以便每次按键时更新 JLabel 文本,而不管应用程序是否具有焦点?

想法

一些帮助的项目包括:

  • 调用 getDefaultToolkit().sync(); 显式刷新渲染管道.
  • 在标签上调用 paintImmediately(getBounds()).

第一个项目似乎起了很大的作用,但是某些键似乎仍然丢失(尽管可能是因为我键入的速度太快了).有道理的是,防止渲染管道合并绘画请求可以避免按键丢失.

研究

与此问题相关的资源

解决方案

使用默认工具包调用 sync():

  @Override公共无效propertyChange(final PropertyChangeEvent e){invokeLater(()->{更新(e);//防止崩溃多个绘画事件.getDefaultToolkit().sync();});} 

请参见完整代码.

Background

Developing a rudimentary, open-source keyboard and mouse on-screen display desktop application for screen casting, called KmCaster:

The application uses the JNativeHook library to receive global keyboard and mouse events, because Swing's Key and Mouse listeners are restricted to receiving events directed at the application itself.

Problem

When the application loses focus, the user interface shows intermittent key presses, rather than every key press. Yet the console shows that the application has received every key press.

Code

A short, self-contained, compileable example:

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;

import javax.swing.*;

import static java.util.logging.Level.OFF;
import static java.util.logging.Logger.getLogger;
import static javax.swing.SwingUtilities.invokeLater;
import static org.jnativehook.GlobalScreen.*;
import static org.jnativehook.keyboard.NativeKeyEvent.getKeyText;

public class Harness extends JFrame implements NativeKeyListener {

  private final JLabel mLabel = new JLabel( "Hello, world" );
  private int mCount;

  public void init() {
    getContentPane().add( mLabel );

    setDefaultCloseOperation( EXIT_ON_CLOSE );
    setLocationRelativeTo( null );
    setAlwaysOnTop( true );
    pack();
    setVisible( true );
  }

  @Override
  public void nativeKeyPressed( final NativeKeyEvent e ) {
    final var s = getKeyText( e.getKeyCode() );
    System.out.print( s + " " + (++mCount % 10 == 0 ? "\n" : "") );

    invokeLater( () -> mLabel.setText( s ) );
  }

  public static void main( final String[] args ) throws NativeHookException {
    disableNativeHookLogger();
    registerNativeHook();

    final var harness = new Harness();
    addNativeKeyListener( harness );

    invokeLater( harness::init );
  }

  private static void disableNativeHookLogger() {
    final var logger = getLogger( GlobalScreen.class.getPackage().getName() );
    logger.setLevel( OFF );
    logger.setUseParentHandlers( false );
  }

  @Override
  public void nativeKeyReleased( final NativeKeyEvent e ) {}

  @Override
  public void nativeKeyTyped( final NativeKeyEvent e ) {}
}

The code above produces a small window that, when run, demonstrates the problem:

Be sure to type into any other window to see the perplexing loss of key presses within the demo application.

Environment

  • OpenJDK version "14.0.1" 2020-04-14, 64-bit
  • XFCE
  • Arch Linux
  • JNativeHook 2.1.0

Details

JNativeHook runs in its own thread, but using invokeLater (or invokeAndWait?) should issue the UI update on Swing's event thread.

The call to disableNativeHookLogger() isn't relevant, it merely keeps the console clean when running the demo.

Console Output

Here is the console output when the application has focus:

Shift I Space A M Space I N S I 
D E Space T H E Space A P P 
L I C A T I O N Period

Here is the console output when the application loses focus:

Shift I Space A M Space O U T S
I D E Space T H E Space A P
P L I C A T I O N Period 

So it's clear that no keyboard events are missing when nativeKeyPressed is called, regardless of whether the application has focus. That is, neither JNativeHook nor its event bubbling via JNI appears to be the culprit.

Question

What needs to change so that the JLabel text is updated for every key press regardless of whether the application has focus?

Ideas

Some items that help include:

  • Call getDefaultToolkit().sync(); to flush the rendering pipeline explicitly.
  • Call paintImmediately( getBounds() ) on the label.

The first item seems to make a huge difference, but some keys still appear to be missing (although it could be that I'm typing too quickly). It makes sense that preventing the rendering pipeline from merging paint requests avoids loss of key strokes.

Research

Resources related to this issue:

解决方案

Call sync() using the default toolkit:

  @Override
  public void propertyChange( final PropertyChangeEvent e ) {
    invokeLater(
        () -> {
          update( e );

          // Prevent collapsing multiple paint events.
          getDefaultToolkit().sync();
        }
    );
  }

See the full code.

这篇关于令人困惑的按键压榨机案例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆