Dúvida para Implementar Ideia

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.

Na testagem do programa, preste atenção no seguinte:

  • Se o programa fechar sozinho sem mostrar nada, provavelmente o que ocorreu é que ele lançou uma Exception que não foi tratada. Se isso acontecer após pressionar Enter, então a Exception deve ter ocorrido dentro do método ProcessadorDeEventosNativos#nativeKeyPressed(NativeKeyEvent e), aí você pode colocar um try/catch lá dentro que captura a Exception e exibe na Tela.
  • Se você testar o programa na IDE ela já deve mostrar qualquer Exception, mas se testar com o JAR exportado, talvez só apareça essas Exceptions não capturadas se rodar o programa pelo console.
  • Fique atenta ao que a Janela do programa exibe:
    1) Ao iniciar deve ser tudo cinza;
    2) Ao teclar Enter deve capturar e mostrar uma parte da Tela, que é a areaDaSelecao configurada, e que deve conter os números que podem ser selecionados pelo Ctrl+F;
    3) Se dentro dessa área capturada houver algum daqueles pixels laranja que são colocados pela Seleção do Ctrl+F, exatamente daquela cor, então a Janelinha deve mostrar também a área em que ela acredita que está a Checkbox.

Portanto, se “Área-da-Checkbox” não aparecer na Janelinha, significa que o programa não encontrou nenhum pixel laranja (exatamente daquela cor: R=225, G=150, B=50) dentro da “Área-da-Seleção”.

Se a “Área-da-Checkbox” aparecer na Janelinha mas não mostrar a checkbox a ser clicada por inteiro, ou mostrar partes de outras checkbox junto, você precisará mexer nas configurações:

  • margemInferiorAdicionada
  • margemSuperiorAdicionada
  • bordaEsquerdaDaAreaDeCheckbox
  • bordaDireitaDaAreaDeCheckbox

Se a checkbox a ser clicada aparecer por inteiro mas o programa não clicar nela, as causas podem ser:

  • O robô não conseguiu mover o cursor e clicar, mas eu acho que isso lançaria uma Exception e fecharia o programa.
  • Causa mais provável: a partedecheckbox.png não foi encontrada (não deu “match”) dentro da Área-de-Checkbox, se esse é o caso o console deve mostrar "boudsDaCheckbox: null" devido a isso:

Aí vai ser preciso gerar uma nova imagem partedecheckbox.png, talvez com um recorte menor para aumentar as chances de “match”.

Se der problema, me envia um recorte da tela com a Janelinha do programa.

1 curtida

Olá, Douglas.

Tudo bem, eu não consegui ainda permissão para testar na empresa :frowning:
Estou esperando que alguém la me ajude, mas é no tempo deles, vou tentar executar aqui conforme vem me explicando.
Uma duvida e talvez muito boba, eu consigo tornar o programa um executável ou algo portátil, acho que dessa forma eles me dariam mais atenção, acredito que não vão avaliar os códigos. Assim acredito que me deixariam executar, liberaram o Mouse Recorder Pro la, acredito que a sua implementação é meio que com a mesma função.
De qualquer forma assim que avançar aqui te aviso como rodou tudo, muito obrigada por toda ajuda. :blush:

Sim, dá pra fazer qualquer um dos dois. Eu acho que o melhor é ter o JAR exportado, acho que é o “mais portátil” possível, pois é simplesmente:

  • um arquivo .jar;
  • uma pasta “irmã” do Jar (fica dentro do mesmo diretório do Jar, um do lado do outro) chamada “images”;
  • e dentro dessa pasta “images” temos a “partedecheckbox.png”

Pra rodar, é só dar dois clicks no Jar. Também dá pra fazer um atalho dele, por praticidade.

Tem como gerar instalador também.

1 curtida

Você pode pesquisar por “exportar JAR” no NetBeans, no Eclipse é:

Clicar com botão direito no Projeto -> Export… -> Runnable Jar File -> (escolher a classe Main no assistente e a pasta de destino, dando um nome pro Jar) -> Finish.

Eu acho que o JAR roda em qualquer Sistema Operaciona com uma JVM que o aceite (aceite os recursos utilizados por ele e a versão do Java dele), deve ser aí que entra o “escreva uma vez e rode em qualquer lugar”.

Vou estar esperando pra saber o que aconteceu aí :slight_smile:

1 curtida

Ótimo então, vou tentar essa opção.
Obrigada mais vez. :smiley:

“images” é uma pasta dentro da pasta “src”, só isso. Dentro da pasta “images” tem a imagem partedecheckbox.png.

Não vejo porque o projeto teria uma estrutura diferente no NetBeans, no máximo, o NetBeans colocaria o import do JNativeHook em um lugar diferente.

Se o programa não encontrar a imagem na pasta e com o nome que está no código, lança uma Exception. Se as classes forem colocadas em packages errados, nem compila.

Você precisa prestar atenção nisso: As Configurações que falei, incluíndo a imagem partedecheckbox.png precisam ser alteradas/feitas sob-medida para o computador que vai rodar o programa (resolução da tela, sistema operacional, navegador). Tirando um PrinScreen da Tela desse computador com o sistema-web aberto do jeito que você me mandou aquelas imagens já deve ser o suficiente para você conseguir configurar para esse Computador.

Você tem que saber em qual computador irá testar o programa lá na empresa, e preparar as Configurações para que funcionem nesse computador.

Acho que um próximo passo nesse programa, seria colocar as configurações em um arquivo .txt que o programa iria ler e carregar; aí seria só editar esse arquivo .txt para alterar as configurações, sem ter que editar o código fonte e sem ter que re-exportar o Jar.

Posso te mandar a imagem partedecheckbox.png recortada de acordo com os printscreens que você me mandou, entretanto, é importante que você aprenda a criar essa imagem por si só, pra refazer sempre que necessário:

Para criar essa imagem, vá no Computador que rodará o programa, e faça o seguinte:

  1. Abra a Tela do Sistema-Web (como nas imagens que você me mandou);
  2. Tecle “PrintScreen”;
  3. Abra o Paint, dê Ctrl+V, a imagem deve aparecer no Paint;
  4. Dê Zoom no Paint sobre uma das Checkbox da imagem;
  5. Use a Ferramenta de Seleção Retangular do Paint image e selecione o interior da Checkbox, ou uma parte desse interior (anteriormente eu te enviei uma imagem "recortar partedecheckbox.png" que explica sobre o recorte do interior da checkbox);
  6. Após criar a Seleção Retangular, clique em Cortar image;
  7. Vá em “Salvar Como…” -> “Imagem PNG” -> salve com o nome partedecheckbox.png (tudo em letras minúsculas), dentro da pasta “images” do programa.

Se não ficou claro, veja aqui:


Vou te mandar no e-mail o projeto como tenho aqui.

:slight_smile:

1 curtida

Seu serviço de e-mail rejeitou meu e-mail (aparentemente por causa dos anexos zip):

JNativeHook-2.0.3.zip (611,9 KB)
ProjClicadorDeCheckbox.zip (20,7 KB)
ClicadorDeCheckbox.zip (196,0 KB)

Vi aqui que o GUJ permite anexar arquivos, são esses aí em cima.

Tem o programa exportado em JAR, eu percebi depois de exportar que é necessário que a pasta “images” fique dentro da pasta “src” como está no anexo, devido ao caminho relativo que eu coloquei no código: “src/images/partedecheckbox.png”.

Também estou enviando o Projeto do Eclipse, veja que precisa do JNativeHook na minha versão (mais antiga) para rodá-lo, colocando-o na pasta:

C:/Java/JNativeHook-2.0.3/JNativeHook/jar/jnativehook-2.0.3.jar (caminho escrito no arquivo .classpath do projeto).

Se você quiser a versão mais nova do JNativeHook, precisará baixá-la e importá-la pro projeto, e então usá-la.

Veja se consegue fazê-lo rodar aí :slight_smile:

1 curtida

Muito obrigada Douglas, e me desculpe por todo trabalho, preciso estudar bem mais sobre o assunto, pra mim ainda é tudo novo, e venho tentando aprender um pouquinho pela internet dentro do tempo que tenho um espacinho, mas vou procurar fazer um curso para tornar as coisas mais claras pra mim, tenho muito a aprender ainda. :open_mouth:
Obrigada de verdade pela paciência e ajuda quanto a tudo.

Oxe mais que estranho o e-mail ter rejeitado.
De qualquer forma, download realizado aqui, vou levar para empresa e verificar se consigo testar, depois vou ajustando conforme comentou, mas acredito que vai rodar lindamente. :smiley:
Muito mas muito obrigada mesmo.

De nada, vou ficar aguardando pra saber se deu certo :slight_smile: