Posts: 3,368
Threads: 195
Joined: Jan 2003
Hi all,
I was wondering about INP(96)... gives a readout of the keyboard right?
Well I found out that INP(96) can give two or more states depending on how long you press the thing. I was hoping to fix up the description in the FAQ, but I'm just not exactly sure how it works.
Does anyone know such a place where one can look up the specifics of this particular INP function? I know it exists somewhere... I recall someone talking about it in this very forum...
Peace cannot be obtained without war. Why? If there is already peace, it is unnecessary for war. If there is no peace, there is already war."
Visit www.neobasic.net to see rubbish in all its finest.
Posts: 1,752
Threads: 21
Joined: Jun 2002
Posts: 1,407
Threads: 117
Joined: Dec 2002
INP(96) gives you the key scan code when you press it, it repeats it at the key repeat rate if tou hokd it and returns the code +128 when you release it.
Be warned:s ome keys, as arrow keys, never emit a release code.
Reading INP(98) does not clear the keyboard buffer.
I used to implement it like this..
Code: 'keyboard array (as in ASM multikey)
DIM k(128)
'main loop
DO
k1 = INP(&H60)
'if key pressed or released
IF k1 THEN
'clear keyboard buffer
DEF SEG = &H40: POKE &H1C, PEEK(&H1A)
k(k1 AND 127) = ((k1 AND 128) = 0)
'take actions depending on key presses
IF k(1) THEN EXIT DO 'escape pressed
..................
END IF
'render
..........
LOOP
Antoni
Posts: 38
Threads: 1
Joined: Aug 2005
Quote:Be warned ome keys, as arrow keys, never emit a release code.
Are you sure? Do you have a documentation (and an example maybe?) that proves this statement?
Regards,
Mark
Posts: 1,407
Threads: 117
Joined: Dec 2002
CORRECTION: (I was speaking from the top of my head, so checked an old code)
Using INP(60) means you must be there in the moment the keycode is emitted, if you do not read at the correct moment you miss the code.
As the key release is emited only once, it's easier to miss it than keypresses as they are repeated.
So I ended resetting the keyboard array locations after reading them. If the key was still pressed, new press codes would be emitted.
For some reason I missed more releases from the arrow keys than from the numeric keypad, that's why I recalled it that way. If you try the code you will have a smoother movement using the numeric pad than with the arrow keys. Why?
Code: DECLARE SUB raytrace ()
DECLARE SUB ffix ()
ffix
SCREEN 13
DIM SHARED map(9, 9) AS INTEGER, skylut(200) AS SINGLE
DIM SHARED tex(31, 31) AS INTEGER, foff(15) AS INTEGER
DIM SHARED tex1(31, 31) AS INTEGER
DIM SHARED tex2(31, 31) AS INTEGER
DIM SHARED kbd(128) AS INTEGER
DIM SHARED frames%
DIM SHARED y99lut!(100 TO 199)
'read map,do sky lut
FOR i% = 0 TO 99
READ map(i% \ 10, i% MOD 10)
skylut(i%) = 25590 / (i% - 100)
NEXT
'make texture maps
FOR i% = 0 TO 31
FOR j% = 0 TO 31
tex(i%, j%) = 16 + (i% XOR j%) 'xor walls
i1% = i% - 16: j1% = j% - 16
tex1(i%, j%) = 64 + SQR((i1% * i1%) + (j1% * j1%)) 'concentric ground
tex2(i%, j%) = 128 + RND * 63 'rnd sky
NEXT j%, i%
'step-simulation vertical offset
CONST pioct! = 3.141592 / 8!
FOR i% = 0 TO 15
foff(i%) = ABS(COS(i% * pioct!) * 64)
NEXT
'set palette
OUT &H3C8, 0
'grey:walls
FOR i% = 0 TO 63
OUT &H3C9, i% + 16: OUT &H3C9, i% + 16: OUT &H3C9, i% + 16
NEXT
'green:ground
FOR i% = 0 TO 63
OUT &H3C9, 0: OUT &H3C9, 140 + 2 * i%: OUT &H3C9, 0
NEXT
'blue:sky
FOR i% = 0 TO 63
OUT &H3C9, 0: OUT &H3C9, 0: OUT &H3C9, 140 + i%
NEXT
tim! = TIMER
frames% = 0
raytrace
LOCATE 1, 1: PRINT frames% / (TIMER - tim!)
a$ = INPUT$(1)
END
'map data
DATA 7 , 8, 7, 8, 7, 8, 7, 8, 7, 8
DATA 7 , 0, 0, 0, 0, 0, 0, 0, 0, 8
DATA 8 , 0, 9, 1, 0, 2,10, 2, 0, 7
DATA 7 , 0, 1, 9, 0, 0, 0,10, 0, 8
DATA 8 , 0, 0, 0, 0, 0, 0, 0, 0, 7
DATA 7 , 0, 3,11, 3,11, 0, 0, 0, 8
DATA 8 , 0,11, 0, 0 ,3, 0 ,0, 0, 7
DATA 7 , 0, 3, 0, 0,11, 0, 0 ,0, 8
DATA 8 , 0, 0, 0, 0, 0, 0, 0, 0, 7
DATA 8 , 7, 8, 7, 8, 7, 8, 7, 8, 8
SUB raytrace
CONST rtf = 2048
CONST rtl = .0001
CONST inf = 3000000
CONST incu = .05
xpos = 1.5
ypos = 1.5
ini% = 1
'erase key buffer and set num lock off
DEF SEG = &H40: POKE &H1C, PEEK(&H1A): POKE &H17, PEEK(&H17) AND NOT 32
'frames loop
DO
frames% = frames% + 1
'keyboard input
k% = INP(&H60):
IF k% THEN
kbd(k% AND 127) = -((k% AND 128) = 0)
DEF SEG = &H40: POKE &H1C, PEEK(&H1A)
IF kbd(1) THEN EXIT DO
END IF
'calculate new position and angle
turn% = kbd(&H4D) - kbd(&H4B): kbd(&H4D) = 0: kbd(&H4B) = 0
mov% = kbd(80) - kbd(72) + ini%:kbd(80) = 0: kbd(72) = 0
'a movement has happened, update and collision detect
IF turn% OR mov% THEN
angle = angle + turn% * .06
xpos2 = mov% * COS(angle) * incu
ypos2 = mov% * SIN(angle) * incu
xpos32 = xpos * 32
ypos32 = ypos * 32
'calculate walk offsets
f% = f% + mov%
foff% = foff(f% AND 15)
calc = 25600 - 32 * foff%
FOR y% = 100 TO 199: y99lut!(y%) = calc / (y% - 99): NEXT
IF ini% THEN ini% = 0
dxc = COS(angle) * incu: dxs = SIN(angle) * incu / 160
dyc = COS(angle) * incu / 160: dys = SIN(angle) * incu
'colision detector
xp22 = xpos - xpos2 - xpos2
IF map(INT(ypos - incu), INT(xp22 - incu)) = 0 THEN
IF map(INT(ypos - incu), INT(xp22 + incu)) = 0 THEN
IF map(INT(ypos + incu), INT(xp22 - incu)) = 0 THEN
IF map(INT(ypos + incu), INT(xp22 + incu)) = 0 THEN
xpos = xpos - xpos2
END IF
END IF
END IF
END IF
yp22 = ypos - ypos2 - ypos2
IF map(INT(yp22 - incu), INT(xpos - incu)) = 0 THEN
IF map(INT(yp22 + incu), INT(xpos - incu)) = 0 THEN
IF map(INT(yp22 - incu), INT(xpos + incu)) = 0 THEN
IF map(INT(yp22 + incu), INT(xpos + incu)) = 0 THEN
ypos = ypos - ypos2
END IF
END IF
END IF
END IF
xp1! = (xpos - INT(xpos)) * rtf
yp1! = (ypos - INT(ypos)) * rtf
END IF
'screen sweep loop
DEF SEG = &HA000:
FOR x% = 0 TO 319
'INIT RAYCASTER
dx = dxc - (x% - 160) * dxs
dy = (x% - 160) * dyc + dys
SELECT CASE dx
CASE IS < -rtl
nextxt& = -xp1! / dx
dxt& = -rtf / dx
CASE IS > rtl
nextxt& = (rtf - xp1!) / dx
dxt& = rtf / dx
CASE ELSE
nextxt& = inf
END SELECT
SELECT CASE dy
CASE IS < -rtl
nextyt& = -yp1! / dy
dyt& = -rtf / dy
CASE IS > rtl
nextyt& = (rtf - yp1!) / dy
dyt& = rtf / dy
CASE ELSE
nextyt& = inf
END SELECT
sdx% = SGN(dx): sdy% = SGN(dy)
xm% = INT(xpos): ym% = INT(ypos)
'raycast until wall hit
DO
IF nextxt& < nextyt& THEN
xm% = xm% + sdx%
IF map(ym%, xm%) THEN ti = rtf / nextxt&: EXIT DO
nextxt& = nextxt& + dxt&
ELSE
ym% = ym% + sdy%
IF map(ym%, xm%) THEN ti = rtf / nextyt&: EXIT DO
nextyt& = nextyt& + dyt&
END IF
LOOP
d1% = 99 - CINT((800 + foff%) * ti)
d2% = 102 + CINT((800 - foff%) * ti)
d21% = d2% - d1%
'draw a vertical slice.
tx% = ((xpos + ypos + (dx + dy) / ti) * 32) AND 31
p& = x%
FOR y% = 0 TO 199
SELECT CASE y%
'sky
CASE IS < d1%
'tt% = 1
tt% = tex2(dx * skylut(y%) AND 31, dy * skylut(y%) AND 31)
'tt% = tex2(skx(y%), sky(y%))
'wall
CASE IS < d2%
tt% = tex((32 * (y% - d1%) \ d21%) AND 31, tx%)
CASE ELSE
'ground
'tt% = 2
tt% = tex1(xpos32 + dx * y99lut!(y%) AND 31, ypos32 + dy * y99lut!(y%) AND 31)
'tt% = tex1(y99x(y%), y99y(y%))
END SELECT
POKE p&, tt%
p& = p& + 320
NEXT
NEXT x%
LOOP
END SUB
Antoni
Posts: 38
Threads: 1
Joined: Aug 2005
It seems that you don't check for the &HE0 key code (introduces an enhanced key code). This also was the problem when I wrote my first IRQ1 handler.
When you "forget" to look for &HE0, you'll get some very strange results when you query keys like SHIFT directly.
Regards,
Mark
Posts: 1,407
Threads: 117
Joined: Dec 2002
...and that's why so many people switched to FB. You developers sort out that odd stuff for us.
Antoni
Posts: 3,368
Threads: 195
Joined: Jan 2003
Reason I asked is because I was looking in the FreeBasic documentation and stumbled upon a multikey routine with scan codes. I noticed some of them were missing and some didn't look quite right so I checked what I put in the FAQ. Some of my own mappings from numbers to keys were wrong, and I decided to check it. It turns out that things were quite a bit more complicated...
I think several keys, like arrow keys, produce an alternating pattern, but the rest have a pressed/recently pressed number. Just wanted to figure out what was going on.
Thanks for the replies..
Peace cannot be obtained without war. Why? If there is already peace, it is unnecessary for war. If there is no peace, there is already war."
Visit www.neobasic.net to see rubbish in all its finest.
Posts: 38
Threads: 1
Joined: Aug 2005
Hmm ... does that mean that you've found an error in the FreeBASIC sources? If so, please tell me what's the problem and what key codes cause troubles.
BTW: Please take a look at the CVS source of the DOS port to see the direct I/O access to 0x60 (dead code removed):
Code: static int fb_MultikeyHandler(unsigned irq_number)
{
unsigned char scancode_raw;
fb_hWriteControlCommand( 0xAD ); /* Lock keyboard */
/* read the raw scancode from the keyboard */
scancode_raw = inportb(0x60); /* read scancode */
{
size_t scancode = scancode_raw;
if( scancode==0xE0 ) {
got_extended_key = TRUE;
} else {
int release_code = (scancode & 0x80)!=0;
scancode &= 0x7F;
if( got_extended_key ) {
got_extended_key = FALSE;
switch( scancode ) {
case 0x2A:
/* Ignore this extended key code, otherwise you'll
* get spurious SHIFT presses/releases */
scancode = 0;
break;
}
}
if( scancode!=0 ) {
/* Remeber scancode status */
key[scancode] = !release_code;
}
}
}
fb_hWriteControlCommand( 0xAE ); /* Unlock keyboard */
return FALSE;
}
Regards,
Mark
Posts: 357
Threads: 118
Joined: Oct 2004
INP(96) also goes through the keyboard's driver before ever reaching Qbasic, sometimes things can get changed, thats also why the windows key, or any extra keys never will give you a scancode.
f you play a Microsoft CD backwards you can hear demonic voices. The scary part is that if you play it forwards it installs Windows.
|