Transformando Strings em series de KeyCodes

Tou fazendo umas adaptacoes no Selenium (pra que ele possa fazer upload de arquivos em browsers que nao o Firefox), e esbarrei num probleminha meio chato: na java.awt.Robot tem um metodo keyPress(int keycode) que recebe aqueles KeyEvent.VK_*.

O problema eh que eu quero digitar uma String inteira, com o nome do arquivo. Eu teria que transformar algo como “C:\foo.jpg” em:

int[] { VK_C, VK_COLON, VK_BACK_SLASH, VK_F, VK_O, VK_O, VK_PERIOD, VK_J, VK_P, VK_G }

…o que parece relativamente simples, ate vc ver que nao tem nada na API que faca isso (e o mais proximo, Character.getNumericValue e equivalentes, nao te dao um keycode pra maioria das coisas nao-alfabeticas, como ‘:’ e ‘.’).

Fiquei travado nisso. Alguem tem alguma ideia?

O Danilo Sato eh um genio:

public static void main(String[] args) { char[] test = "C:\\code\\selenium-rc\\native_upload\\test-type.jpg".toCharArray(); for (int i = 0; i < test.length; i++) { System.out.print(AWTKeyStroke.getAWTKeyStroke(test[i]).getKeyChar()); } }

Uia o.O

Er, retiro o que eu disse. O Danilo ainda eh esperto - bem mais que a galera da Sun, pelo jeito. A AWTKeyStroke nao faz bem isso que eu quero:

public static AWTKeyStroke getAWTKeyStroke(char keyChar) { return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); }

Voila, VK_UNDEFINED. Maldicao!

Se alguem tiver outra ideia, fico devendo uma breja.

http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/KeyEvent.html#VK_T

Também não sei se a sequência é seguida para os caracteres não-alfabéticos, mas não dá pra criar uma classe utilitária com um bloco estático mais ou menos assim?

Map&lt;Char, Int&gt; keysMap = new HashMap&lt;Char, Int&gt;();
for(int i = 0; i &lt; 256; ++i) keysMap.put(i, i);

E ter nessa classe um método estático do tipo

public static int getKeyCode(char key) {
   return keysMap.get(key);
}

Talvez eu não tenha entendido direito seu problema…

…foi o que eu acabei fazendo, mas mesmo assim dei de cara com outra parede:

int colon = KeyEvent.VK_COLON; // = 513 robot.keyPress(colon);

resulta em:

java.lang.IllegalArgumentException: Invalid key code at sun.awt.windows.WRobotPeer.keyPress(Native Method) at java.awt.Robot.keyPress(Unknown Source) at org.openqa.selenium.server.SeleniumDriverResourceHandler.doCommand(Se leniumDriverResourceHandler.java:464)

Pelo que imagino, você teria de fazer algo parecido com o seguinte:

keyPress (VK_SHIFT)
keyPress(VK_SEMICOLON)
keyRelease(VK_SEMICOLON)
keyRelease(VK_SHIFT)

já que a tecla “:” não existe no teclado (só “;” e você precisa usar o Shift para acessar o “:”. )
Estou supondo que você esteja usando o teclado americano; não sei se o inglês é tão diferente assim do americano.
(Eu sei que o teclado francês é “AZERTY” em vez de “QWERTY” e outras coisas mais estranhas).
(O teclado ABNT ou brasileiro tem um monte de teclas fora do lugar, mas o “:” continua sobre o “;”. )

EDIT - Olhei e é sutilmente diferente quanto a alguns caracteres.

Realmente, existem algumas dessas barreiras… Alguns caracteres de pontuação ficam em intervalos diferentes…
O dois pontos e o ponto e vírgula ficam “455” unidades a mais que o código do caracter… Tentei verificar com mais caracteres, mas nada…

Por exemplo, o VK_COLON é ( ( ( int ) ‘:’ ) + 455 ) == 513

Fiquei uma meia hora tentando pensar em algo, mas não tive nenhum idéia diferente das que vocês já postaram…

O mais perto que cheguei…

Class c = KeyEvent.class;
Field[] f = c.getFields();
HashMap< String, Integer > mapa = new HashMap< String, Integer >();

for ( int i = 0; i < f.length; i++ ) {

    if ( f [ i ].getType() == int.class ) {
        try {
            mapa.put( f[ i ].getName(), new Integer( String.valueOf( f[ i ].get( null ) ) ) );
        } catch ( IllegalArgumentException ex ) {
            ex.printStackTrace();
        } catch ( IllegalAccessException ex ) {
            ex.printStackTrace();
        }
    }

}

String entrada = "Teste";
char[] caracteres = entrada.toCharArray();

for ( int i = 0; i < caracteres.length; i++ )
    System.out.println( mapa.get( "VK_" + String.valueOf( caracteres[ i ] ).toUpperCase() ) );

Mas faltam as pontuações, etc…

Com isso dá pra ver o código de todas as constantes cujo nome começa com VK_ …

import java.awt.AWTKeyStroke;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



/**
 * @author Cassio Marques 
 *
 */
public class Bla {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Map&lt;String, Integer&gt; keysMap = new HashMap&lt;String, Integer&gt;();
		Class klass = KeyEvent.class;		
		Field[] campos = klass.getDeclaredFields();
		Pattern pattern = Pattern.compile(&quot;^VK_&quot;);
		Matcher matcher;
		for(Field f : campos) {
			try {				
				if(!f.isAccessible()) f.setAccessible(true);
				matcher = pattern.matcher(f.getName());
				if(matcher.find()) {					
					System.out.println(f.getName() + &quot; ==&gt; &quot; + f.getInt(null));
					keysMap.put(f.getName(), f.getInt(null));
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}

	}

}

Valeu, galera. A solucao final acabou meio como uma mistura do que o daviduzatto e o cassio sugeriram.

Ah, e thingol - matou a pau. O lance eh o mesmo pra (, ) e todos os caracteres do genero. Ainda nao testei o #, que no meu Mac eh feito com Alt+3, mas como # nao ocorre em nenhum dos arquivos que eu tenho que usar pra testar aqui, nao tem la tanto problema.

Disponha :smiley:

Caraca isso me lembra quando brincavamos de fazer jogo em pascal la por volta de 1996 e tinhamos que tratar as interrupções do teclado porquê o keycode tinha algumas bizarrices tipos essas …