; Redefinir teclas y ver el estado de las teclas elegidas en el juego. ; Metodo optimizado con la extraccion de semifila (puerto) y tecla durante ; la redefinicion de las teclas y no durante la lectura del teclado en ; el bucle del juego. ORG 33500 CALL CLS CALL Redefinir_Teclas_SSSTTT ; Redefinir teclado CALL Wait_For_No_Key ; Esperar a que no haya teclas pulsadas CALL CLS ; Bucle del programa, lee nuestras teclas e imprime primero la ; "leyenda" de las teclas y luego el byte de estado de teclado: bucle: LD DE, 0 CALL CursorAt ; Nos vamos a (0,0) LD DE, msg_keys CALL PrintString ; Imprimimos mensaje "*<>^v" CALL Leer_Teclado_SSSTTT CALL PrintBin ; Imprimimos estado teclas (A) en binario JR bucle ; Repetir hasta reset ; Mensajes del programa msg_izq DEFB "Izquierda? ", _EOS msg_der DEFB "Derecha? ", _EOS msg_arriba DEFB "Arriba? ", _EOS msg_abajo DEFB "Abajo? ", _EOS msg_disp DEFB "Disparo? ", _EOS msg_keys DEFB " *<>^v", _CR, _EOS ; Teclas por defecto si no se redefine: O P Q A SPACE ; Hay que declararlas aqui en el mismo orden en que queremos ; que aparezcan en los bits teclas_player_1: p1_puerto_disp DEFB $7F ; Semifila ' ' = puerto $FEFE p1_tecla_disp DEFB $01 ; Tecla ' ' = bit 1 p1_puerto_izq DEFB $DF ; Semifila 'O' = puerto $DFFE p1_tecla_izq DEFB $02 ; Tecla 'O' = bit 2 p1_puerto_der DEFB $DF ; Semifila 'P' = puerto $DFFE p1_tecla_der DEFB $01 ; Tecla 'P' = bit 1 p1_puerto_arriba DEFB $FB ; Semifila 'Q' = puerto $FBFE p1_tecla_arriba DEFB $01 ; Tecla 'Q' = bit 1 p1_puerto_abajo DEFB $FD ; Semifila 'A' = puerto $FDFE p1_tecla_abajo DEFB $01 ; Tecla 'A' = bit 1 P1_NUM_TECLAS EQU 5 ; Usaremos 5 teclas: OPQA ; Estado de las tecla pulsadas p1_teclas_pulsadas DEFB 0 ;----------------------------------------------------------------------- ; Utiliza Redefine_Key para obtener las semifilas y tecla (00TTTSSS) ; del scancode seleccionado por el usuario pulsando una tecla. ; La semifila se guarda como puerto a leer y la tecla como ; el bit (posición) de esa tecla en la respuesta. ; Ejemplo: 'O' = p1_puerto_izq = $DF ; p1_tecla_izq = 2 (%00000010) ; Llama a "Redefine_Key" para mostrar el mensaje y pedir la tecla. ; ; ENTRADA: Nada ; SALIDA: Nada ; MODIFICA: AF, DE, HL, Flags ;----------------------------------------------------------------------- Redefinir_Teclas_SSSTTT: ; Los siguientes textos se podrian haber impreso tambien usando un bucle ; con INC DE (avanzar cadena) e INC HL (avanzar tecla a escribir) LD DE, msg_izq CALL PrintString ; Imprimir mensaje "Izquierda?" CALL Redefine_Key ; Esperar pulsacion (e imprimir ASCII) CALL Scancode_To_Port_Key LD HL, p1_puerto_izq ; Apuntamos HL a la p1_puerto_izq LD (HL), E ; Guardamos la semifila INC HL ; Incrementamos HL => apuntamos a p1_tecla_x LD (HL), D ; Guardamos la tecla LD DE, msg_der ; Siguiente mensaje: "Derecha?" CALL PrintString CALL Redefine_Key ; Esperar pulsacion (e imprimir ASCII) CALL Scancode_To_Port_Key LD HL, p1_puerto_der ; Apuntamos HL a la p1_puerto_X LD (HL), E ; Guardamos la semifila INC HL ; Incrementamos HL => apuntamos a p1_tecla_x LD (HL), D ; Guardamos la tecla LD DE, msg_arriba ; Repetimos con ARRIBA CALL PrintString CALL Redefine_Key CALL Scancode_To_Port_Key LD HL, p1_puerto_arriba ; Apuntamos HL a la p1_puerto_X LD (HL), E ; Guardamos la semifila INC HL ; Incrementamos HL => apuntamos a p1_tecla_x LD (HL), D ; Guardamos la tecla LD DE, msg_abajo ; Repetimos con ABAJO CALL PrintString CALL Redefine_Key CALL Scancode_To_Port_Key LD HL, p1_puerto_abajo ; Apuntamos HL a la p1_puerto_X LD (HL), E ; Guardamos la semifila INC HL ; Incrementamos HL => apuntamos a p1_tecla_x LD (HL), D ; Guardamos la tecla LD DE, msg_disp ; Repetimos con DISPARO CALL PrintString CALL Redefine_Key CALL Scancode_To_Port_Key LD HL, p1_puerto_disp ; Apuntamos HL a la p1_puerto_X LD (HL), E ; Guardamos la semifila INC HL ; Incrementamos HL => apuntamos a p1_tecla_x LD (HL), D ; Guardamos la tecla RET ;----------------------------------------------------------------------- ; Scancode_To_Port_Key: Extrae de un scancode 00TTTSSS ; los valores TTT y SSS, para guardarlos después por separado como ; PUERTO y TECLA ; Escrita por Xor_A [Fer]. ; ; ENTRADA: A = scancode de teclado (00TTTSSS) ; SALIDA: D = NUMERO de bit de TECLA. ; E = PUERTO (parte alta) correspondiente a esa SEMIFILA ; Ejemplo: 'O' = D = $DF ; E = 2 (%00000010) ; ; MODIFICA: A, DE, E, FLAGS ;----------------------------------------------------------------------- Scancode_To_Port_Key: LD D, A ; Hacer copia de scancode en D AND $07 ; Eliminar todos los bits menos 00000SSS CPL ; Invertir valores (1/0) LD E, A ; E = contador para bucle LD A, $FE ; Empezamos por primera semifila (determina puerto) JR Z, ConvScn_tecla ; Si Z==1 => es primera semifila ConvScn_loop1: RLCA ; Rotamos A: Siguiente semifila DEC E JR NZ, ConvScn_loop1 ; Si Z==0 => no es la semifila correcta ConvScn_tecla: LD E, A ; Salvaguardamos semifila (puerto a leer) en E LD A, D ; Recuperamos A = 00TTTSSS de nuevo AND $38 ; Eliminamos todos los valores menos 00TTT000 LD D, $10 ; Inicializamos a la tecla mas interna RET Z ; Si Z==1 => es la tecla interna ConvScn_loop2 RR D ; Rotamos: Siguiente tecla de la semifila SUB 8 JR NZ, ConvScn_loop2 ; Si Z==0 => NO ES LA TECLA CORRECTA RET ;----------------------------------------------------------------------- ; Lee el estado de las teclas definidas en variables y almacena en A ; dicho estado (1=pulsada, 0=no pulsada). El byte está codificado así: ; ; BITS 4 3 2 1 0 ; SIGNIFICADO FIRE LEFT RIGHT UP DOWN ; ; ENTRADA: NADA (usa las variables p1_puerto_* y p1_tecla_*) ; SALIDA: A = byte de estado de las teclas (empaquetadas en bits). ; MODIFICA: A, HL y CarryFlag ; ;----------------------------------------------------------------------- Leer_Teclado_SSSTTT: LD DE, P1_NUM_TECLAS*256 ; D = 5 (teclas a leer), E = 0 LD HL, teclas_player_1 ; 1a tecla (p1_puerto_X) para bit + alto LD C, $FE ; Parte baja puerto teclado tecl_sssttt_loop: LD B, (HL) ; cogemos puerto a leer (parte alta) INC HL ; pasamos al siguiente byte (p1_tecla_X) IN A, (C) ; leer del puerto de esta tecla CPL ; Ahora: 1 teclas pulsadas, 0 no pulsadas AND $1F ; aislamos las teclas AND (HL) ; comparo con la tecla en memoria (y ponemos CF=0) JR Z, tecl_sssttt_nopulsada ; Si Z == 1 => tecla no pulsada SCF ; Ponemos Carry = 1 para meterlo en A al rotar tecl_sssttt_nopulsada: RL E ; meto el valor de la pulsacion de la tecla ; (carry OFF no pulsada/carry ON pulsada) INC HL ; apunto a siguiente puerto (semifila) DEC D ; decrementamos el num. de teclas pendientes por leer JR NZ, tecl_sssttt_loop ; siempre necesita una pulsacion para salir del bucle LD A, E ; Recuperamos estado final LD (p1_teclas_pulsadas), A ; Guardamos en variable el estado de las teclas RET ; Devolvemos en A el estado de las teclas ;----------------------------------------------------------------------- ; Utiliza Find_Key para obtener una tecla válida. Se queda en un bucle ; de espera hasta que una sola tecla esté pulsada, y la devuelve en A. ; Además, imprime por pantalla el codigo ASCII de la tecla. ; ; ENTRADA: Nada ; SALIDA: A = scancode ; MODIFICA: Flags ;----------------------------------------------------------------------- Redefine_Key: PUSH DE PUSH HL CALL Wait_For_No_Key wait_for_scan_loop: CALL Find_Key JR NZ, wait_for_scan_loop ; Mas de una tecla leida, repetir LD A, D CP $FF ; si A es $FF => ninguna tecla pulsada JR Z, wait_for_scan_loop ; Repetimos hasta que A != $FF LD H, D ; Nos hacemos copia de D en H CALL Scancode2Ascii ; Convertir D (scancode) en A (ASCII) CP 'e' ; ¿Es 'e'? Imprimir "ENTER" JR NZ, redef_key_NO_ENTER LD DE, redef_key_enter CALL PrintString JR redef_key_end ; Impreso texto, salimos redef_key_NO_ENTER: CP 's' ; ¿Es 's'? Imprimir "SPACE" JR NZ, redef_key_NO_SPACE LD DE, redef_key_space CALL PrintString JR redef_key_end redef_key_NO_SPACE: CP 'c' ; ¿Es 'c'? Imprimir "CS" JR NZ, redef_key_NO_CAPSSHIFT LD DE, redef_key_cs CALL PrintString JR redef_key_end redef_key_NO_CAPSSHIFT: CP 'y' ; ¿Es 'y'? Imprimir "SS" JR NZ, redef_key_NO_SYMBOLSHIFT LD DE, redef_key_ss CALL PrintString JR redef_key_end redef_key_NO_SYMBOLSHIFT: ; Si llegamos aqui no era tecla especial. RST 16 ; Ninguna tecla especial => Print ASCII LD A, D redef_key_end: LD A, H ; Recuperamos scancode CALL PrintCR ; Imprimir retorno de carro POP HL POP DE RET ; Volver con registros preservados redef_key_enter DB "ENTER", _EOS redef_key_space DB "SPACE", _EOS redef_key_ss DB "SS", _EOS redef_key_cs DB "CS", _EOS ;----------------------------------------------------------------------- ; Chequea el teclado para detectar la pulsación de una tecla. ; Modifica A, H, DE y BC. ; Devuelve un código en el registro D que indica: ; ; Bits 0, 1 y 2 de "D": Semifila de teclas (puerto) detectada. ; Bits 3, 4 y 5 de "D": Tecla (posición) en esa semifila ; => (00TTTSSS) ; ; Así, el valor devuelto nos indica la semifila a leer y el bit a testear. ; ; El registro D valdrá 255 ($FF) si no hay ninguna tecla pulsada. ; ; Flags: ZF 0: Más de una tecla pulsada ; ZF 1: Tecla correctamente leída ;----------------------------------------------------------------------- Find_Key: LD DE, $FF2F ; Valor inicial "ninguna tecla" LD BC, $FEFE ; Puerto NXHALF: IN A, (C) CPL AND $1F JR Z, NPRESS ; Saltar si ninguna tecla pulsada INC D ; Comprobamos si hay más de 1 tecla pulsada RET NZ ; Si es así volver con Z a 0 LD H, A ; Cálculo del valor de la tecla LD A, E KLOOP: SUB 8 SRL H JR NC, KLOOP RET NZ ; Comprobar si más de una tecla pulsada LD D, A ; Guardar valor de tecla en D NPRESS: ; Comprobar el resto de semifilas DEC E RLC B JR C, NXHALF ; Repetimos escaneo para otra semifila CP A ; Ponemos flag a zero RET Z ; Volvemos ;----------------------------------------------------------------------- ; Scancode2Ascii: convierte un scancode en un valor ASCII ; IN: D = scancode de la tecla a analizar ; OUT: A = Codigo ASCII de la tecla (0-9 y A-Z) ; minusculas: e = ENTER, s = SPACE, c = CAPSSHIFT e = SYMBOLSHIFT ;----------------------------------------------------------------------- Scancode2Ascii: PUSH HL PUSH BC LD HL, 0 LD BC, TABLA_Scancode2ASCII ADD HL, BC ; HL apunta al inicio de la tabla ; buscamos en la tabla un max de 40 veces por el codigo ; le sumamos 40 a HL, leemos el valor de (HL) y ret A SC2Ascii_1: LD A, (HL) ; leemos un byte de la tabla CP "1" ; Si es "1" fin de la rutina (porque en ; (la tabla habriamos llegado a los ASCIIs) JR Z, SC2Ascii_Exit ; (y es condicion de forzado de salida) INC HL ; incrementamos puntero de HL CP D ; comparamos si A==D (nuestro scancode) JR NZ, SC2Ascii_1 SC2Ascii_Found: LD BC, 39 ; Sumamos 39(+INC HL=40) para ir a la ADD HL, BC ; seccion de la tabla con el codigo ASCII LD A, (HL) ; leemos el codigo ASCII de esa tabla SC2Ascii_Exit: POP BC POP HL RET ; 40 scancodes seguidos de sus ASCIIs equivalentes TABLA_Scancode2ASCII: DEFB $24, $1C, $14, $0C, $04, $03, $0B, $13, $1B, $23 DEFB $25, $1D, $15, $0D, $05, $02, $0A, $12, $1A, $22 DEFB $26, $1E, $16, $0E, $06, $01, $09, $11, $19, $21 DEFB $27, $1F, $17, $0F, $07, $00, $08, $10, $18, $20 DEFB "1234567890QWERTYUIOPASDFGHJKLecZXCVBNMys" ;-- Incluir libreria de utilidades -- INCLUDE "utils.asm" END 33500