Monitorando CapsLock

Bem gente o que quero fazer é uma coisa muito comum, existentente em vários softwares por ai, que é captiturar o status das teclas capslock e numlock, aqui no forum mesmo encontrei um tópico falando disso, http://www.guj.com.br/posts/list/118945.java. Já da pra ter um idéia de como fazer, usar o evento de precionamento dessas teclas e fazer o teste com getLockingKeyState para obter o estado, assim, cada vez que a tecla for precionada o método getLockingKeyState é chamado para vericicar o estado da mesma (teoria). Só que estou com uma dúvida, se por acaso eu prescionar uma das teclas em um momento em que a janela da aplicação esteja minimizada ou sem o foco, quando a janela da aplicação for restaurada ou receber o foco ela irá atualizar ou eu terei que chamar o getLockingKeyState nessas ações (restaurar, ganhar foco) também?

Grato gente.

Tem que chamar também.

:shock:

Tava dando uma olhada nos requisitos aqui, parece que a coisa não vai ser tão simples como au achava, olha só, trata-se de uma aplicação MID, onde outros Frames vão abrir dentro de um JDesktopPane. Então, mesmo que o foco não esteja no frame principal e esteja em algum dos frames filhos, quando o susuário prescionar o capslock, deve aparecer lá na barra de status do frame principal.
Eu poderia setar o JLabel que representa o capslock como static, assim ele poderia ser acessado de qualquer lugar, mas tem dois detalhes.

Estou representando o stado das teclas LOCK através de JLabels. A intenção é fazer assim, capslock desligado = JLabel.setEnable(false) e capslock ligado = JLabel.setColor(uma cor qualquer). A duvida é se eu setar alguma modificação nesse jlabel estando com foco em algum frame filho essa moficicação vai ser logo visualizada ou apenas quando o foco voltar para o frame principal?

E outra terei que implementar o evento de precionamento da tecla em todos os frames da aplicação?

Caso negativo, tem geito de fazer isso?

O pulo do gato é o “getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)”. Só implementei a atualização do Caps Lock quando você está sobre a janela (mas não quando ela é restaurada, etc. Isso fica por sua conta).

package guj;

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;

public class ExemploCapsLock extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel jContentPane = null;
	private JLabel lblStatus = null;
	private JPanel pnlStatus = null;
	private JDesktopPane dspMain = null;
	private JPanel pnlButtons = null;
	private JButton btnNewInternalFrame = null;

	private JPanel getPnlStatus() {
		if (pnlStatus == null) {
			pnlStatus = new JPanel();
			pnlStatus.setLayout(new BorderLayout());
			pnlStatus.setBorder(BorderFactory
					.createBevelBorder(BevelBorder.LOWERED));
			pnlStatus.add(lblStatus, BorderLayout.EAST);
		}
		return pnlStatus;
	}
	private JDesktopPane getDspMain() {
		if (dspMain == null) {
			dspMain = new JDesktopPane();
		}
		return dspMain;
	}
	private Random r = new Random();
	private JInternalFrame createIntfExemplo() {
		JInternalFrame intfExemplo = new JInternalFrame();
		intfExemplo.setBounds(new Rectangle(14 + r.nextInt(30), 13 + r
				.nextInt(30), 187 + r.nextInt(30), 108 + r.nextInt(30)));
		intfExemplo.setTitle("Exemplo " + r.nextInt(100000));
		intfExemplo.setContentPane(new JPanel());
		return intfExemplo;
	}
	private JPanel getPnlButtons() {
		if (pnlButtons == null) {
			pnlButtons = new JPanel();
			pnlButtons.setLayout(new BorderLayout());
			pnlButtons.add(getBtnNewInternalFrame(), BorderLayout.NORTH);
		}
		return pnlButtons;
	}
	private JButton getBtnNewInternalFrame() {
		if (btnNewInternalFrame == null) {
			btnNewInternalFrame = new JButton();
			btnNewInternalFrame.setText("New Internal Frame");
			btnNewInternalFrame
					.addActionListener(new java.awt.event.ActionListener() {
						public void actionPerformed(java.awt.event.ActionEvent e) {
							JInternalFrame fr = ExemploCapsLock.this
									.createIntfExemplo();
							dspMain.add(fr);
							fr.setVisible(true);
						}
					});
		}
		return btnNewInternalFrame;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				ExemploCapsLock thisClass = new ExemploCapsLock();
				thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				thisClass.setVisible(true);
			}
		});
	}
	public ExemploCapsLock() {
		super();
		initialize();
	}
	private void initialize() {
		KeyStroke capsLockKey = KeyStroke
				.getKeyStroke(KeyEvent.VK_CAPS_LOCK, 0, true);
		getJContentPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put (capsLockKey, "capsLock");
		getJContentPane().getActionMap().put("capsLock", new AbstractAction() {
			@Override
			public void actionPerformed(ActionEvent e) {
				boolean capsLock = Toolkit.getDefaultToolkit()
						.getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
				if (capsLock)
					lblStatus.setText("Caps Lock ON");
				else
					lblStatus.setText("Caps Lock OFF");
			}
		});
		this.setSize(360, 258);
		this.setContentPane(getJContentPane());
		this.setTitle("Exemplo Caps Lock");
	}
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			lblStatus = new JLabel();
			lblStatus.setText("Caps");
			lblStatus.setHorizontalAlignment(SwingConstants.RIGHT);
			jContentPane = new JPanel();
			jContentPane.setLayout(new BorderLayout());
			jContentPane.add(getPnlButtons(), BorderLayout.NORTH);
			jContentPane.add(getDspMain(), BorderLayout.CENTER);
			jContentPane.add(getPnlStatus(), BorderLayout.SOUTH);
		}
		return jContentPane;
	}
} // @jve:decl-index=0:visual-constraint="10,10"


Show de bola!

Se eu fosse mulher te dava um beijo :lol: kkkkkkkkkkkk

Valeu brother qualquer dificudade replico aqui.

Perfeito mas tem um problema, não funciona quando o foco está sobre um JOptionPane. Acredito que seja pelo fato de que os JOptionPane por padrão não abrem dentro do JdesktopPane.
Existem algum geito de fazer os JOptionPane abrirem dentro do JDesktopPanel? Ou então de fazer funcionar com JOptionPane padrão?

Valeu!

Você pode usar uma caixa de diálogo interna.
Infelizmente, ela não “sai para fora” do JDesktopPane.

O código para visualizar a caixa de diálogo interna seria mais ou menos:

	private JButton getBtnNewOptionPane() {
		if (btnNewOptionPane == null) {
			btnNewOptionPane = new JButton();
			btnNewOptionPane.setText("New Option Pane");
			btnNewOptionPane.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					JOptionPane.showInternalMessageDialog (dspMain, "Hello! Goodbye");
				}
			});
		}
		return btnNewOptionPane;
	}


Ok, não lembrava que existia esses dialogos internos. var servir perfeito, não vejo necessidade de ter quer tirar o dialogo fora do desktop mesmo.

Agora sem querer abusar da bondade, se fosse possivel gostaria que vc desse uma comentada no trecho responssavel por emplementar a funcionalidade, pq tem uns métodos lá que não conhecia, como: getInputMap, getActionMap, put, etc… Li a documentação mas não entendi muito bem pra que servem esses métodos.

Grato!

1         KeyStroke capsLockKey = KeyStroke  
                 .getKeyStroke(KeyEvent.VK_CAPS_LOCK, 0, true);  
2         getJContentPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put (capsLockKey, "capsLock");  
3         getJContentPane().getActionMap().put("capsLock", new AbstractAction() {  
             @Override  
             public void actionPerformed(ActionEvent e) {  
                 boolean capsLock = Toolkit.getDefaultToolkit()  
                         .getLockingKeyState(KeyEvent.VK_CAPS_LOCK);  
                 if (capsLock)  
                     lblStatus.setText("Caps Lock ON");  
                 else  
                     lblStatus.setText("Caps Lock OFF");  
             }  
         }); 
  1. Isto cria um objeto KeyStroke, que representa uma tecla Caps Lock ao ser “released” (solta).
  2. O “input map” é uma forma de um componente (ou dos componentes que estão dentro desse componente, quando você usa “JComponent.WHEN_IN_FOCUSED_WINDOW”) lidar com teclas, cliques de mouse e outros eventos de entrada. Nesse caso, ele associa a tecla Caps Lock à ação com o nome “capsLock”.
  3. O “action map” mapeia nomes (como “capsLock”) a ações. Neste caso, criou-se uma ação “capsLock”, que cada vez que é acionada (digamos ao soltarmos a tecla Caps Lock) checa qual o estado do Caps Lock e muda o texto do JLabel.

Perfeito, entendi.

O action map não era realmente o que eu estava penssando que era.

Cara, to com outro pleblema. Eu consigo checar o status no momento em que a aplicação é aberta, funciona com focusGained ou com windowsOpened, porém não to comseguindo checar quando a janela da aplicação perde o foco para outros programas e depois recebe o foco novamente. O focusGained era pra resolver isso mas não acontece nada. Ja tentei com vários, windowsDeiconified, windowsActived, mas nem um funciona coloquei pra exibir menssgens ai funciona, mas pra fazer a checagem não.

Bem gente, descobri o problema mas não sei como resolver.

O problema é que a variavel tipo booleana que recebe o resutado do getLockingKeyState() está mantendo o seu valor inicial e não está mudando

Um exemplo bem simples, coloquei um teste no evento focusGained do JFrame.

    private void formFocusGained(java.awt.event.FocusEvent evt) {                                 
        boolean lockpress = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_NUM_LOCK);
        if(lockpress){
            System.out.println("Verdadeiro");
        }
        else {
            System.out.println("Falso");
        }
        
        /*System.out.println("Está executando");
        bs.getLock(KeyEvent.VK_NUM_LOCK, jlnumlock);
        bs.getLock(KeyEvent.VK_CAPS_LOCK, jlcapslock);*/
    }                                

Se executarem esse teste verão que a variavel lockpress fica sempre com o seu primeiro valor, se começar com false será false sempre e vice e versa, mesmo que eu mude o foco para outra aplicação e prescione a tecla numlock, quando volto o foco para a aplicação a variavel lockpress continua a ter o mesmo valor.

:roll:

Bem pra ficar de informação para alguém que como eu futuramente resolva criar as famosas Barras de Status, e implementar o monitoramento das teclas Lock, DESISTA. Infelizmente com java não é possivel, tudo porque existe um bug no metodo getLockingKeyState(). Então a não ser que vc esteja disposto a perder um logo tempo desenvolvendo sua própria solução para capturar o estado das teclas cap, desista.
Sei que nós somos previlégiados por termos acesso 100% gratuito a uma ferramenta como o java. Mas é bincadeira não :x um bug reportado a 9 anos atrás e até hoje não foi corrigido. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414164
Mas essa é a realidade de softwares livres, como não existe compromisso para com os clientes pois trata-se de um produto livre, não há cobrança e consequentemente a correção de bugs depende da disposição dos mantenedores da ferramenta/tecnologia. Se fosse um produto comercial como da MS em questão de meses já estaria resolvido.
Fazer o que né, o jeito é esperar mais alguns anos para ver se os responssaveis acordam de bom humor e resolvem corrigir o bug.

[quote=matheusssilva]pois trata-se de um produto livre, não há cobrança e consequentemente a correção de bugs depende da disposição dos mantenedores da ferramenta/tecnologia.
[/quote]

Bullshit.
O fato é exatamente ao contrário: se o Java efetivamente fosse um software completamente livre, isso já teria sido corrigido há séculos.
É que o pessoal da Sun/Oracle prioriza a correção de alguns bugs e mesmo as contribuições/correções feitas pela comunidade demoram “um pouco” para serem efetivadas.
Um bug que está há 9 ou 10 anos nessa lista provavelmente nunca foi revisado pelo pessoal de lá. Olhando o log das alterações do OpenJDK, dá para ver que um monte de coisas foi efetivamente contribuída por eles, por exemplo (muitos engenheiros da Red Hat têm acesso de “commiter” no código do OpenJDK.
Algumas correções podem e devem ter sido feitas pelo pessoal da Red Hat, que contribui com o pessoal da Sun pelo projeto IcedTea, que é uma implementação do OpenJDK para o Linux. Mas pode ser, por exemplo, que tal coisa tenha passado batida - afinal, o bug database é da Sun/Oracle, não da Red Hat.
EDIT
Não tinha visto que o bug era em relação ao Windows. Nesse caso, acho que não há muitos “commiters” externos à Sun/Oracle que mexam com a parte Windows do OpenJDK; portanto, isso provavelmente vai ficar sem solução por algum tempo :frowning: