; 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 %00000111 ; 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 %00111000 ; 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 %00011111 ; 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 %00011111 ; aislamos las teclas 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