Ver la versión completa : Pulsación de teclas ¿doble? en SDL
Puck2099
14/10/2005, 07:15
Hola,
Estoy portando mi Samurai del GPSDK a SDL y me he encontrado con el problema de que, cuando pulso algún control (el pad o un botón), la GP32 lo interpreta como si lo hubiera pulsado dos veces.
Probándolo compilado para Linux funciona perfectamente, pero en la GP32 no entiendo porque no va bien. No se trata de un problema de "rebotes", pues si hago una pausa de varios segundos desde la primera vez que pulso el botón, da igual, pues sigue reaacionando como si lo hubiera pulsado dos veces.
El código que utilizo para responder a las pulsaciones es el siguiente:
SDL_Event event;
while (SDL_PollEvent (&event)) {
if (event.type == SDL_QUIT) saltar_menu = 1;
}
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_UP] && cursor_menu >1) {
cursor_menu--;
pausar = 1;
}
if (keys[SDLK_DOWN] && cursor_menu <4) {
cursor_menu++;
pausar = 1;
}
Ese pausar es para hacer una pequeña pausa cada vez que se pulsa un botón para que no se mueva demasiado deprisa el cursor.
Saludos
Puck2099
14/10/2005, 19:52
Venga, ¿ninguna idea? [wei3]
no veo como haces la pausa, y no entiendo que quieres decir con que te lo detecta como 2 pulsaciones :(
aiken
A lo mejor es que el polling lo hace muy rapido, a mi me paso cuando hize una rutina para un teclado hexadecimal... tenia unos cuantos milisengundos entre pasada y pasada...
Tengo poca idea de programación de ese tipo, pero ¿no podria ser la pulsación en si y la "despulsación"?
Puck2099
14/10/2005, 21:50
no veo como haces la pausa, y no entiendo que quieres decir con que te lo detecta como 2 pulsaciones :(
aiken
La pausa la hago con un:
if (pausa) SDL_Delay(150);
En cuanto a lo de las 2 pulsaciones, te pongo un ejemplo: hay un menú de opciones colocadas de forma vertical con un cursor que marca la opción seleccionada. Pues bien, si pulsas el pad hacia abajo para que baje el cursor a la opción inferior, éste baja dos posiciones. ¿Me explico ahora? :)
Saludos
Puck2099
14/10/2005, 21:52
A lo mejor es que el polling lo hace muy rapido, a mi me paso cuando hize una rutina para un teclado hexadecimal... tenia unos cuantos milisengundos entre pasada y pasada...
No creo que sea eso, pues si te fijas cada vez que se pulsa un botón se hace una pausa. Al principio probé con pausas de 150 ms para evitar lo que dices, que el polling se haga demasiado deprisa, pero visto que no funcionaba lo aumenté hasta 3 segundos para descartar que fuera por eso y efectivamente seguía haciendo las "2 pulsaciones", la segunda 3 segundos después de la primera.
Saludos
anibarro
14/10/2005, 22:14
Puck2099 intenta poner la pausa dentro de los ifs como "if (keys[SDLK_UP] && cursor_menu >1)", en vez de poner "pausar = 1;", mete ahi el SDL_Delay(150); a ver si funciona, y si funciona pues vamos viendo donde esta el fallo ^^
ZeNiTRaM
15/10/2005, 00:52
Prueba haciendo que la primera vez que la tecla se pulse, poniendo alguna variable para que no se vuelva a detectar la pulsacion hasta que se haya detectado que el boton se haya soltado de por medio..
una cosa si paurar=1 esta dentro de los dos ifs porque no poner uno solo al final del 2º if??
para el caso lo mismo, no??
Puck2099
15/10/2005, 02:49
una cosa si paurar=1 esta dentro de los dos ifs porque no poner uno solo al final del 2º if??
para el caso lo mismo, no??
No, porque son acciones excluyentes, si lo pones solo en el segundo if no hace la pausa si se pulsa hacia arriba, solo hacia abajo.
anibarro
15/10/2005, 05:25
¿probaste a meter el delay dentro del if?
Se supone que el "while (SDL_PollEvent (&event))" lo hace hasta que no quedan mas acciones almacenadas en la cola, puede que dependiendo donde pongas las pausas, hagas que se almacenen dos eventos en la cola...la verdad es q no se que puede pasar :shock:
Puck, a priori no se ve error alguno, por eso estoy como tu de desconcertado, pero puede que Tebb tenga razón cuando hace la diferencia entre "pulsar una tecla" y "soltar una tecla", y ya que SDL permite controlar por eventos como tu mismo has hecho controlando el SDL_Quit podrías intentar hacer lo mismo y cambiar el uso de la función SDL_GetKeyState() por un control según el tipo de evento (en este caso pulsar pero no soltar una tecla) en la pulsación de una tecla determinada, algo así como:
/* Estructura event de tipo SDL_Event para los eventos. */
SDL_Event event;
/* Controlamos e inicializamos la cola de eventos. */
while(SDL_PollEvent(&event))
{
/* Controlamos SOLO un tipo de evento que implique
unicamente pulsar una tecla, pero no el soltarla. */
if(event.type==SDL_KEYDOWN)
{
/* Con un switch controlamos el evento SDL_KEYDOWN
según cual sea la tecla pulsada */
switch(event.key.keysym.sym)
{
case SDLK_UP: cursor_menu--; pausar = 1; break; /* Tecla direccional "ARRIBA" */
case SDLK_DOWN: cursor_menu++; pausar = 1; break; /* Tecla direccional "ABAJO" */
}
}
}En el ejemplo que te he puesto ves event.key.keysum.sym que entre sus campos está otra estructura que como seguro sabrás es SDL_KeyboardEvent pero esta a su vez tiene como campo a otra estructura que es SDL_keysym, que es la que nos interesa en este caso, ya que almacena información sobre la tecla presionada (como en este caso sym, el valor definido en SDL para esa tecla, al contrario que el campo scancode que depende del hardware). He dejado las pausas que haces pero no se como de necesarias seran si funciona esto y he optado por un switch por gustos personales, no me gusta ver dos o más if seguidos para controlar lo mismo a menos que estén encadenados, pero cambialos por un par de if si lo prefieres mejor y perdona el exceso de comentarios, pero es otra de mis manías.
P.D: Ten en cuenta que esto no lo he probado en la GP32, así que no se si tampoco funcionará :rolleyes:
Puck2099
15/10/2005, 05:34
¿probaste a meter el delay dentro del if?
Se supone que el "while (SDL_PollEvent (&event))" lo hace hasta que no quedan mas acciones almacenadas en la cola, puede que dependiendo donde pongas las pausas, hagas que se almacenen dos eventos en la cola...la verdad es q no se que puede pasar :shock:
Nada, acabo de probarlo y sigue igual...
Puck2099
15/10/2005, 05:52
Puck, a priori no se ve error alguno, por eso estoy como tu de desconcertado, pero puede que Tebb tenga razón cuando hace la diferencia entre "pulsar una tecla" y "soltar una tecla", y ya que SDL permite controlar por eventos como tu mismo has hecho controlando el SDL_Quit podrías intentar hacer lo mismo y cambiar el uso de la función SDL_GetKeyState() por un control según el tipo de evento (en este caso pulsar pero no soltar una tecla) en la pulsación de una tecla determinada, algo así como:
En el ejemplo que te he puesto ves event.key.keysum.sym que entre sus campos está otra estructura que como seguro sabrás es SDL_KeyboardEvent pero esta a su vez tiene como campo a otra estructura que es SDL_keysym, que es la que nos interesa en este caso, ya que almacena información sobre la tecla presionada (como en este caso sym, el valor definido en SDL para esa tecla, al contrario que el campo scancode que depende del hardware). He dejado las pausas que haces pero no se como de necesarias seran si funciona esto y he optado por un switch por gustos personales, no me gusta ver dos o más if seguidos para controlar lo mismo a menos que estén encadenados, pero cambialos por un par de if si lo prefieres mejor y perdona el exceso de comentarios, pero es otra de mis manías.
P.D: Ten en cuenta que esto no lo he probado en la GP32, así que no se si tampoco funcionará :rolleyes:
Gracias por el ejemplo :)
Si no entiendo mal, lo que pretendemos con ese ejemplo es que solo reconozca la pulsación de la tecla por si el error viene porque también reconocía el dejar de pulsarla, ¿verdad?
El problema, es que de ser así, si dejas apretada una dirección solo se desplazaría el cursor una posición, ¿verdad? Osea, no sería posible que dejando pulsada la dirección recorriera todas las opciones, sino que habría que ir pulsando varias veces, ¿no?
Saludos
El problema, es que de ser así, si dejas apretada una dirección solo se desplazaría el cursor una posición, ¿verdad? Osea, no sería posible que dejando pulsada la dirección recorriera todas las opciones, sino que habría que ir pulsando varias veces, ¿no?De esta forma así debería ser, puesto que al pulsar una tecla se controla que ha ocurrido ese evento pero hasta no pulsar otra o soltar y pulsar otra vez la misma, no debe detectar otro evento. Yo la verdad es que estoy acostumbrado a esta forma en los menus (cuando es con el teclado o en algún juego en una consola) de ir pulsando tantas veces como sea necesaria para ir a donde quiero, pero si deseas que una vez pulsada la tecla ABAJO, por ejemplo, digamos que después de 1 segundo siga hacia abajo puedes probar con state (valores SDL_PRESSED si está pulsado y SDL_RELEASED si has soltado la tecla) el campo que como type pertenece a SDL_KeyboardEvent (y como antes dije parte de la unión llamada SDL_Event) y básicamente nos da la misma info, solo que la guarda de dos formas diferentes (no me preguntes la razón xD).
Así a priori se me ocurre que quizás podrías controlar con un bucle while con la información de state (por distinguir aunque sea solo en el código) y un cierto retardo o usando un contador por ejemplo que si una determinada tecla está pulsada (ABAJO para el ejemplo) un determinado tiempo, 1 segundo por ejemplo como decía antes, entonces se incremente la variable (cursor_menu++) repetidas veces hasta que el bucle controle que sea ha soltado esa tecla. Este sería el metodo chapuzas.
La otra manera, en teoría más correcta y limpia, que también nos la proporciona la librería SDL, es usando una función llamada SDL_EnableKeyRepeat() para activar el uso de repetición de eventos en la pulsación de teclas, no la he usado nunca (por los motivos que te he dicho) pero puede que te sea util para lo que pides. El prototipo de esta función es:
int SDL_EnableKeyRepeat(int delay, int interval);
Donde delay es el tiempo que la tecla debe estar pulsada antes de que se empieze a repetir el evento e interval es el intervalo o velocidad de repetición, que puedes usar los valores (probando) que veas mejor, aunque SDL tiene dos constantes, que son parte del archivo de cabecera SDL_keyboard.h (que no se necesita incluir pues ya lo hace SDL.h), SDL_DEFAULT_REPEAT_DELAY (500 milisegundos) y SDL_DEFAULT_REPEAT_INTERVAL (con valor de 30), para delay e interval respectivamente. Además, si ambos parametros están igualados a 0 puedes desabilitar la repetición de eventos por si te interesa que esto sea así en algún momento.
En la doc de SDL puedes buscar más info supongo sobre el uso de esta función.
EDITO: He corregido un par de errores en el segundo parrafo, que me he saltado la parte que comentaba de usar el campo state por el morro y que ponía pulsar una tecla en vez de soltarla :p
Puck2099
15/10/2005, 07:12
Bueno, siguiendo tu ejemplo ya he conseguido que no se repita la pulsación de la tecla :)
Ahora estoy con el tema del EnableKeyRepeat, pero justo en estos momentos se ha caído el server de libsdl.org y no puedo sacar información sobre la función... :(
Seguiré informando :p
Bueno, siguiendo tu ejemplo ya he conseguido que no se repita la pulsación de la tecla :)
Ahora estoy con el tema del EnableKeyRepeat, pero justo en estos momentos se ha caído el server de libsdl.org y no puedo sacar información sobre la función... :(
Seguiré informando :pMe alegro de que te funcione el ejemplo de paso esto lo tenemos en el foro como un "tip" si sale la misma pregunta :)
Respeto a la web de SDL, a mi me funciona, prueba de nuevo a ver, la documentación oficial de la función SDL_EnableKeyRepeat (http://www.libsdl.org/cgi/docwiki.cgi/SDL_5fEnableKeyRepeat) no es muy extensa, de hecho es básicamente lo que te he dicho salvo que te he puesto cuanto valen las constantes que se mencionan y unos pocos ejemplos (http://www.codase.com/search/call?name=SDL_EnableKeyRepeat) que he encontrado.
Puck2099
15/10/2005, 07:34
Me alegro de que te funcione el ejemplo de paso esto lo tenemos en el foro como un "tip" si sale la misma pregunta :)
Respeto a la web de SDL, a mi me funciona, prueba de nuevo a ver, la documentación oficial de la función SDL_EnableKeyRepeat (http://www.libsdl.org/cgi/docwiki.cgi/SDL_5fEnableKeyRepeat) no es muy extensa, de hecho es básicamente lo que te he dicho salvo que te he puesto cuanto valen las constantes que se mencionan y unos pocos ejemplos (http://www.codase.com/search/call?name=SDL_EnableKeyRepeat) he encontrado.
Sí, fue terminar de postear y que funcionara otra vez la web :p
Bueno, ya lo tengo funcionando con las repeticiones y todo :)
Primero inicializo la función de las repeticiones:
SDL_EnableKeyRepeat (200, 200);
Y luego ya proceso las pulsaciones dentro del polling de eventos:
while (SDL_PollEvent (&event)) {
if (event.type == SDL_QUIT) saltar_menu = 1;
if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_UP && cursor_menu >1) {
cursor_menu--;
}
if (event.key.keysym.sym == SDLK_DOWN && cursor_menu <4) {
cursor_menu++;
}
if (event.key.keysym.sym == SDLK_LCTRL) {
switch (cursor_menu) {
case 1:
if (idioma == 0) idioma =1;
else if (idioma == 1) idioma =0;
break;
case 2:
if (jugadores == 1) jugadores =2;
else if (jugadores == 2) jugadores =1;
break;
case 3:
if (tiempo == 3) tiempo =5;
else if (tiempo == 5) tiempo =3;
break;
case 4:
if (dificultad == 0) dificultad =1;
else if (dificultad == 1) dificultad =0;
break;
}
}
if (event.key.keysym.sym == SDLK_RETURN) {
saltar_menu = 1;
}
}
}
Lo raro es que cuando dejo pulsado el botón A (LCTRL) no hace repeticiones, pero bueno, tampoco es que lo necesite :)
Muchas gracias de nuevo por la ayuda tío :brindis:
Sí, fue terminar de postear y que funcionara otra vez la web :p
Bueno, ya lo tengo funcionando con las repeticiones y todo :)Ole, cojonudo :brindis:
Lo raro es que cuando dejo pulsado el botón A (LCTRL) no hace repeticiones, pero bueno, tampoco es que lo necesite :)Eso si que es misterioso, ¿pasa con el B también? :confused:
Muchas gracias de nuevo por la ayuda tío :brindis:De nada, me alegra haberte podido ayudar en algo :brindis:
Puck2099
15/10/2005, 08:11
Agh, ¡qué rabia!, me acabo de dar cuenta de que así no funcionan las diagonales :llorosa:
Agh, ¡qué rabia!, me acabo de dar cuenta de que así no funcionan las diagonales :llorosa:La leche, si no es una cosa es otra (o como decía uno, un problema no se resuelve, solo desaparece y se crea otro problema) xDD
No estoy seguro como funcionará los controles con SDL en la GP32, pero claro, puede ser porque la diagonal en un teclado es una combinación de dos teclas de dos direcciones distintas. No se si digo una tontería, pero has ¿probado a controlar la pulsación de dos teclas direccionales a la vez o en la GP32 no se puede por algún motivo? Aunque creia que estabamos hablando que esto era para un menú clásico, ¿es que es algo distinto el menú (no solo ir arriba, abajo, a la izquierda o a la derecha) o es que lo necesitas para el juego en si?
¿ Porque no dejas de lado la lectura de teclas con la libreria SDL y compruebas las teclas directamente con la función de la GP32, GpKeyGet() ?
Si quieres te paso las funciones de chequeo de teclado que implemente para mi editor para la GP...
http://www.gp32spain.com/archivos.php?tipo=Utilidades&pagina=detalles&numero=577
Un ejemplo:
gettecla = GpKeyGet();
k_arriba = gettecla & 8;
k_abajo = gettecla & 2;
k_izquierda = gettecla & 1;
k_derecha = gettecla & 4;
k_botonR = gettecla & 0x80;
k_botonL = gettecla & 0x10;
k_botonA = gettecla & 0x40;
k_botonB = gettecla & 0x20;
k_start = gettecla & 0x100;
k_select = gettecla & 0x200;
k_escape = k_start & (k_select>>1);
if (k_botonR & k_botonL) printf("has pulsado R y L a la vez");
Y el problema de repeticiones de tecla lo puedes solucionar con una funcion que guarde la tecla anterior, la compare con la actual, y si es la misma poner a cero la variable de la tecla.
Y un contador de ciclos por si quieres poner autorepeticion.
me referia que en vez de esto que habias puesto
SDL_Event event;
while (SDL_PollEvent (&event)) {
if (event.type == SDL_QUIT) saltar_menu = 1;
}
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_UP] && cursor_menu >1) {
cursor_menu--;
pausar = 1;
}
if (keys[SDLK_DOWN] && cursor_menu <4) {
cursor_menu++;
pausar = 1;
}
no era mas facil sacar el pausar=1??
SDL_Event event;
while (SDL_PollEvent (&event)) {
if (event.type == SDL_QUIT) saltar_menu = 1;
}
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_UP] && cursor_menu >1)
cursor_menu--;
if (keys[SDLK_DOWN] && cursor_menu <4)
cursor_menu++;
pausar=1;
Puck2099
15/10/2005, 21:41
La leche, si no es una cosa es otra (o como decía uno, un problema no se resuelve, solo desaparece y se crea otro problema) xDD
No estoy seguro como funcionará los controles con SDL en la GP32, pero claro, puede ser porque la diagonal en un teclado es una combinación de dos teclas de dos direcciones distintas. No se si digo una tontería, pero has ¿probado a controlar la pulsación de dos teclas direccionales a la vez o en la GP32 no se puede por algún motivo? Aunque creia que estabamos hablando que esto era para un menú clásico, ¿es que es algo distinto el menú (no solo ir arriba, abajo, a la izquierda o a la derecha) o es que lo necesitas para el juego en si?
En realidad al principio lo aplicaba para el menú clásico, pero una vez que me funcionaba ya me he puesto a cambiarlo en el juego en sí que tenía el mismo problema de repetición y ahí sí necesitaba las diagonales.
Bueno, finalmente lo he solucionado mediante una chapucilla, y, aunque un poco impreciso, funciona bien. Voy a pegar el código de lo que he hecho, aunque se me está ocurriendo una manera de mejorarlo... :)
EDITO: Ya está, ahora sí que va perfecto y con una precisión cojonuda :) Voy a modificar el código que había pegado aquí abajo con los cambios realizados.
Primero declaro un int pausa como global.
Defino una función donde se moverá al cursor para hacer el código más sencillo:
void control_player (int pos_b[2]) {
Uint8* keys;
keys=SDL_GetKeyState(NULL);
if (keys[SDLK_LEFT] && pos_b[0]>11) {
pos_b[0] = pos_b[0]-27;
pausa = 15;
}
if (keys[SDLK_RIGHT] && pos_b[0]<200) {
pos_b[0] = pos_b[0]+27;
pausa = 15;
}
if (keys[SDLK_UP] && pos_b[1]>11) {
pos_b[1] = pos_b[1]-27;
pausa = 15;
}
if (keys[SDLK_DOWN] && pos_b[1]<200) {
pos_b[1] = pos_b[1]+27;
pausa = 15;
}
}
Así solo hace una pausa si hay alguna tecla pulsada.
Ahora en el bucle del juego:
while (juego) {
while (SDL_PollEvent (&event)) {
if (event.type == SDL_QUIT) juego = 0;
}
if (pausa == 0) {
control_player(pos_b);
}
....
....
if (pausa >0) pausa--;
}
Saludos
Pues, al no ver el codigo más a fondo, solo se que hasta ahora has intentado corregir el problema de la impresición o repetición del movimiento del stick direccional, que antes querías usar con el codigo que has usado para moverte por el menú pero te daba problemas con el movimiento de las diagonales, ¿pero tu código que signifca la estructura pos_b? ¿se encarga de las diagonales? pregunto por curiosidad, al ver, entre otras cosas, que cambias el valor en pos_b[0] = pos_b[0]-27 después de controlar que sea así con ese if (keys[SDLK_LEFT] && pos_b[0]>11) por ejemplo.
Puck2099
16/10/2005, 01:32
Pues, al no ver el codigo más a fondo, solo se que hasta ahora has intentado corregir el problema de la impresición o repetición del movimiento del stick direccional, que antes querías usar con el codigo que has usado para moverte por el menú pero te daba problemas con el movimiento de las diagonales, ¿pero tu código que signifca la estructura pos_b? ¿se encarga de las diagonales? pregunto por curiosidad, al ver, entre otras cosas, que cambias el valor en pos_b[0] = pos_b[0]-27 después de controlar que sea así con ese if (keys[SDLK_LEFT] && pos_b[0]>11) por ejemplo.
La pos_b es un vector de dos enteros que representa la posición del cursor en un tablero. pos_b[0] es la posición x y pos_b[1] es la posición y.
Sé que es una chapuza, pero es el primer código que hice para la GP32, a los días de tenerla y no me plantee hacer una estructura más bonita tipo cursor.x y cursor.y :p
Ese 27 que ves que se suma o resta a la posición, es el tamaño de cada casilla del tablero, 27 pixels de ancho y largo. El 11 y 200 que se comprueba que no se sobrepase son los límites del tablero en pixels.
En cuanto tenga el código funcionando al 100% bajo SDL me pondré a "limpiarlo" y mejorar un poco esas chapuzas para liberarlo :)
Espero que haya quedado más claro :)
Saludos
Espero que haya quedado más claro :)Pues bastante más claro, gracias a tu explicación me he podido imaginar algo de como es el movimiento en el juego y saber el porque de ese código :)
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.