'
' NeoLib - Keyboard Module
'
' Features:
'  9 subs
'  1 functions
' For a total of: 10 routines
'
' Specially designed and coded for AAP's QBCPC
' Official Library of the QuickBASIC Caliber Programming Compo (Summer & Autumn 2003)
'

DECLARE FUNCTION neoKeybInkeyScan% ()

DECLARE SUB neoKeybGetShift (LeftShift AS INTEGER, RightShift AS INTEGER, Alt AS INTEGER, Control AS INTEGER)
DECLARE SUB neoKeybGetShiftEnhanced (LeftControl AS INTEGER, RightControl AS INTEGER, LeftAlt AS INTEGER, RightAlt AS INTEGER, SysReq AS INTEGER)
DECLARE SUB neoKeybGetLeds (NumLock AS INTEGER, CapsLock AS INTEGER, ScrollLock AS INTEGER)
DECLARE SUB neoKeybSetLeds (NumLock AS INTEGER, CapsLock AS INTEGER, ScrollLock AS INTEGER)
DECLARE SUB neoKeybOff ()
DECLARE SUB neoKeybOn ()
DECLARE SUB neoKeybSetSpeed (TypemativDelay AS INTEGER, TypematicRate AS SINGLE)
DECLARE SUB neoKeybWaitKey ()
DECLARE SUB neoKeybSetKey (ScanCode AS INTEGER, ASCIIcode AS INTEGER)

DEFINT A-Z
'$DYNAMIC
'$INCLUDE:'QB.BI'

DIM SHARED Regs AS RegType
DIM SHARED RegsX AS RegTypeX

'////////////////////////////////////////////////////////////////////
' FUNCTIONS
'////////////////////////////////////////////////////////////////////
FUNCTION neoKeybInkeyScan
	'returns the scancode of a pressed key, or the key which was last pressed
	nKIS = INP(&H60)
	IF nKIS > 128 THEN neoKeybInkeyScan = 0 ELSE neoKeybInkeyScan = nKIS
END FUNCTION

'////////////////////////////////////////////////////////////////////
' SUBS
'////////////////////////////////////////////////////////////////////
SUB neoKeybGetShift (LeftShift AS INTEGER, RightShift AS INTEGER, Alt AS INTEGER, Control AS INTEGER)
	'gets the press status of shift, alt and ctrl
	' LeftShift = returns 0 or -1 whether left shift has been pressed
	' RightShift = returns 0 or -1 whether right shift has been pressed
	' Alt = returns 0 or -1 whether alt has been pressed
	' Control = returns 0 or -1 whether control has been pressed

	'use int 16h, ah=2h
        Regs.ax = &H0200
        INTERRUPT &H16, Regs, Regs

	'now al contains the shift flags
        RightShift = ((Regs.ax AND 1) > 0)
        LeftShift = ((Regs.ax AND 2) > 0)
        Control = ((Regs.ax AND 4) > 0)
        Alt = ((Regs.ax AND 8) > 0)
END SUB

SUB neoKeybGetShiftEnhanced (LeftControl AS INTEGER, RightControl AS INTEGER, LeftAlt AS INTEGER, RightAlt AS INTEGER, SysReq AS INTEGER)
	'gets the press status of control, alt and sysreq
	' LeftControl = returns 0 or -1 whether left control has been pressed
	' RightControl = returns 0 or -1 whether right control has been pressed
	' LeftAlt = returns 0 or -1 whether left alt has been pressed
	' RightAlt = returns 0 or -1 whether right alt has been pressed
	' SysReq = returns 0 or -1 whether sysreq has been pressed

	'use int 16h, ah=12h
	Regs.ax = &H1200
	INTERRUPT &H16, Regs, Regs

	'now it is in ah
	ah = (Regs.ax AND &HFF00&) \ &H100
        LeftControl = ((ah AND 1) > 0)
        LeftAlt = ((ah AND 2) > 0)
        RightControl = ((ah AND 4) > 0)
        RightAlt = ((ah AND 8) > 0)
        SysReq = ((ah AND 128) > 0)
END SUB

SUB neoKeybGetLeds (NumLock AS INTEGER, CapsLock AS INTEGER, ScrollLock AS INTEGER)
	'gets the status of the keyboard leds
	' NumLock = returns 0 or -1 whether numlock is active
	' CapsLock = returns 0 or -1 whether capslock is active
	' ScrollLock = returns 0 or -1 whether scrolllock is active

        'use int 16h, ah=2h
        Regs.ax = &H0200
        INTERRUPT &H16, Regs, Regs

        'now al contains the flags
        ScrollLock = ((Regs.ax AND 16) > 0)
        NumLock = ((Regs.ax AND 32) > 0)
        CapsLock = ((Regs.ax AND 64) > 0)
END SUB

SUB neoKeybSetLeds (NumLock AS INTEGER, CapsLock AS INTEGER, ScrollLock AS INTEGER)
	'sets the status of the keyboard leds, without changing the leds
	' NumLock = numlock status , 0 or -1
	' CapsLock = capslock status , 0 or -1
	' ScrollLock = scrolllock status , 0 or -1

	status = ABS(ScrollLock <> 0) + 2 * ABS(NumLock <> 0) + 4 * ABS(CapsLock <> 0)
        OUT &H60, &HED
        IF INP(&H60) <> &HFA THEN EXIT SUB
        FOR I = 0 TO 100: NEXT I
        OUT &H60, status
END SUB

SUB neoKeybOff
	'disables the keyboard

        OUT &H60, &HF5
END SUB

SUB neoKeybOn
	'enables the keyboard

	OUT &H60, &HF4
END SUB

SUB neoKeybSetSpeed (TypemativDelay AS INTEGER, TypematicRate AS SINGLE)
	'sets the keyboard speed
	' TypemativDelay = how many ms it takes to repeat a char
	' TypematicRate = how many ms it takes to scan keyboard

        td = TypemativDelay \ 250 - 1
	res = td * 32
	tr = CINT(CSNG((30.0! - TypematicRate) * (31!/28!)))
	res = res + tr

	OUT &H60, &HF3
	IF INP(&H60) <> &HFA THEN EXIT SUB
	FOR I = 0 TO 249: NEXT I
	OUT &H60, res
END SUB

SUB neoKeybWaitKey
	'waits for a key to be pressed

	'use int 21h, ax =0800h
	Regs.ax = &H800
	INTERRUPT &H21, Regs, Regs
END SUB

SUB neoKeybSetKey (ScanCode AS INTEGER, ASCIIcode AS INTEGER)
	'puts a key in the keyboard buffer, as if it had been pressed
	' ScanCode = the scancode of the desired key (1-?)
	' ASCIIcode = the ascii code of the desired key (0-255)

	'use int16h ax=500h
	Regs.ax = &H500
        Regs.cx = ASCIIcode + 256 * ScanCode
        INTERRUPT &H16, Regs, Regs
END SUB
