Dúvida para Implementar Ideia

Olá pessoal, bom dia.

Gostaria de uma luz quanto a uma possível programação, minha ideia é que ao utilizar a tecla de pesquisa Ctrl+F e informar um numero especifico, ao clicar Enter o botão seja sensível para identificar o numero e selecionar uma caixinha que no sistema o qual utilizo habilita um outro botão para que eu realize uma impressão de documentos.
Não sei se ficou claro e sou leiga quanto ao assunto, mas caso possam ajudar com o conhecimento de você, fico agradecida.

Ideia

é um sistema Web ou Desktop? se for Web vc usa algum framework? dê mais detalhes pra gente pode te ajudar

Se for apenas um número, seria melhor mudar o nome “localizar” para “selecionar”.

Se for vários, poderia usar um “textarea” em que digita vários números separados por espaços, depois com um botão “selecionar todas” marcasse todos os números.

Também poderia criar uma forma de intervalos, exemplo entra “123~330” e marca todos dentro do intervalo.

2 curtidas

Olá Diego,

Acho interessante a idéia eu vou dar uma pesquisada sobre o assunto. Eu pensei em ter uma ferramenta com a função do clicador, porem com a inteligência que ele não possui em selecionar números específicos no qual vou possuir uma massiva em arquivo excel, por isso exemplifiquei a funçao ctrl+f porque realizo a busca do número exato, e gostaria que no momento do enter ele não só me mostrasse o número pesquisado como também selecionasse a caixa na linha do número qie indiquei. Como utilizamos um sistema já desenvolvido não consigo fazer alterações, por isso pensei em uma ferramenta a mais, usando o clicador ele faria o processo sozinha apenas com o meu comando repetido.

Acho melhor deixar o Enter somente para pesquisa pois isso pode bagunçar as marcações. Não sei como a busca funciona, mas supondo que ao digitar a busca seja feita automaticamente, então tudo bem em usar o “Enter” para marcar ou desmarcar.

Uma outra sugestão seria usar uma outra lista que adiciona aqueles que seriam marcados, assim não perderia de vista as marcadas caso fizesse nova busca, como um componente PickList, exemplo no link:
https://www.primefaces.org/showcase/ui/data/pickList.xhtml

1 curtida

A busca que é o grande problema, porque eu queria exemplificando que quando eu utilizasse a função Ctrl + F e clicasse para pesquisar ele de imediato já selecionasse a linha com o numero correto,nesse tela que mandei anteriormente veja que o numero 119738 / 69059 esta na função Ctrl+F ele indicou, porem não consegue selecionar. Para que eu use a tecla “Enter” para marcar ou desmarcar, consegue me ajudar a como programar?

O sistema é de terceiro ?

Se for ai daria mais trabalho porque você teria de ler o site, buscar a tabela e procurar elemento por elemento.

Mas caso o sistema seja feito por você mesmo, o que da pra fazer é criar um input para buscar dentro do campo da tabela “n° contr…” o valor digitado, e caso ele ache você pode usar a função .parent() do jquery e selecionar a linha da tabela.

Com essa linha da tabela selecionada basta você buscar pelo check box e dar um checked nele.

Abraços.

2 curtidas

Olá John,

Sim, é de terceiro. :weary:
Sou bem leiga quanto ao assunto mas agradeço sua ideia, vou pesquisar para entender melhor e realizar alguns testes.

Abraços, muito obrigada.

Eu acho que a sugestão do @John-Jones está no caminho certo. Pelo que entendi, você usa um sistema web - acessado pelo navegador - que não pode modificar o código, mas você deve conseguir sim fazer o que você quer! eu vejo três formas:

  1. Crie uma extensão para o Navegador, é fácil se for o Chrome (os outros eu não sei), mas você vai precisar de conhecimento de javascript e html.
  2. Use o Selenium IDE, talvez você consiga implementar sua ideia até mesmo sem o conhecimento de javascript ou de outra linguagem de programação com ele (nuca usei ele mas vi que tem umas interfaces gráficas pra ele). Também sei que ele pode ser conectado ao java para controlar a página web no Navegador através de código java.
  3. Crie um “Clicador” (um programa Robô) que identifica o número selecionado e a CheckBox que está na mesma linha, ele vai cuidar então de clicar nessa checkbox.

Criar um clicador desse pode ser bem fácil, na verdade:

  1. Ele precisa buscar dois retângulos compridos de pixels que estejam a uma determinada distância uns dos outros, onde os pixels serão dessa cor:
    image
    Essa é a cor que o Navegador usou para selecionar os Números, seu programa iria buscar as faixas de pixels dessa cor que estão acima e abaixo do número Selecionado, mais ou menos assim:
    image
    Seu programa buscaria pela tela o que está dentro dos retângulos de contorno azul acima.

  2. Ao encontrar, seu programa já sabe a (ou tem noção suficiente da) posição Y em que estará a CheckBox, então ele pode buscar pelos pixels da checkbox dentro da Faixa Y descoberta:
    image

  3. Quando seu programa encontrar a checkbox, é só ele clicar nela quando você teclar Enter (seu programa precisará ouvir os Eventos Nativos do teclado).

Eu implementei algo semelhante a isso em Java a pouco tempo, usando a classe Robot, não é difícil não. O problema, é que basta um pixel diferente e o programa já não vai funcionar, porque ele compara pixel por pixel. Mas o meu tem funcionado muito bem :slight_smile:
Para ouvir os Eventos Nativos do Teclado com Java, dá pra usar o JNativeHook, que também é fácil de usar.

Em qualquer uma das opções que você escolher, você não vai precisar de muito código, mas, infelizmente, pode gastar um bom tempo aprendendo o necessário pra implementar.

2 curtidas

Douglas,

Achei fantástica a ideia, muito obrigada pelas alternativas, vou pesquisar e tentar executar.
No caso do clicador, não querendo abusar, mas já abusando, se não for dar muito trabalho e puder me ajudar com os códigos e a forma de fazer, agradeço, mas de qualquer forma vou pesquisando e agradeço demais pelo direcionamento.

Abraço. :wink:

A desvantagem do clicador em relação as implementações com Selenium/Extensão-de-Navegador é que estas últimas são muito mais resilientes, ou seja:

  • o Clicador pode “quebrar” se as coias mudarem de lugar, alterar o Zoom da página ou não deixar o navegador em tela cheia já pode ser o suficiente para quebrá-lo;
  • Ele se baseia em comparação de pixels, então a mudança na renderização também pode quebrá-lo (usar um Navegador diferente, ou, uma nova versão do Navegador que gera uma renderização diferente).
  • Uma resolução de Tela diferente também pode quebrá-lo, pois as coisas podem aparecer em lugares diferentes, ou a renderização pode mudar por serem mais/menos pixels.

Se sua utilização é sempre igual, o Clicador pode funcionar, pelo menos por um bom tempo.

Pra mim te ajudar a fazer um clicador para sua necessidade, vou precisar que envie PrintScreens da sua tela toda, sem cortar nada, onde haja os números selecionados na página após utilizar o Ctrl+F.

1 curtida

Ocultar as informações dos clientes assim não deve causar problemas, há menos que você precise cobrir a área laranja que o Ctrl+F do navegador destaca, porque o programa vai varrer uma área da tela buscando por esses pixels.

Hum, não sei se essas imagens vão dar certo, você colocou o Navegador em tela cheia? É assim que você vai usar no dia-a-dia? Caso contrário, você precisa me dar o printscreen da tela por completo mesmo, sem recortar as bordas dela; isso inclui a barra de tarefas do windows (ou do seu S.O.), as abas do chrome, etc.

Você pode cobrir as informações, mas não pode cortar a imagem, nem redimensionar, porque se não a posição dos pixels muda (redimensionar é pior ainda, aí nem dá para usar a imagem). Seria algo como essa imagem que peguei da internet:

Deve dar certo você colocar as imagens aqui no GUJ, tem a opção de baixar, e eu acho (e espero que) o GUJ não as modifique ao rodar algum algoritmo de otimização de imagens.

Acho que essa 1ª imagem que você postou, a de cima, é do tipo que vai dar certo; tira uns 3 printscreens selecionando números diferentes, uns com o número XXXXXX e outras com o número com barra XXXXXX / XXXXX. Eu quero ver se os pixels laranja aparecem bem nítidos em cima e em baixo dos números sem contaminação de outras cores.

Essa imagem de baixo eu não entendi, é uma tela bem diferente. O programa teria que lidar com essa tela também? Você vai usar Ctrl+F nela? O que o programa teria que fazer nesta tela?

A minha ideia é um programa que roda no Tray do sistema, em Java. Ele iria simplesmente detectar os pixels laranja da área destacada pelo Ctrl+F, para descobrir a posição Y da checkbox, e então buscar a checkbox certa comparando pixels.

Ainda não está pronto, mas o código abaixo já consegue fazer o seguinte:

  1. Detectar a linha Selecionada pelo Navegador (na cor laranja) ao usar Ctrl+F;
  2. Determinar uma Área onde a Checkbox dessa Linha específica está;
  3. Encontrar a posição dessa Checkbox na Tela e mover o cursor para cima dela.

Fazer o cursor clicar nela vai ser fácil, já fiz um método “clicar(…)”.

No futuro será necessário usar o JNativeHook para que todo esse processamento ocorra sempre que você teclar Enter.

Agora acho bom você testar, para testar faça o seguinte:

  1. Abra o Navegador no seu sistema e use Ctrl+F para selecionar alguma das linhas, como na “tela teste 2.PNG”;
  2. Coloque as classes abaixo na sua IDE e compile, rode o código do Main;
  3. Após iniciar a execução do Código, você terá 5 segundos para alternar para o navegador deixando-o maximizado como “tela teste 2.PNG”, pois após esse tempo o Clicador ira dar um prinscreen e irá buscar a linha selecionada e checkbox.

Se tudo der certo, o cursor deve ir parar em cima da checkbox, e você deve ver algo assim:

package main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class Main {

	private static BufferedImage checkBoxImage;
	private static JFrame tela;
	private static Robot robo;

	private static boolean isFechar = false;
	private static BuscadorDaCheckboxDaLinhaSelecionada buscadorDaCheckboxDaLinhaSelecionada;

	public static void main(String[] args) {
		try {
			dormir(5000);
			robo = new Robot();
			checkBoxImage = ImageIO.read(new File("src/images/partedecheckbox.png"));
			BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada = new BuscadorDeLinhaSelecionada(
					new Color(255, 150, 50), 5, 5);
			Rectangle areaDaSelecao = new Rectangle(674, 318, 103, 492);
			buscadorDaCheckboxDaLinhaSelecionada = new BuscadorDaCheckboxDaLinhaSelecionada(checkBoxImage,
					buscadorDeLinhaSelecionada, areaDaSelecao, 365, 400, robo);
			Rectangle boundsDaCheckboxEncontrada = buscadorDaCheckboxDaLinhaSelecionada
					.buscarCheckboxDaLinhaSelecionada();
			System.out.println(boundsDaCheckboxEncontrada);
			if (boundsDaCheckboxEncontrada != null) {
				robo.mouseMove(boundsDaCheckboxEncontrada.x, boundsDaCheckboxEncontrada.y);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
			saidaComErro(e1);
		}

		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					tela = new Tela();
					// tela.setExtendedState(JFrame.ICONIFIED);
				} catch (Exception e) {
					e.printStackTrace();
					saidaComErro(e);
				}
			}
		});
	}

	public static void dormir(int tempo) {
		try {
			Thread.sleep(tempo);
		} catch (InterruptedException e) {
			e.printStackTrace();
			saidaComErro(e);
		}
	}

	private static void saidaComErro(Exception e) throws HeadlessException {
		JOptionPane.showMessageDialog(null, e);
		System.exit(1);
	}

	/** Clica na posição x e y passadas. */
	private static void clicar(int x, int y) {
		robo.mouseMove(x, y);
		robo.mousePress(InputEvent.BUTTON1_DOWN_MASK);
		robo.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
	}

	@SuppressWarnings("serial")
	private static class Tela extends JFrame {
		TrayIcon trayIcon;
		SystemTray tray;

		Tela() {
			super("Clicador em Checkbox de linha Selecionada");
			System.out.println("creating instance");
			try {
				System.out.println("setting look and feel");
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (Exception e) {
				System.out.println("Unable to set LookAndFeel");
				saidaComErro(e);
			}
			if (SystemTray.isSupported()) {
				System.out.println("system tray supported");
				tray = SystemTray.getSystemTray();

				ActionListener exitListener = new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						System.out.println("Exiting....");
						isFechar = true;
						System.exit(0);
					}
				};
				PopupMenu popup = new PopupMenu();
				MenuItem defaultItem = new MenuItem("Sair");
				defaultItem.addActionListener(exitListener);
				popup.add(defaultItem);
				defaultItem = new MenuItem("Abrir");
				defaultItem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						setVisible(true);
						setExtendedState(JFrame.NORMAL);
					}
				});
				popup.add(defaultItem);
				// trayIcon = new TrayIcon(checkBoxImage, "Clicador de Checkbox", popup);
				// trayIcon.setImageAutoSize(true);
			} else {
				System.out.println("system tray not supported");
			}
			addWindowStateListener(new WindowStateListener() {

				public void windowStateChanged(WindowEvent e) {
					if (e.getNewState() == ICONIFIED || e.getNewState() == 7) {
						System.out.println("ICONIFIED: " + ICONIFIED);
						try {
							// tray.add(trayIcon);
							setVisible(false);
							System.out.println("added to SystemTray");
						} catch (Exception ex) {
							System.out.println("unable to add to tray");
							saidaComErro(ex);
						}
					}
					if (e.getNewState() == MAXIMIZED_BOTH || e.getNewState() == NORMAL) {
						// tray.remove(trayIcon);
						setVisible(true);
						System.out.println("Tray icon removed");
					}
				}
			});

			setIconImage(checkBoxImage);

			setSize(230, 500);
			// setResizable(false);
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			add(new Painel());
			setAlwaysOnTop(true);
			setVisible(true);
		}
	}

	@SuppressWarnings("serial")
	private static class Painel extends JPanel {
		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.setColor(Color.DARK_GRAY);
			g.fillRect(0, 0, getWidth(), getHeight());

			BufferedImage areaDaSelecao = buscadorDaCheckboxDaLinhaSelecionada.areaDaSelecaoBuscada.get();
			if (areaDaSelecao != null) {
				g.drawImage(areaDaSelecao, 20, 20, null);
				BufferedImage areaDaCheckbox = buscadorDaCheckboxDaLinhaSelecionada.areaComCheckboxBuscada.get();
				if (areaDaCheckbox != null) {
					g.drawImage(areaDaCheckbox, areaDaSelecao.getWidth() + 30, 20, null);
					g.drawImage(checkBoxImage, areaDaSelecao.getWidth() + 30, areaDaCheckbox.getHeight() + 30, null);
				}
			}
		}

	}

}

Busca a linha com a cor laranja:

package main;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class BuscadorDeLinhaSelecionada {

	private Color corDaSelecao;

	private int margemSuperiorAdicionada; // valor em pixels
	private int margemInferiorAdicionada; // valor em pixels

	public BuscadorDeLinhaSelecionada(Color corDaSelecao, int margemSuperiorAdicionada, int margemInferiorAdicionada) {
		this.corDaSelecao = corDaSelecao;
		this.margemSuperiorAdicionada = margemSuperiorAdicionada;
		this.margemInferiorAdicionada = margemInferiorAdicionada;
	}

	public LinhaDaSelecao encontrarInicioEFimDaLinhaSelecionada(BufferedImage areaDaSelecaoScreenshot, int margemY) {
		LinhaDaSelecao linha = encontrarInicioEFim(areaDaSelecaoScreenshot, corDaSelecao, margemY);
		if (linha == null)
			return null;
		System.out.println("inicioY: " + linha.inicioY + " / linha.fimY: " + linha.fimY);
		linha.inicioY = linha.inicioY - margemSuperiorAdicionada;
		linha.fimY = linha.fimY + margemInferiorAdicionada;
		System.out.println("inicioY: " + linha.inicioY + " / linha.fimY: " + linha.fimY);
		return linha;
	}

	private LinhaDaSelecao encontrarInicioEFim(BufferedImage img, Color cor, int margemY) {
		boolean encontrou = false;
		LinhaDaSelecao linhaDaSelecao = new LinhaDaSelecao();
		linhaDaSelecao.inicioY = Integer.MAX_VALUE;
		linhaDaSelecao.fimY = Integer.MIN_VALUE;
		for (int x = 0; x < img.getWidth(); x++) {
			for (int y = 0; y < img.getHeight(); y++) {
				if (new Color(img.getRGB(x, y)).equals(corDaSelecao)) {
					int posicaoYRealDoPixel = y + margemY;
					if (linhaDaSelecao.inicioY > posicaoYRealDoPixel) {
						encontrou = true;
						linhaDaSelecao.inicioY = posicaoYRealDoPixel;
					}
					if (linhaDaSelecao.fimY < posicaoYRealDoPixel) {
						encontrou = true;
						linhaDaSelecao.fimY = posicaoYRealDoPixel;
					}
				}
			}
		}
		return (encontrou) ? linhaDaSelecao : null;
	}

	public static class LinhaDaSelecao {
		public int inicioY;
		public int fimY;
	}
}

Busca a checkbox dentro da área onde ela pode estar:

package main;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;

public class BuscadorDeImagemDentroDeImagem {

	/**
	 * Busca a 'imagemFilho' dentro da 'imagemPai' retornando um {@link Rectangle}
	 * com a informação (x, y, width e height) de onde ela foi encontrada na
	 * 'imagemPai'; ou retorna null caso não a encontre.
	 */
	public static Rectangle buscarFilho(BufferedImage imagemPai, BufferedImage imagemFilho) {
		for (int x = 0; x < imagemPai.getWidth(); x++) {
			for (int y = 0; y < imagemPai.getHeight(); y++) {
				if (contemFilho(imagemPai, imagemFilho, x, y)) {
					return new Rectangle(x, y, imagemFilho.getWidth(), imagemFilho.getHeight());
				}
			}
		}
		return null;
	}

	/**
	 * Retorna true apenas se a 'imagemFilho' for encontrada na 'imagemPai' na
	 * posição 'offsetX' e 'offsetY' passadas; retorna false caso contrário.
	 */
	public static boolean contemFilho(BufferedImage imagemPai, BufferedImage imagemFilho, int offsetX, int offsetY) {
		if (!filhoCabeDentroDoPai(imagemPai, imagemFilho, offsetX, offsetY)) {
			return false; // não contém o filho se ele não cabe dentro do pai
		}
		for (int x = 0; x < imagemFilho.getWidth(); x++) {
			for (int y = 0; y < imagemFilho.getHeight(); y++) {
				if (imagemPai.getRGB(offsetX + x, offsetY + y) != imagemFilho.getRGB(x, y)) {
					return false;
				}
			}
		}
		return true;
	}

	private static boolean filhoCabeDentroDoPai(BufferedImage imagemPai, BufferedImage imagemFilho, int offsetX,
			int offsetY) {
		if ((offsetX + imagemFilho.getWidth()) > imagemPai.getWidth()) {
			return false;
		}
		if ((offsetY + imagemFilho.getHeight()) > imagemPai.getWidth()) {
			return false;
		}
		return true;
	}

}

Basicamente cuida de tudo que implementei:

package main;

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import main.BuscadorDeLinhaSelecionada.LinhaDaSelecao;

public class BuscadorDaCheckboxDaLinhaSelecionada {

	private Robot robo;

	private BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada;

	private Rectangle areaDaSelecao;
	private int bordaEsquerdaDaAreaDeCheckbox;
	private int bordaDireitaDaAreaDeCheckbox;

	private BufferedImage imagemDaCheckbox;

	/** Não altere o valor desta property. */
	public final ObjectProperty<BufferedImage> areaComCheckboxBuscada = new SimpleObjectProperty<>();
	/** Não altere o valor desta property. */
	public final ObjectProperty<BufferedImage> areaDaSelecaoBuscada = new SimpleObjectProperty<>();

	public BuscadorDaCheckboxDaLinhaSelecionada(BufferedImage imagemDaCheckbox,
			BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada, Rectangle areaDaSelecao,
			int bordaEsquerdaDaAreaDeCheckbox, int bordaDireitaDaAreaDeCheckbox, Robot robo) throws AWTException {
		this.robo = robo;
		this.imagemDaCheckbox = imagemDaCheckbox;
		this.buscadorDeLinhaSelecionada = buscadorDeLinhaSelecionada;
		this.areaDaSelecao = areaDaSelecao;
		this.bordaEsquerdaDaAreaDeCheckbox = bordaEsquerdaDaAreaDeCheckbox;
		this.bordaDireitaDaAreaDeCheckbox = bordaDireitaDaAreaDeCheckbox;
	}

	public Rectangle buscarCheckboxDaLinhaSelecionada() {
		areaDaSelecaoBuscada.set(robo.createScreenCapture(areaDaSelecao));
		LinhaDaSelecao linhaSelecionada = buscadorDeLinhaSelecionada
				.encontrarInicioEFimDaLinhaSelecionada(areaDaSelecaoBuscada.get(), areaDaSelecao.y);
		if (linhaSelecionada != null) {
			int width = bordaDireitaDaAreaDeCheckbox - bordaEsquerdaDaAreaDeCheckbox;
			int height = linhaSelecionada.fimY - linhaSelecionada.inicioY;
			Rectangle boundsDaAreaComCheckboxBuscada = new Rectangle(bordaEsquerdaDaAreaDeCheckbox,
					linhaSelecionada.inicioY, width, height);
			System.out.println("boundsDaAreaComCheckboxBuscada: " + boundsDaAreaComCheckboxBuscada);
			areaComCheckboxBuscada.set(robo.createScreenCapture(boundsDaAreaComCheckboxBuscada));
			Rectangle boundsDaCheckbox = BuscadorDeImagemDentroDeImagem.buscarFilho(areaComCheckboxBuscada.get(),
					imagemDaCheckbox);
			if (boundsDaCheckbox != null) {
				boundsDaCheckbox.x += boundsDaAreaComCheckboxBuscada.x;
				boundsDaCheckbox.y += boundsDaAreaComCheckboxBuscada.y;
			}
			System.out.println("boundsDaCheckbox: " + boundsDaCheckbox);
			return boundsDaCheckbox;
		}

		return null;
	}

}

Atenção para essa imagem “src/images/partedecheckbox.png”, você recortar a imagem da checkbox obtida pelo seu printscreen garantindo que a parte recortada é igual - em todos os pixels - a todas as outras checkbox da tela. O programa busca na tela (dentro da área onde a checkbox buscada pode estar) por essa “partedecheckbox” conferindo pixel-a-pixel. Veja se essa imagem abaixo dará certo para ser a “partedecheckbox.png”:

partedecheckbox_teste

A estrutura do projeto:
image

1 curtida

Douglas,

Muito obrigada, você é demais … Ainda não consegui realizar os testes mas fico imensamente agradecida pelo seu tempo dedicado, preciso solicitar alguns acessos para o ambiente de teste e execução do programa pode listar pra mim o que vou precisar solicitar instalação para ambiente de teste e posterior executar o clicador? Devido ao acesso restrito por ser ambiente corporativo, vou precisar solicitar a área de TI a instalação, pra dai então conseguir testar. Desculpa pelo abuso.

Hum… parece que testar o programa aí é meio complicado, talvez seja melhor ter o programa já pronto (ou quase pronto) pra mandar para o teste.

De qualquer forma, esse programa vai ter que fazer coisas que podem ser vistas como perigosas: o Robot do Java permite fazer screenshots e emitir eventos de mouse e teclado, então ele poderia ser usado para vazar dados (através dos screenshots) ou mesmo dar controle da máquina a um hacker (controle de mouse/teclado)!

O JNativeHook é uma biblioteca, que pode ser ainda mais perigosa: é muito fácil usá-la para criar um KeyLogger, já que ele tem como objetivo ficar ouvindo os Eventos do Sistema Operacional.

Um programa Java pode ser exportado em um arquivo JAR, sendo meio que um “executável portátil”, não precisando instalar nada. Mas o Computador que vai rodá-lo precisa ter a JVM instalada, que roda os programas Java. Acho que quase todo computador tem a JVM, mas não sei. Qualquer coisa dá pra baixar e instalar, “instalar o Java”.

Acho que o melhor que você pode fazer é conversar com o pessoal da TI, eles podem analisar o código pra ver que não é malicioso, e para determinar se abrirá vulnerabilidades no sistema ou não.

Você programa em Java? tem acesso a uma IDE pra compilar, editar e/ou rodar o código que te mandei?

Eu estou te ajudando com isso porque acredito que a vontade de Deus é que façamos pelos outros o que gostaríamos que fizessem por nós, eu amo Deus e com isso tenho a vontade de fazer o bem no meu coração (vontade que Ele mesmo colocou); eu acho que esse Clicador pode ser uma benção no seu dia-a-dia e que seria muito mais díficil pra você fazê-lo do que pra mim, por isso decidi fazê-lo. :slight_smile:

Que Deus te abençoe.

Eu também não tenho muito conhecimetno nessa área, mas acho que os problemas são:

  1. Existem malwares que se aproveitam de bibliotecas instaladas no computador infectado, utilizando-as a seu serviço. Se um malware infectar uma máquina com a biblioteca JNativeHook, talvez ele consiga utilizar essa biblioteca para ficar “escutando” tudo que é digitado. Mas talvez precise ser um malware projetado para reconhecer essa biblioteca e saber como consumí-la, algo um tanto específico.

  2. A documentação da classe Robot diz (o negrito é meu):

Using the class to generate input events differs from posting events to the AWT event queue or AWT components in that the events are generated in the platform’s native input queue. For example, Robot.mouseMove will actually move the mouse cursor instead of just generating mouse move events.

Note that some platforms require special privileges or extensions to access low-level input control. If the current platform configuration does not allow input control, an AWTException will be thrown when trying to construct Robot objects. For example, X-Window systems will throw the exception if the XTEST 2.2 standard extension is not supported (or not enabled) by the X server.

Applications that use Robot for purposes other than self-testing should handle these error conditions gracefully.

Veja que para rodar o Robot o computador pode precisar de “privilégios especiais”, eu imagino que esses privilégios seriam dados em alguma configuração da JVM, ou em alguma configuração do computador, mas não sei. De qualquer forma, sempre que é necessário “aumentar os privilégios” a segurança cai, pois malwares talvez consigam se aproveitar desses privilégios.

Em qualquer caso, o programa sózinho não faz nenhum mal, mas, se a máquina for infectada por um malware talvez esse malware consiga se aproveitar dos recursos/privilégios consumidos pelo programa.

Seria necessário uma pesquisa mais profunda para saber sobre vulnerabilidades abertas pela classe Robot e pelo JNativeHook. Preferencialmente uma pesquisa em inglês.

Dá para reaproveitar quase todo o código que fiz mudando a implementação do Robô e do Listener-de-Eventos-Nativos (JNativeHook), por outras bibliotecas que a equipe de TI preferir. Talvez dê até para evitar a utilização de um Listener-de-Eventos-Nativos, se o robô conseguir monitorar a tela para saber em qual momento deve clicar na checkbox; mas no fim, o programa precisará fazer screenshots e dar clicks, então será necessário usar algum robô (mesmo que seja de outra biblioteca, ou, de algum modo, implementado em outro programa que seria controlado pelo programa que fiz).

Talvez isso dê certo para aumentar a segurança (precisa ser mais pesquisado, pra ver se ajuda mesmo):

  1. Veja se é possível rodar navegador com o sistema web numa Máquina Virtual, como o VirtualBox, dentro dessa Máquina Virtual você colocaria o Clicador também, para usá-lo junto. Com isso, você pode estar isolando o Clicador e o SistemaWeb do resto dos Sistema, mantendo-os ativos apenas enquanto está usando. A ideia é que, como o Clicador está rodando na Máquina Virtual, se um malware tentar controlar alguma biblioteca dele essa biblioteca também estará limitada à Máquina Virtual e suas restrições.

  2. O programa é um JAR, pode ficar todo dentro de uma pasta, não precisa ser instalado; com isso, você pode: Comprimir e Criptogravar a pasta do Programa enquanto não estiver usando, evitando o acesso a ele, depois, na hora de usar, descomprimir/descriptografar. Se você vai ficar usando-o o tempo todo (como imagino), isso nem deve adiantar; mas a ideia é que, enquanto comprimido e criptografado, nenhum malware conseguiria usufruir do JNativeHook no programa.

Dei uma pesquisada rápida sobre a segurança do Robot e do JNativeHook, e não encontrei praticamente nada relevante. Apenas alguns dizendo que o Robot pode trazer vulnerabilidades como eu disse, sem maiores explicações ou fontes confiáveis. Para o JNativeHook, o que encontrei foi um malware feito em java que - aparentemente - já vem com o JNativeHook para usá-lo em suas atividades (os criadores do malware colocaram o JNativeHook no malware deles), mas não vi nada sobre ele se aproveitar do JNativeHook já presente em outro programa:

Pode ser uma boa coisa perguntar sobre isso no StackOverFlow, de preferência o inglês se você sabe escrever bem em inglês (me negativaram lá uma vez por escrever mau em inglês :frowning: ). Perguntar sobre vulnerabilidades da classe awt.Robot e do JNativeHook, se existem exploits para eles, e o que pode ser feito para se proteger.

No primeiro link que te mandei eu vi algo sobre as AWTPermissions, que não sei quase nada, diz assim:

AWTPermission - Permissions are defined in the policy file which modules should not have access to, but still a good thing to take note of.

Pelo que entendi, são algumas dessas AWTPermissions que o Robot vai precisar, e parece que elas são definidas em um arquivo; seria necessário pesquisar sobre isso e ver se é possível fazer as permissões serem dadas apenas ao Clicador, com segurança de que nenhum malware pode se aproveitar dessas Permissions.

Eu não tenho conhecimento suficiente para dizer o quão inseguro seria usar esse Clicador, talvez não diminua em quase nada a segurança, imagino que isso depende do qual difícil/fácil é criar um malware que conseguiria se aproveitar. Se for fácil, deve ser fácil também encontrar exploits para o Robot e para o JNativeHook, e deve ser fácil encontrar pessoas experientes no StackOverflow em inglês dizendo como o uso dessas bibliotecas podem ser exploradas por malwares.

No fim, me diga qual decisão você tomou, se vai seguir adiante com esse programa ou não, se você for seguir adiante eu continuando implementando. Acho que falta bem pouquinho pra terminá-lo.

Que bom que você consegue editar o código, assim você será capaz de alterar os valores de Configuração. Percebi que o programa, na verdade, ficou até bem resiliente:

  • Apenas alterando as Configurações o Programa pode ser adaptado para funcionar:
    1. Em outra Resolução da Tela;
    2. Em outro Navegador e/ou outra Versão do mesmo Navegador;
    3. Em uma versão um pouco diferente do Layout do site, caso este venha a ser alterado;
    4. Com Zoom no Navegador;
    5. Com a Janela do Navegador não-maximizada (mas precisa estar em lugar específico da tela, de acordo com a Configuração);
    6. Em outro Computador.
1 curtida

Bem, acredito que está pronto, depois vou ter que te explicar sobre as Configurações para você poder reconfigurar caso precise. Eu centralizei todas as configurações no método “iniciarConfiguracoes()”, então você já sabe o ponto de todo o código que precisará alterar, e não ficará perdida.

Você vai ter que baixar o JNativeHook e importar o JAR dele para o seu Projeto, eu fiz no Eclipse seguindo o que está escrito aqui, veja como é no NetBeans. Eu usei a versão 2.0.3, acho que já deve ter novas versões, mas não sei se são compatíveis ou se você terá que mudar o código.

Assim fica a estrutura do Projeto:

image

Classe Main:

package main;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import main.listener.ListenerDeEventosNativos;
import main.listener.ProcessadorDeEventosNativos;

public class Main {

	private static BufferedImage checkBoxImage;
	private static JFrame tela;
	private static Robot robo;

	private static BuscadorDaCheckboxDaLinhaSelecionada buscadorDaCheckboxDaLinhaSelecionada;

	public static void main(String[] args) {

		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					tela = new Tela();
				} catch (Exception e) {
					e.printStackTrace();
					saidaComErro(e);
				}
			}
		});

		try {
			ListenerDeEventosNativos.iniciar();
			iniciarConfiguracoes();
			Clicador clicador = new Clicador(robo, buscadorDaCheckboxDaLinhaSelecionada);
			ListenerDeEventosNativos
					.addNativeKeyListener(new ProcessadorDeEventosNativos(clicador::clicarNaCheckbox, () -> {
						SwingUtilities.invokeLater(() -> tela.repaint());
					}));
		} catch (Exception e1) {
			e1.printStackTrace();
			saidaComErro(e1);
		}
	}

	/** Altere as configurações para corresponder as suas necessidades. */
	private static void iniciarConfiguracoes() throws Exception {
		robo = new Robot();
		checkBoxImage = ImageIO.read(new File("src/images/partedecheckbox.png"));
		BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada = new BuscadorDeLinhaSelecionada(new Color(255, 150, 50),
				5, 5);
		Rectangle areaDaSelecao = new Rectangle(674, 318, 103, 492);
		buscadorDaCheckboxDaLinhaSelecionada = new BuscadorDaCheckboxDaLinhaSelecionada(checkBoxImage,
				buscadorDeLinhaSelecionada, areaDaSelecao, 365, 400);
	}

	private static void saidaComErro(Exception e) throws HeadlessException {
		JOptionPane.showMessageDialog(null, e);
		System.exit(1);
	}

	@SuppressWarnings("serial")
	private static class Tela extends JFrame {

		Tela() {
			super("Clicador em Checkbox de linha Selecionada");
			System.out.println("creating instance");
			setSize(230, 500);
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			add(new Painel());
			setAlwaysOnTop(true);
			setVisible(true);
		}
	}

	@SuppressWarnings("serial")
	private static class Painel extends JPanel {
		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.setColor(Color.DARK_GRAY);
			g.fillRect(0, 0, getWidth(), getHeight());

			BufferedImage areaDaSelecao = buscadorDaCheckboxDaLinhaSelecionada.areaDaSelecaoBuscada.get();
			if (areaDaSelecao != null) {
				g.drawImage(areaDaSelecao, 20, 20, null);
				BufferedImage areaDaCheckbox = buscadorDaCheckboxDaLinhaSelecionada.areaComCheckboxBuscada.get();
				if (areaDaCheckbox != null) {
					g.drawImage(areaDaCheckbox, areaDaSelecao.getWidth() + 30, 20, null);
					g.drawImage(checkBoxImage, areaDaSelecao.getWidth() + 30, areaDaCheckbox.getHeight() + 30, null);
				}
			}
		}

	}

}

Clicador:

package main;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;

public class Clicador {

	private Robot robo;
	private BuscadorDaCheckboxDaLinhaSelecionada buscadorDaCheckboxDaLinhaSelecionada;

	public Clicador(Robot robo, BuscadorDaCheckboxDaLinhaSelecionada buscadorDaCheckboxDaLinhaSelecionada) {
		this.robo = robo;
		this.buscadorDaCheckboxDaLinhaSelecionada = buscadorDaCheckboxDaLinhaSelecionada;
	}

	/**
	 * Retorna true apenas se encontrou e clicou na Checkbox, false caso contrário.
	 */
	public boolean clicarNaCheckbox() {
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Rectangle boundsDaCheckboxEncontrada = buscadorDaCheckboxDaLinhaSelecionada.buscarCheckboxDaLinhaSelecionada(
				robo.createScreenCapture(new Rectangle(0, 0, screenSize.width, screenSize.height)));
		System.out.println(boundsDaCheckboxEncontrada);
		if (boundsDaCheckboxEncontrada != null) {
			int centroDaCheckBox_X = boundsDaCheckboxEncontrada.x + (boundsDaCheckboxEncontrada.width / 2);
			int centroDaCheckBox_Y = boundsDaCheckboxEncontrada.y + (boundsDaCheckboxEncontrada.height / 2);
			clicar(centroDaCheckBox_X, centroDaCheckBox_Y);
			System.out.println("Clicou na Checkbox - x: " + centroDaCheckBox_X + ", y: " + centroDaCheckBox_Y);
			return true;
		}
		return false;
	}

	/** Clica na posição x e y passadas. */
	private void clicar(int x, int y) {
		robo.mouseMove(x, y);
		robo.mousePress(InputEvent.BUTTON1_DOWN_MASK);
		robo.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
	}
}

Buscador da Linha Selecionada pelo Ctrl+F:

package main;

import java.awt.Color;
import java.awt.image.BufferedImage;

public class BuscadorDeLinhaSelecionada {

	private Color corDaSelecao;

	private int margemSuperiorAdicionada; // valor em pixels
	private int margemInferiorAdicionada; // valor em pixels

	public BuscadorDeLinhaSelecionada(Color corDaSelecao, int margemSuperiorAdicionada, int margemInferiorAdicionada) {
		this.corDaSelecao = corDaSelecao;
		this.margemSuperiorAdicionada = margemSuperiorAdicionada;
		this.margemInferiorAdicionada = margemInferiorAdicionada;
	}

	public LinhaDaSelecao encontrarInicioEFimDaLinhaSelecionada(BufferedImage areaDaSelecaoScreenshot, int margemY) {
		LinhaDaSelecao linha = encontrarInicioEFim(areaDaSelecaoScreenshot, corDaSelecao, margemY);
		if (linha == null)
			return null;
		System.out.println("inicioY: " + linha.inicioY + " / linha.fimY: " + linha.fimY);
		linha.inicioY = linha.inicioY - margemSuperiorAdicionada;
		linha.fimY = linha.fimY + margemInferiorAdicionada;
		System.out.println("inicioY: " + linha.inicioY + " / linha.fimY: " + linha.fimY);
		return linha;
	}

	private LinhaDaSelecao encontrarInicioEFim(BufferedImage img, Color cor, int margemY) {
		boolean encontrou = false;
		LinhaDaSelecao linhaDaSelecao = new LinhaDaSelecao();
		linhaDaSelecao.inicioY = Integer.MAX_VALUE;
		linhaDaSelecao.fimY = Integer.MIN_VALUE;
		for (int x = 0; x < img.getWidth(); x++) {
			for (int y = 0; y < img.getHeight(); y++) {
				if (new Color(img.getRGB(x, y)).equals(corDaSelecao)) {
					int posicaoYRealDoPixel = y + margemY;
					if (linhaDaSelecao.inicioY > posicaoYRealDoPixel) {
						encontrou = true;
						linhaDaSelecao.inicioY = posicaoYRealDoPixel;
					}
					if (linhaDaSelecao.fimY < posicaoYRealDoPixel) {
						encontrou = true;
						linhaDaSelecao.fimY = posicaoYRealDoPixel;
					}
				}
			}
		}
		return (encontrou) ? linhaDaSelecao : null;
	}

	public static class LinhaDaSelecao {
		public int inicioY;
		public int fimY;
	}
}

Buscador de uma Imagem que está também dentro de outra Imagem (talvez a classe mais reutilizável!):

package main;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;

public class BuscadorDeImagemDentroDeImagem {

	/**
	 * Busca a 'imagemFilho' dentro da 'imagemPai' retornando um {@link Rectangle}
	 * com a informação (x, y, width e height) de onde ela foi encontrada na
	 * 'imagemPai'; ou retorna null caso não a encontre.
	 */
	public static Rectangle buscarFilho(BufferedImage imagemPai, BufferedImage imagemFilho) {
		for (int x = 0; x < imagemPai.getWidth(); x++) {
			for (int y = 0; y < imagemPai.getHeight(); y++) {
				if (contemFilho(imagemPai, imagemFilho, x, y)) {
					return new Rectangle(x, y, imagemFilho.getWidth(), imagemFilho.getHeight());
				}
			}
		}
		return null;
	}

	/**
	 * Retorna true apenas se a 'imagemFilho' for encontrada na 'imagemPai' na
	 * posição 'offsetX' e 'offsetY' passadas; retorna false caso contrário.
	 */
	public static boolean contemFilho(BufferedImage imagemPai, BufferedImage imagemFilho, int offsetX, int offsetY) {
		if (!filhoCabeDentroDoPai(imagemPai, imagemFilho, offsetX, offsetY)) {
			return false; // não contém o filho se ele não cabe dentro do pai
		}
		for (int x = 0; x < imagemFilho.getWidth(); x++) {
			for (int y = 0; y < imagemFilho.getHeight(); y++) {
				if (imagemPai.getRGB(offsetX + x, offsetY + y) != imagemFilho.getRGB(x, y)) {
					return false;
				}
			}
		}
		return true;
	}

	private static boolean filhoCabeDentroDoPai(BufferedImage imagemPai, BufferedImage imagemFilho, int offsetX,
			int offsetY) {
		if ((offsetX + imagemFilho.getWidth()) > imagemPai.getWidth()) {
			return false;
		}
		if ((offsetY + imagemFilho.getHeight()) > imagemPai.getWidth()) {
			return false;
		}
		return true;
	}

}

Buscador da Checkbox que será clicada:

package main;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import main.BuscadorDeLinhaSelecionada.LinhaDaSelecao;

public class BuscadorDaCheckboxDaLinhaSelecionada {

	private BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada;

	private Rectangle areaDaSelecao;
	private int bordaEsquerdaDaAreaDeCheckbox;
	private int bordaDireitaDaAreaDeCheckbox;

	private BufferedImage imagemDaCheckbox;

	/** Não altere o valor desta property. */
	public final ObjectProperty<BufferedImage> areaComCheckboxBuscada = new SimpleObjectProperty<>();
	/** Não altere o valor desta property. */
	public final ObjectProperty<BufferedImage> areaDaSelecaoBuscada = new SimpleObjectProperty<>();

	public BuscadorDaCheckboxDaLinhaSelecionada(BufferedImage imagemDaCheckbox,
			BuscadorDeLinhaSelecionada buscadorDeLinhaSelecionada, Rectangle areaDaSelecao,
			int bordaEsquerdaDaAreaDeCheckbox, int bordaDireitaDaAreaDeCheckbox) {
		this.imagemDaCheckbox = imagemDaCheckbox;
		this.buscadorDeLinhaSelecionada = buscadorDeLinhaSelecionada;
		this.areaDaSelecao = areaDaSelecao;
		this.bordaEsquerdaDaAreaDeCheckbox = bordaEsquerdaDaAreaDeCheckbox;
		this.bordaDireitaDaAreaDeCheckbox = bordaDireitaDaAreaDeCheckbox;
	}

	/**
	 * Recebe um screenshot de toda a tela, e retorna um Rectangle com as bouds do
	 * checkbox a ser clicado, ou retorna null caso não tenha encontrado ele ou a
	 * linha Selecionada.
	 */
	public Rectangle buscarCheckboxDaLinhaSelecionada(BufferedImage screenshot) {
		areaDaSelecaoBuscada.set(
				screenshot.getSubimage(areaDaSelecao.x, areaDaSelecao.y, areaDaSelecao.width, areaDaSelecao.height));
		LinhaDaSelecao linhaSelecionada = buscadorDeLinhaSelecionada
				.encontrarInicioEFimDaLinhaSelecionada(areaDaSelecaoBuscada.get(), areaDaSelecao.y);
		if (linhaSelecionada != null) {
			int width = bordaDireitaDaAreaDeCheckbox - bordaEsquerdaDaAreaDeCheckbox;
			int height = linhaSelecionada.fimY - linhaSelecionada.inicioY;
			Rectangle boundsDaAreaComCheckboxBuscada = new Rectangle(bordaEsquerdaDaAreaDeCheckbox,
					linhaSelecionada.inicioY, width, height);
			System.out.println("boundsDaAreaComCheckboxBuscada: " + boundsDaAreaComCheckboxBuscada);
			areaComCheckboxBuscada
					.set(screenshot.getSubimage(boundsDaAreaComCheckboxBuscada.x, boundsDaAreaComCheckboxBuscada.y,
							boundsDaAreaComCheckboxBuscada.width, boundsDaAreaComCheckboxBuscada.height));
			Rectangle boundsDaCheckbox = BuscadorDeImagemDentroDeImagem.buscarFilho(areaComCheckboxBuscada.get(),
					imagemDaCheckbox);
			if (boundsDaCheckbox != null) {
				boundsDaCheckbox.x += boundsDaAreaComCheckboxBuscada.x;
				boundsDaCheckbox.y += boundsDaAreaComCheckboxBuscada.y;
			}
			System.out.println("boundsDaCheckbox: " + boundsDaCheckbox);
			return boundsDaCheckbox;
		}

		return null;
	}

}

Classe que consome o JNativeHook:

package main.listener;

import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

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

public class ListenerDeEventosNativos {

	public static void iniciar() throws NativeHookException {
		removerLogDoJNativeHook();
		registrarONativeHook();
	}

	private static void registrarONativeHook() throws NativeHookException {
		try {
			GlobalScreen.registerNativeHook();

		} catch (NativeHookException ex) {
			System.err.println("There was a problem registering the native hook.");
			throw ex;
		}
	}

	private static void removerLogDoJNativeHook() {
		// Clear previous logging configurations.
		LogManager.getLogManager().reset();

		// Get the logger for "org.jnativehook" and set the level to off.
		Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
		logger.setLevel(Level.OFF);
	}

	public static void addNativeKeyListener(NativeKeyListener listener) {
		// Construct the example object and initialze native hook.
		GlobalScreen.addNativeKeyListener(listener);
	}

}

Classe que processa quando “Enter” é teclado:

package main.listener;

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

public class ProcessadorDeEventosNativos implements NativeKeyListener {

	/**
	 * Esses algoritmos serão executados toda vez que a Tecla ENTER for pressionada.
	 */
	private Runnable[] algoritmosParaExecutar;

	/**
	 * Os 'algoritmosParaExecutar' serão executado toda vez que a Tecla ENTER for
	 * pressionada.
	 */
	public ProcessadorDeEventosNativos(Runnable... algoritmosParaExecutar) {
		this.algoritmosParaExecutar = algoritmosParaExecutar;
	}

	@Override
	public void nativeKeyPressed(NativeKeyEvent e) {
		// System.out.println(arg0.getKeyChar());
		if (e.getKeyCode() == NativeKeyEvent.VC_ENTER) {
			System.out.println("Tecla ENTER pressionada!");
			for (Runnable algoritmo : algoritmosParaExecutar) {
				if (algoritmo != null) {
					System.out.println(algoritmo);
					algoritmo.run();
				}
			}
		}
	}

	@Override
	public void nativeKeyReleased(NativeKeyEvent arg0) {
	}

	@Override
	public void nativeKeyTyped(NativeKeyEvent arg0) {
	}

}

Veja que esta última classe usa um NativeKeyEvent.VC_ENTER, talvez você vá precisar usar também o NativeKeyEvent.VC_KP_ENTER, (não li a documentação para saber a diferença).

Bem, eu testei aqui e funciou muito bem. Sempre que você teclar Enter a Janela do programa mostra o que ele capturou da Tela, que é a Área-da-Seleção (onde os Números estão, e onde aparece a Seleção laranja do Ctrl+F), Caso a Seleção Laranja tenha sido detectada aparece também a “areaComCheckboxBuscada”, que é a área da Tela em que o programa acredita que estará a Checkbox correta a ser Clicada.
Essa Janela também mostrará a imagem que você criou para ser a partedecheckbox.png.

O programa clica na Checkbox encontrada (se ele encontrou) sempre que você Teclar Enter. Ele não vai desmarcar a Checkbox, porque os pixels dela vão estar diferentes quando ela estiver com o visto dentro.

1 curtida

A respeito do que eu falei da versão do JNativeHook:

  • Se você usar a mesma versão que eu, provavelmente não terá que mexer no código (quase certo);
  • Se você usar a versão mais recente que houver, talvez precise mexer no código se a forma de usar o JNativeHook tiver mudado, mas a vantagem é que a última versão sempre deve ser mas segura contra exploits, pois a biblioteca já deve ter sido alterada para inutilizar os exploits já conhecidos.

JNativeHook é open-source e , acho que isso aumenta segurança: muita gente olhando o código e avisando sobre bugs e problemas de segurança.

1 curtida

Boa noite, Douglas.

Acredito que vai atender as minhas expectativas e colaborar muito quando estiver executando, vou te agradecer a toda hora a cada post aqui viu rss, vai cansar de ler, mas não vou me cansar de agradecer, muito obrigada mesmo pela atenção e pelo programa.
Já fiz o download das imagens das imagens para configuração, assim que conseguir testar te aviso como ta rolando aqui, pode demorar um pouco porque vou depender dos acessos, mas vou verificar se consigo acesso externo pra isso. :blush:

Entendido Douglas, eu vou ver se dou conta de realizar os ajustes necessários, e pela segurança optar por algo mais recente então como sugeriu.
Obrigadassa por todas as informações, esclarecimentos e pelo programa, você é demais, eu fico admirada com esses códigos, e o que podem fazer. :smiley:

Me da uma ajuda por favor quanto as imagens por conter o nome e link da empresa oculta pra mim por favor, acredito que não de problemas, mas melhor evitar, já realizei o download.