gbdk-releases/gbdk-lib/libc/gb/input.s
2015-01-10 16:25:08 +01:00

590 lines
9.5 KiB
ArmAsm

.include "global.s"
;; Note that while gets uses a pointer, the pointer had better
;; be in non-banked RAM else bad things will happen.
;; BANKED: checked, imperfect
.globl .copy_vram
.globl .set_xy_wtt
.globl .mv_sprite
.globl .set_sprite_prop
.globl .set_sprite_tile
.globl .jpad
.globl .padup
.MINMSPOSX = 0x02 ; In tiles
.MINMSPOSY = 0x0A
.MAXMSPOSX = 0x11
.MAXMSPOSY = 0x0F
.INIMSPOSX = .MINMSPOSX
.INIMSPOSY = .MINMSPOSY
.KBDWINPOSY = 0x08 ; In tiles
.KBDSIZE = 0x1006
.MSOFFSETX = 0x0C ; In pixels
.MSOFFSETY = 0x14
.MINACCEL = 0x0800
.MAXACCEL = 0x0100
.CR = 0x0A ; Unix
; .CR = 0x0D ; Dos
.globl .tmode_out ; From 'output.s'
.globl .put_char
.globl .del_char
.globl .cury
.area _HEADER (ABS)
.org .MODE_TABLE+4*.T_MODE_INOUT
JP .tmode_inout
.module Terminal
.area _BSS
.msx: ; Mouse position
.ds 0x01
.msy:
.ds 0x01
.msacc: ; Mouse acceleration
.ds 0x02
.msstate: ; Mouse state
.ds 0x01
.mschanged: ; Did the mouse move?
.ds 0x01
.string_len: ; Used length of input buffer
.ds 0x01
.area _BASE
;; Enter text mode with input
.tmode_inout::
DI ; Disable interrupts
;; Turn the screen off
LDH A,(.LCDC)
BIT 7,A
JR Z,1$
;; Turn the screen off
CALL .display_off
1$:
LD A,(.mode)
AND #.T_MODE
CALL Z,.tmode_out
LD BC,#.tp1 ; Move pointer
LD HL,#0x8000
LD DE,#.endtp1-.tp1
CALL .copy_vram
LD A,#<.MINACCEL ; Acceleration
LD (.msacc),A
LD A,#>.MINACCEL
LD (.msacc+1),A
;; Initialize window
LD BC,#.frame_tiles
LD DE,#0x0000 ; Place image at (0x00,0x00) tiles
LD HL,#0x140A ; Image size is 0x14 x 0x0A tiles
CALL .set_xy_wtt
LD BC,#.kbdtable
LD DE,#0x0202 ; Place image at (0x02,0x02) tiles
LD HL,#.KBDSIZE ; Image size is 0x10 x 0x06 tiles
CALL .set_xy_wtt
XOR A
LD A,#.MINWNDPOSX
LDH (.WX),A
LD A,#.MAXWNDPOSY ; Hide window
LDH (.WY),A
;; Initialize sprite
LD C,#0x00 ; Sprite 0x00
LD D,#0x00 ; Default sprite properties
CALL .set_sprite_prop
LD C,#0x00 ; Sprite 0x00
LD D,#0x00 ; Tile 0x00
CALL .set_sprite_tile
LD A,#0b00101100
LDH (.OBP0),A
;; Turn the screen on
LD A,#0b11000001 ; LCD = On
; WindowBank = 0x9C00
; Window = Off
; BG Chr = 0x8800
; BG Bank = 0x9800
; OBJ = 8x8
; OBJ = Off
; BG = On
LDH (.LCDC),A
LD A,#.T_MODE_INOUT
LD (.mode),A
EI ; Enable interrupts
RET
.area _CODE
;; Prompt the user for a char and return it in A
.get_char:
PUSH BC
PUSH DE
PUSH HL
CALL .show_kbd
CALL .show_mouse
1$:
CALL .track_mouse
CALL .update_mouse
CALL .jpad
LD D,A
AND #.A ; Is A pressed ?
JP Z,1$
LD A,(.msy) ; Look for char under the mouse
SUB #.MINMSPOSY
JR Z,12$
LD E,A
XOR A
11$:
ADD #.MAXMSPOSX-.MINMSPOSX+1
DEC E
JR NZ,11$
12$:
LD E,A
LD A,(.msx)
SUB #.MINMSPOSX
ADD E
LD HL,#.kbdtable
LD B,#0x00
LD C,A
ADD HL,BC
LD B,(HL)
CALL .hide_mouse
CALL .hide_kbd
LD A,B
POP HL
POP DE
POP BC
RET
;; Prompt the user for a string and store it in (HL)
.get_string:
PUSH BC
PUSH DE
PUSH HL
CALL .show_kbd
CALL .show_bkg
CALL .show_mouse
XOR A
LD (.string_len),A
1$:
CALL .track_mouse
CALL .update_mouse
CALL .jpad
LD D,A
AND #.A ; Is A pressed ?
JP NZ,10$
LD A,D
AND #.B ; Is B pressed ?
JP NZ,20$
LD A,D
AND #.SELECT ; Is SELECT pressed ?
JP NZ,30$
LD A,D
AND #.START ; Is START pressed ?
JR Z,1$
CALL .padup ; Wait for button to be depressed
LD A,#.CR
CALL .put_char
LD (HL),#0x00
CALL .hide_mouse
CALL .hide_bkg
CALL .hide_kbd
POP HL
POP DE
POP BC
RET
10$:
;; Insert a character at cursor position
LD A,(.string_len) ; Check buffer length
; CP #.BUFLEN-1 ; Keep 1 char for EOS
; JR Z,13$
INC A
LD (.string_len),A ; Update it
LD A,(.msy) ; Look for char under the mouse
SUB #.MINMSPOSY
JR Z,12$
LD E,A
XOR A
11$:
ADD #.MAXMSPOSX-.MINMSPOSX+1
DEC E
JR NZ,11$
12$:
LD E,A
LD A,(.msx)
SUB #.MINMSPOSX
ADD E
PUSH HL
LD HL,#.kbdtable
LD B,#0x00
LD C,A
ADD HL,BC
LD A,(HL)
POP HL
LD (HL+),A ; Add it into input buffer
CALL .put_char ; Print it
CALL .show_bkg ; Ensure the text is not hidden
13$:
CALL .padup ; Wait for button to be depressed
JP 1$
20$:
;; Delete a character at cursor position
LD A,(.string_len) ; Is there any char in the buffer ?
OR A
JR Z,21$
DEC A ; Yes
LD (.string_len),A ; Update buffer length
DEC HL
CALL .del_char
21$:
CALL .padup ; Wait for button to be depressed
JP 1$
30$:
CALL .hide_mouse
CALL .hide_bkg
CALL .hide_kbd
CALL .padup ; Wait for button to be depressed
CALL .show_kbd
CALL .show_bkg
CALL .show_mouse
JP 1$
.show_kbd:
PUSH BC
PUSH DE
LDH A,(.LCDC)
OR #0b00100000 ; Window = On
LDH (.LCDC),A
LD A,#.MAXWNDPOSY ; Show window
1$:
BIT 0,A ; Wait for VBL every 2 pixels (slow down)
JR NZ,2$
LD B,A
CALL .wait_vbl_done
LD A,B
2$:
LDH (.WY),A
CP #.KBDWINPOSY*0x08
JR Z,99$
DEC A
JR 1$
99$:
POP DE
POP BC
RET
.hide_kbd:
PUSH BC
PUSH DE
LD A,#.KBDWINPOSY*0x08+1
1$: ; Hide window
BIT 0,A ; Wait for VBL every 2 pixels (slow down)
JR Z,2$
LD B,A
CALL .wait_vbl_done
LD A,B
2$:
LDH (.WY),A
CP #.MAXWNDPOSY
JR Z,3$
INC A
JR 1$
3$:
LDH A,(.LCDC)
AND #0b11011111 ; Window = Off
LDH (.LCDC),A
POP DE
POP BC
RET
.show_bkg:
PUSH BC
PUSH DE
LDH A,(.SCY)
LD D,A
LD A,(.cury)
SUB #.KBDWINPOSY-1
JR C,99$
JR Z,99$
SLA A ; A = A * 8
SLA A
SLA A
SUB D
JR C,99$
JR Z,99$
LD C,A
LDH A,(.SCY)
1$:
BIT 0,A ; Wait for VBL every 2 pixels (slow down)
JR Z,2$
LD B,A
CALL .wait_vbl_done
LD A,B
2$:
INC A
LDH (.SCY),A
DEC C
JR Z,99$
JR 1$
99$:
POP DE
POP BC
RET
.hide_bkg:
LDH A,(.SCY)
OR A
RET Z
PUSH BC
PUSH DE
1$:
BIT 0,A ; Wait for VBL every 2 pixels (slow down)
JR Z,2$
LD B,A
CALL .wait_vbl_done
LD A,B
2$:
DEC A
LDH (.SCY),A
JR Z,99$
JR 1$
99$:
POP DE
POP BC
RET
.show_mouse:
LD A,#.INIMSPOSX
LD (.msx),A
LD A,#.INIMSPOSY
LD (.msy),A
CALL .set_mouse
LDH A,(.LCDC)
OR #0b00000010 ; OBJ = On
LDH (.LCDC),A
RET
.hide_mouse:
LDH A,(.LCDC)
AND #0b11111101 ; OBJ = Off
LDH (.LCDC),A
RET
.track_mouse:
PUSH BC
PUSH DE
PUSH HL
XOR A
LD (.mschanged),A ; Default to no change
CALL .jpad
LD D,A
LD HL,#.msstate
AND #.UP+.DOWN+.LEFT+.RIGHT
JR NZ,1$
LD (HL),#0x00 ; Reset state
JP 99$
1$:
LD A,(HL)
LD (HL),#0x01 ; Set state
OR A ; Was it 0 ?
LD HL,#.msacc ; Acceleration
JR NZ,2$
; Yes
LD (HL),#<.MINACCEL
INC HL
LD (HL),#>.MINACCEL
JR 4$ ; Update position
2$:
LD C,(HL)
INC HL
LD B,(HL)
DEC BC
LD A,B
OR C
JR Z,3$
LD (HL),B
DEC HL
LD (HL),C
JP 99$
3$: ; Set new acceleration to maximum
LD (HL),#>.MAXACCEL
DEC HL
LD (HL),#<.MAXACCEL
4$: ; Update position
LD A,#0x01
LD (.mschanged),A
LD A,D
AND #.UP ; Is UP pressed ?
JR Z,6$
LD A,(.msy)
CP #.MINMSPOSY
JR Z,5$
DEC A
LD (.msy),A
JR 6$
5$:
LD A,#.MAXMSPOSY
LD (.msy),A
6$:
LD A,D
AND #.DOWN ; Is DOWN pressed ?
JR Z,8$
LD A,(.msy)
CP #.MAXMSPOSY
JR Z,7$
INC A
LD (.msy),A
JR 8$
7$:
LD A,#.MINMSPOSY
LD (.msy),A
8$:
LD A,D
AND #.LEFT ; Is LEFT pressed ?
JR Z,10$
LD A,(.msx)
CP #.MINMSPOSX
JR Z,9$
DEC A
LD (.msx),A
JR 10$
9$:
LD A,#.MAXMSPOSX
LD (.msx),A
10$:
LD A,D
AND #.RIGHT ; Is RIGHT pressed ?
JR Z,99$
LD A,(.msx)
CP #.MAXMSPOSX
JR Z,11$
INC A
LD (.msx),A
JR 99$
11$:
LD A,#.MINMSPOSX
LD (.msx),A
99$:
POP HL
POP DE
POP BC
RET
.update_mouse:
LD A,(.mschanged) ; Did it change ?
OR A
RET Z ; No
.set_mouse:
PUSH BC
PUSH DE
PUSH HL
LD C,#0x00 ; Sprite 0x00
LD A,(.msx)
SLA A ; A = A * 8
SLA A
SLA A
ADD #.MSOFFSETX
LD D,A
LD A,(.msy)
SLA A ; A = A * 8
SLA A
SLA A
ADD #.MSOFFSETY
LD E,A
CALL .mv_sprite
POP HL
POP DE
POP BC
RET
_getchar:: ; Banked
LD A,(.mode)
CP #.T_MODE_INOUT
JR Z,1$
PUSH BC
CALL .tmode_inout
POP BC
1$:
CALL .get_char
LD E,A
RET
_gets:: ; Banked
LD A,(.mode)
CP #.T_MODE_INOUT
JR Z,1$
PUSH BC
CALL .tmode_inout
POP BC
1$:
LDA HL,.BANKOV(SP) ; Skip return address
LD A,(HL+)
LD H,(HL) ; HL = s
LD L,A
PUSH HL
CALL .get_string
POP DE
RET
;; PENDING: this is unfortunate. Refed from .tmode_inout
.area _BASE
.tp1:
.pointers:
; Tile 0x00
.byte 0xFF,0xFF,0xFE,0x82,0xFC,0x84,0xFC,0x84,0xFE,0x82,0xFF,0xB1,0xCF,0xC9,0x87,0x87
.endtp1:
.frame_tiles:
.byte 0x1C,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x1D
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x0F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0F
.byte 0x1E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x1F
.kbdtable:
;; This is unfortunate. astorgb and rgbasm cant interpert:
;; .ascii " !\"#$%&'()*+,-./"
;; so we have to use the hex form here.
.db 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
.db 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F
.ascii "0123456789:"
;; astorgb recognises the embedded ; as a comment :)
.db 0x3B
.ascii "<=>?"
.ascii "@ABCDEFGHIJKLMNO"
.ascii "PQRSTUVWXYZ[\\]^_"
.ascii "`abcdefghijklmno"
.ascii "pqrstuvwxyz\{\|\}~ "