Java: událost stisknutí tlačítka v okně

janbraun

Java: událost stisknutí tlačítka v okně
« kdy: 12. 11. 2016, 09:52:32 »
Potřeboval bych provést nějakou akci, když se stiskne klávesa kdykoliv a kdekoliv v okně. Chci aby se zareagovalo pouze na uvolnění klávesy. Bohužel když je klávesa držená zmáčknutá, tak tak se akce neustále opakuje. Co dělám špatně?


Kód: [Vybrat]
KeyboardFocusManager.getCurrentKeyboardFocusManager()
                .addKeyEventDispatcher(new KeyEventDispatcher() {
                    @Override
                    public boolean dispatchKeyEvent(KeyEvent e) {
                       
                        if (e.getID() == KeyEvent.KEY_RELEASED) {
                           
                            System.out.println("akce");

                        }
                    }
                });
« Poslední změna: 13. 11. 2016, 22:24:09 od Petr Krčmář »


Re:Java-událost stisknutí tlačítka
« Odpověď #1 kdy: 12. 11. 2016, 11:39:22 »
Chování při držení klávesy je podle mne závislé na platformě (operačním systému). Java ty události jenom přebírá ze systému.

.

Re:Java-událost stisknutí tlačítka
« Odpověď #2 kdy: 12. 11. 2016, 11:52:12 »
Javu neznám, ale evidentně jsi se chytil na "klávesnici" a ne na fyzickou klávesu. Zatímco fyzická klávesa dá jeden event down a jeden up, "klávesnice" jich může vygenerovat mraky (viz třeba autorepeat, pokud klávesu držím).

Lol Phirae

Re:Java-událost stisknutí tlačítka
« Odpověď #3 kdy: 12. 11. 2016, 12:08:53 »
Co dělám špatně?

Používáš Javu.  ;D

Re:Java-událost stisknutí tlačítka
« Odpověď #4 kdy: 14. 11. 2016, 08:41:19 »



gll

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #6 kdy: 14. 11. 2016, 09:37:01 »
Na linuxu lze číst eventy z xinput, ale určitě existují i lepší řešení.

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #7 kdy: 14. 11. 2016, 10:03:11 »
Když se ti povede nějak z Javy vydobýt X11 handle, tak můžeš zkusit přes JNI zavolat XkbSetDetectableAutoRepeat.

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #8 kdy: 14. 11. 2016, 11:27:14 »
Vyrobil jsem nějaký hack. JNI wrapper je už v knihovně ve formě XlibWrapper, ale to je non-public API.

Kód: (Test.java) [Vybrat]
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test {
    public static void main(String[] args) throws Exception {
        Program prog = new Program();
        SwingUtilities.invokeAndWait(prog);
    }
   
    public static class Program implements Runnable {

        public Program() {}

        @Override
        public void run() {
            JFrame myFrame = new JFrame("Main frame");

            XHack.SetDetectableAutoRepeat(true);

            myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            myFrame.setSize(750, 500);
            myFrame.setLocationRelativeTo(null);
            myFrame.setVisible(true);

            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new Dispatcher());

        }
    }

    public static class Dispatcher implements KeyEventDispatcher {

        public Dispatcher() {}

        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {

            if (e.getID() == KeyEvent.KEY_RELEASED)
                System.out.println("akce");

            return false;

        }
    }
}
Kód: (XHack.java) [Vybrat]
import java.lang.reflect.Method;
import java.lang.Class;


public class XHack {
    public static void SetDetectableAutoRepeat(boolean enabled) {

        try {
            Class<?> xToolkit = Class.forName("sun.awt.X11.XToolkit");
            Class<?> xWrapper = Class.forName("sun.awt.X11.XlibWrapper");

            Method getDisplay = xToolkit.getDeclaredMethod("getDisplay");
            Method setRepeat  = xWrapper.getDeclaredMethod("XkbSetDetectableAutoRepeat", Long.TYPE, Boolean.TYPE);

            getDisplay.setAccessible(true);
            setRepeat .setAccessible(true);

            long display = (long) getDisplay.invoke(null);
            setRepeat.invoke(null, display, enabled);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
U mě to ale nemá žádný efekt, protože se to chová správně i bez toho.
« Poslední změna: 14. 11. 2016, 11:31:15 od linuxtardis »

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #9 kdy: 14. 11. 2016, 11:42:37 »
Moje domněnka, proč mi to funguje i bez toho:
XlibWrapper.XkbSetDetectableAutoRepeat(..., true) je volán z XToolkit.tryXKB()
XToolkit.tryXKB() je volán z XToolkit.init()
XToolkit.init() je volán z XToolkit.XToolkit()
XToolkit.XToolkit() je volán nepřímo z Toolkit.getDefaultToolkit() pomocí reflexe.
A Toolkit.getDefaultToolkit() je volán např. z EventQueue.invokeAndWait(...)
a ten je konečně volán z SwingUtilities.invokeAndWait(...)

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #10 kdy: 14. 11. 2016, 13:10:30 »
Chjo, někdy mám dlouhé vedení... :D
Funguje to, jde to otestovat tak, že místo true použiješ false. Pak u sebe mám stejnou situaci jako ty ve výchozím stavu (tzn. jak to nepotřebuješ).
Kód: [Vybrat]
XHack.SetDetectableAutoRepeat(false);

phi

Re:Java: událost stisknutí tlačítka v okně
« Odpověď #11 kdy: 14. 11. 2016, 14:48:42 »
To je proste problem na Xkach, pokud je mi znamo. beznej workarround je hlidat si rozestupy mezi key release a nasledujicim key pressed.