;KLogger v1.0 by Brandon Wilson ;06/10/05 ;07/12/05 ; ;KLogger is a TI-83 Plus Flash application that will log every keypress as well as keep a record of what ;programs and apps were written. ; ;A limit can be placed on the size of the key and program/app appvars that hold the logs. ; ;Please do not modify the contents of this file or publish it without both my prior knowledge and permission. include "ti83plus.inc" EXT_APP equ 1 ;This definition is required of all apps cseg ;This linker directive is required of all apps. db 080h,0Fh ;Field: Program length db 00h,00h,00h,00h ;Length=0 (N/A for unsigned apps) db 080h,012h ;Field: Program type db 01h,04h ;Type= Shareware, TI-83Plus db 080h,021h ;Field: App ID db 01h ;Id = 1 db 080h,031h ;Field: App Build db 01h ;Build = 1 db 080h,048h ;Field: App Name db "KLogger " ;Name = "KLogger " must be 8 characters db 080h,081h ;Field: App Pages db 01h ;App Pages = 1 db 080h,090h ;No default splash screen db 03h,026h ,09h,04h, 04h,06fh,01bh,80h ;Field: Date stamp- 5/12/1999 db 02h,0dh,040h ;Dummy encrypted TI date stamp signature db 0a1h ,06bh ,099h ,0f6h ,059h ,0bch ,067h db 0f5h ,085h ,09ch ,09h ,06ch ,0fh ,0b4h ,03h ,09bh ,0c9h db 03h ,032h ,02ch ,0e0h ,03h ,020h ,0e3h ,02ch ,0f4h ,02dh db 073h ,0b4h ,027h ,0c4h ,0a0h ,072h ,054h ,0b9h ,0eah ,07ch db 03bh ,0aah ,016h ,0f6h ,077h ,083h ,07ah ,0eeh ,01ah ,0d4h db 042h ,04ch ,06bh ,08bh ,013h ,01fh ,0bbh ,093h ,08bh ,0fch db 019h ,01ch ,03ch ,0ech ,04dh ,0e5h ,075h db 80h,7Fh ;Field: Program Image length db 0,0,0,0 ;Length=0, N/A db 0,0,0,0 ;Reserved db 0,0,0,0 ;Reserved db 0,0,0,0 ;Reserved db 0,0,0,0 ;Reserved _EnableRawKeyHook equ 4F66h _DisableRawKeyHook equ 4F6Fh ;rawKeyHookPtr equ 9B88h rawKeyHookByte equ 9B8Bh kloggerFlags equ asm_Flag1 logStarted equ 0 appSearch equ 1 keySearch equ 2 progSearch equ 3 keySelected equ 4 maybeSkip equ 5 rawKeyHookFlag equ 34h rawKeyHookActive equ 5 wKeySize equ appBackUpScreen wMemFree equ appBackUpScreen+2 wProgSize equ appBackUpScreen+4 varName equ appBackUpScreen+7 wOffset equ appBackUpScreen+20 wSize equ appBackUpScreen+22 wTemp equ appBackUpScreen+24 startApp: ;set log status res logStarted,(iy+kloggerFlags) bit rawKeyHookActive,(iy+rawKeyHookFlag) jr nz,setStatus jr startMenu ld hl,sKeyName rst 20h B_CALL ChkFindSym jr c,statusSkip ;walk through all entries...if incomplete, jump to setStatus, otherwise startMenu ld a,(de) ld c,a inc de ld a,(de) ld b,a inc de saLoop1: ld a,(de) inc de or a jr z,statusSkip ;zero was encountered, so this var is complete, check the other one dec bc ld a,b or c jr nz,saLoop1 jr setStatus ;var is incomplete, so log has been started statusSkip: ld hl,sProgName rst 20h B_CALL ChkFindSym jr c,startMenu ;walk through all entries...if complete, jump to startMenu, otherwise stay for setStatus ld a,(de) ld c,a inc de ld a,(de) ld b,a inc de saLoop2: ld a,(de) inc de or a jr z,startMenu ;zero was encountered, so this var is complete, continue being done dec bc ld a,b or c jr nz,saLoop2 ;var is incomplete, so log has been started setStatus: set logStarted,(iy+kloggerFlags) startMenu: ;draw menu with or without "Stop" option B_CALL ClrLCDFull B_CALL HomeUp ld hl,sTitle call PutSApp ld hl,sMainMenu2 bit logStarted,(iy+kloggerFlags) jr z,drawMenu ld hl,sMainMenu1 call SoftKey ld hl,8*256+25 ld (penCol),hl ld hl,sLogEnabled call VPutSApp jr saKeyLoop drawMenu: call SoftKey ld hl,8*256+25 ld (penCol),hl ld hl,sLogDisabled call VPutSApp saKeyLoop: B_CALL GetKey cp kQuit jr z,exitApp cp kGraph jr z,exitApp cp kYequ jr z,newLog cp kZoom ;jr z,viewLog ;if nothing to stop, don't check for F2 (Stop) bit logStarted,(iy+kloggerFlags) jr z,saKeyLoop cp kWindow jr z,stopLog jr saKeyLoop viewLog: res keySearch,(iy+kloggerFlags) res progSearch,(iy+kloggerFlags) B_CALL ClrLCDFull B_CALL HomeUp ld hl,sTitle call PutSApp call SoftKey2 ld hl,(wOffset) ld (wTemp),hl bit keySearch,(iy+kloggerFlags) jr nz,vlLoop bit progSearch,(iy+kloggerFlags) jr z,startMenu ld hl,(wTemp) inc hl ld (wTemp),hl call vlLeft vlLoop: B_CALL GetKey cp kQuit jr z,exitApp bit keySearch,(iy+kloggerFlags) jr z,_vlKeySearch cp kYequ jr z,vlKeys cp kWindow jr z,vlKeys _vlKeySearch: bit progSearch,(iy+kloggerFlags) jr z,_vlProgSearch cp kZoom jr z,vlProgs cp kTrace jr z,vlProgs _vlProgSearch: cp kGraph jr z,startMenu cp kLeft jr z,vlLeft cp kRight jr z,vlRight jr vlLoop vlLeft: ld hl,0105h ld (curRow),hl ld de,(wTemp) ld hl,(wOffset) B_CALL cphlde jr z,vlLoop push de B_CALL EraseEOL pop de dec de ld (wTemp),de ld a,(de) call getString jr c,vlLoop push hl call stringLength pop hl ld b,a ld a,16 sub b srl a ld (curCol),a call PutSApp ld a,1 ld (curCol),a ld hl,(wTemp) ld de,(wOffset) B_CALL cphlde jr z,_skipLeftArrowL ld a,Lleft jr _slalContinue _skipLeftArrowL: ld a,Lspace _slalContinue: B_CALL PutC ld a,14 ld (curCol),a ld hl,(wOffset) ld de,(wSize) add hl,de ld de,(wTemp) B_CALL cphlde jr z,_skipLeftArrowR ld a,Lconvert jr _slarContinue _skipLeftArrowR: ld a,Lspace _slarContinue: B_CALL PutC jr vlLoop vlRight: ld hl,0105h ld (curRow),hl ld de,(wSize) ld hl,(wOffset) add hl,de ld de,(wTemp) B_CALL cphlde jr z,vlLoop push de B_CALL EraseEOL pop de ld a,(de) call getString jr c,vlLoop push hl call stringLength pop hl ld b,a ld a,16 sub b srl a ld (curCol),a call PutSApp ld a,1 ld (curCol),a ld hl,(wTemp) ld de,(wOffset) B_CALL cphlde jr z,_skipRightArrowL ld a,Lleft jr _sralContinue _skipRightArrowL: ld a,Lspace _sralContinue: B_CALL PutC ld a,14 ld (curCol),a ld hl,(wOffset) ld de,(wSize) add hl,de ld de,(wTemp) B_CALL cphlde jr z,_skipRightArrowR ld a,Lconvert jr _srarContinue _skipRightArrowR: ld a,Lspace _srarContinue: B_CALL PutC jr vlLoop getString: ;finish, return either key string or app name bit progSearch,(iy+kloggerFlags) jr z,_gsKeySearch B_CALL ZeroOP1 ld hl,(wTemp) ld a,(hl) cp 0FFh jr z,_gsError ld b,0 ld c,a inc hl ld de,op1 ldir ld (wTemp),hl ld hl,op1 ret _gsKeySearch: ld hl,(wTemp) ld a,(hl) cp 0FFh jr z,_gsError ld b,a ld hl,sKeyTable-2 _gsksLoop: inc hl ld a,(hl) or a jr nz,_gsksLoop inc hl ld (wTemp),hl djnz _gsksLoop ret _gsError: scf ret stringLength: ;finish ld b,0 strlLoop: ld a,(hl) or a jr z,strlLoopDone inc b inc hl jr strlLoop strlLoopDone: ld a,b ret vlKeys: ld hl,sKeyName rst 20h B_CALL ChkFindSym ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de inc de inc de ld (wOffset),de ld (wSize),hl jr viewLog vlProgs: ld hl,sProgName rst 20h B_CALL ChkFindSym ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de inc de inc de ld (wOffset),de ld (wSize),hl jr viewLog newLog: bit rawKeyHookActive,(iy+rawKeyHookFlag) jr z,newLogStart in a,(6) ld b,a ld a,(rawKeyHookPtr+2) cp b jr z,newLogStart B_CALL ClrLCDFull B_CALL HomeUp ld hl,sTitle call PutSApp ld hl,15*256+3 ld (penCol),hl ld hl,sHook1 call VPutSApp ld hl,22*256+10 ld (penCol),hl ld hl,sHook2 call VPutSApp ld hl,sHookTable call SoftKey nlLoop: B_CALL GetKey cp kQuit jr z,exitApp cp kYequ jr z,newLogStart cp kGraph jr z,startMenu jr nlLoop newLogStart: res maybeSkip,(iy+kloggerFlags) ;input sizes for key and prog appvars ld hl,50 ;19; 15 for VAT entry, 2 for identifiers, 1 for keycode, and 1 for 0 ld (wKeySize),hl B_CALL EnoughMem jr c,startMenu ;clear screen B_CALL ClrLCDFull B_CALL HomeUp ;display and store free memory ld hl,sRAMFree call PutSApp B_CALL CleanAll B_CALL MemChk ld (wMemFree),hl B_CALL DispHL ;draw softkey menu ld hl,sNewTable call SoftKey ld hl,0001h ld (curRow),hl ld hl,sRAMAfter call PutSApp newLogKeyLoop: ;display memory that would be left ld hl,0B01h ld (curRow),hl ld hl,(wMemFree) ld de,(wKeySize) or a sbc hl,de B_CALL DispHL ;display adjust string ld hl,20*256+3 ld (penCol),hl ld hl,sAdjustSize1 call VPutSApp ;display current size ld hl,0105h ld (curRow),hl ld a,Lleft B_CALL PutC ld a,5 ld (curCol),a ld hl,(wKeySize) B_CALL DispHL ld a,14 ld (curCol),a ld a,Lconvert B_CALL PutC newLogKeyLoop2: B_CALL GetKey cp kquit jr z,exitApp cp kGraph jr z,exitApp cp kLeft jr z,newLogLeft cp kRight jr z,newLogRight cp kYequ jr z,newLogContinue cp kWindow jr z,newLogSkip jr newLogKeyLoop2 newLogLeft: ld hl,(wKeySize) ld de,50 or a sbc hl,de ld de,19 B_CALL cphlde jr c,newLogKeyLoop jr z,newLogKeyLoop ld hl,(wKeySize) ld de,50 or a sbc hl,de ld (wKeySize),hl jr newLogKeyLoop newLogRight: ld hl,(wKeySize) ld de,50 add hl,de ld de,(wMemFree) B_CALL cphlde jr nc,newLogKeyLoop jr z,newLogKeyLoop ld hl,(wKeySize) ld de,50 add hl,de ld (wKeySize),hl jr newLogKeyLoop newLogContinue: ld hl,sKeyName rst 20h B_CALL ChkFindSym jr c,newLogContinueNoExist B_CALL DelVarArc newLogContinueNoExist: ld hl,(wKeySize) ld de,15 or a sbc hl,de B_CALL EnoughMem jr c,errorApp ld hl,sKeyName rst 20h ld hl,(wKeySize) ld de,15 or a sbc hl,de B_CALL CreateAppVar ld a,(de) ld c,a inc de ld a,(de) ld b,a inc de ld a,26h ld (de),a inc de ld a,60h ld (de),a inc de dec bc dec bc fillLoop1: ld a,0FFh ld (de),a inc de dec bc ld a,b or c jr nz,fillLoop1 jr newLogSkip2 newLogSkip: set maybeSkip,(iy+kloggerFlags) newLogSkip2: ld hl,50 ;29; 16 bytes for VAT, 2 for identifiers, 10 for type+name, and 1 for 0 ld (wProgSize),hl B_CALL EnoughMem jr c,newLogSkipProg ;clear screen B_CALL ClrLCDFull B_CALL HomeUp ;display and store free memory ld hl,sRAMFree call PutSApp B_CALL CleanAll B_CALL MemChk ld (wMemFree),hl B_CALL DispHL ;draw softkey menu ld hl,sNewTable call SoftKey ld hl,0001h ld (curRow),hl ld hl,sRAMAfter call PutSApp newLogKeyLoopProg: ;display memory that would be left ld hl,0B01h ld (curRow),hl ld hl,(wMemFree) ld de,(wProgSize) or a sbc hl,de B_CALL DispHL ;display adjust string ld hl,20*256+3 ld (penCol),hl ld hl,sAdjustSize2 call VPutSApp push hl ld hl,26*256+3 ld (penCol),hl pop hl call VPutSApp ;display current size ld hl,0105h ld (curRow),hl ld a,Lleft B_CALL PutC ld a,5 ld (curCol),a ld hl,(wProgSize) B_CALL DispHL ld a,14 ld (curCol),a ld a,Lconvert B_CALL PutC newLogKeyLoopProg2: B_CALL GetKey cp kQuit jr z,exitApp cp kGraph jr z,exitApp cp kLeft jr z,newLogLeftProg cp kRight jr z,newLogRightProg cp kYequ jr z,newLogContinueProg cp kWindow jr z,newLogSkipProg jr newLogKeyLoopProg2 newLogLeftProg: ld hl,(wProgSize) ld de,50 or a sbc hl,de ld de,29 B_CALL cphlde jr c,newLogKeyLoopProg jr z,newLogKeyLoopProg ld hl,(wProgSize) ld de,50 or a sbc hl,de ld (wProgSize),hl jr newLogKeyLoopProg newLogRightProg: ld hl,(wProgSize) ld de,50 add hl,de ld de,(wMemFree) B_CALL cphlde jr nc,newLogKeyLoopProg jr z,newLogKeyLoopProg ld hl,(wProgSize) ld de,50 add hl,de ld (wProgSize),hl jr newLogKeyLoopProg newLogContinueProg: ld hl,sProgName rst 20h B_CALL ChkFindSym jr c,newLogContinueNoExistProg B_CALL DelVarArc newLogContinueNoExistProg: ld hl,(wProgSize) ld de,16 or a sbc hl,de B_CALL EnoughMem jr c,errorApp ld hl,sProgName rst 20h ld hl,(wProgSize) ld de,16 or a sbc hl,de B_CALL CreateAppVar ld a,(de) ld c,a inc de ld a,(de) ld b,a inc de ld a,26h ld (de),a inc de ld a,61h ld (de),a inc de dec bc dec bc fillLoop2: ld a,0FFh ld (de),a inc de dec bc ld a,b or c jr nz,fillLoop2 jr newLogSkipProg2 newLogSkipProg: bit maybeSkip,(iy+kloggerFlags) jr nz,startApp newLogSkipProg2: ld hl,getkeyHook in a,(6) B_CALL EnableRawKeyHook jr startApp stopLog: B_CALL DisableRawKeyHook res logStarted,(iy+kloggerFlags) ld hl,sKeyName rst 20h B_CALL ChkFindSym jr c,stopLogSkip ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de dec hl add hl,de ld (hl),0 stopLogSkip: ld hl,sProgName rst 20h B_CALL ChkFindSym jr c,startMenu ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de dec hl add hl,de ld (hl),0 jr startMenu errorApp: B_CALL ClrLCDFull B_CALL HomeUp ld hl,sError1 call PutSApp ld hl,sError2 B_CALL NewLine call PutSApp B_CALL NewLine B_CALL NewLine ld hl,sError3 call PutSApp B_CALL GetKey exitApp: B_CALL ClrLCDFull B_CALL HomeUp B_JUMP JForceCmdNoChar getkeyHook: db 83h ld (rawKeyHookByte),a res appSearch,(iy+kloggerFlags) ;X;locate keylog, and if it's there, search to end; if not, go to proglog ;X;if end is 0, go to proglog ;otherwise, place keypress ;if next byte is last, place 0 ;check if context and keypress are right; if not, quit ;locate proglog, and if it's there, search to end; if not, quit ;if end is 0, quit ;otherwise, place name if possible; if not, place 0 ;if less than three bytes are free, place 0 and quit ld hl,sKeyName rst 20h B_CALL ChkFindSym jr c,_findProglog ld a,b or a jr nz,_findProglog ld a,(de) ld c,a inc de ld a,(de) ld b,a _fkLoop: inc de dec bc ld a,(de) or a jr z,_findProglog ld a,b or c jr nz,_fkLoop B_CALL ChkFindSym ld a,(de) ld c,a inc de ld a,(de) ld b,a _fksLoop: inc de dec bc ld a,(de) cp 0FFh jr nz,_fksLoop dec bc ld a,(rawKeyHookByte) ld (de),a ld a,b or c jr nz,_findProglog inc de ld (de),a _findProglog: ;check if context and keypress are right; if not, quit ld a,(MenuCurrent) or a jr z,_findProglogValid cp 02h ;apps menu jr nz,_endHook call _findProglogVar jr c,_endHook ;app context ;check enter; if pressed, use (MenuCurrent+2) to look up app name and store ;if enter not pressed, check number keys and if pressed, use to look up app name (CHECK IT) and store ld a,(rawKeyHookByte) cp kEnter jr z,_appEnter cp k0 jp m,_endHook cp kCapZ+1 jp p,_endHook cp kEE jr z,_endHook cp kSpace jr z,_endHook push af B_CALL ZeroOP1 pop af cp kCapA jp p,_appLetters cp k0 jr z,_appZero sub k0 dec a jr _appContinue _appZero: ld a,10 jr _appContinue _appLetters: sub kCapA add a,11 jr _appContinue _appEnter: B_CALL ZeroOP1 ld a,(MenuCurrent+2) _appContinue: ld b,a or a jr z,_endHook _faLoop: push bc B_CALL FindAppUp pop bc jr c,_endHook djnz _faLoop ld hl,OP1 ld de,varName-1 ld bc,10 ldir set appSearch,(iy+kloggerFlags) jr _proglogStart _findProglogValid: ld a,(rawKeyHookByte) cp kEnter jr nz,_endHook ;locate proglog, and if it's there, search to end; if not, quit _proglogStart: call _findProglogVar jr c,_endHook ld a,b or a jr nz,_endHook ld a,(de) ld c,a inc de ld a,(de) ld (wKeySize),de ld h,d ld l,e add hl,bc ld (wProgSize),hl _fpLoop: inc de dec bc ld a,(de) or a jr z,_endHook ld a,b or c jr nz,_fpLoop ld de,(wKeySize) _exLoop: inc de ld a,(de) cp 0FFh jr nz,_exLoop push de ld hl,(wProgSize) or a sbc hl,de ld (wProgSize),hl pop de bit appSearch,(iy+kloggerFlags) jr nz,_skipNonApp push de B_CALL IsEditEmpty pop de jr z,_endHook push de ld hl,(editTop) ld a,(hl) cp 5Fh ;prgm token pop de jr nz,_endHook _skipNonApp: push de bit appSearch,(iy+kloggerFlags) jr nz,_skipNonApp2 ld hl,varName ld b,9 _eLoop: ld (hl),0 inc hl djnz _eLoop ld de,varName-1 ld hl,(editTop) ld b,8 _cpLoop: push de ld de,(editBtm) B_CALL cphlde pop de jr z,_cpLoopDone jr nc,_cpLoopDone push de ld de,(editCursor) B_CALL cphlde pop de jr z,_cpLoopSkip2 jr c,_cpLoopSkip _cpLoopSkip2: ld hl,(editTail) _cpLoopSkip: push de ld de,(editBtm) B_CALL cphlde pop de jr z,_cpLoopDone jr nc,_cpLoopDone ld a,(hl) ld (de),a inc hl inc de djnz _cpLoop _cpLoopDone: _skipNonApp2: ;copy name to de if possible; if not, place 0 ld hl,varName ld b,0 _strlen: ld a,(hl) or a jr z,_strlenDone inc hl inc b jr _strlen _strlenDone: ld a,b ld h,0 ld l,a ld de,(wProgSize) B_CALL cphlde pop de jr z,_placeZero jr nc,_placeZero push bc ld c,b ld b,0 ld hl,(wProgSize) or a sbc hl,bc pop bc ld (wProgSize),hl ld (de),a ld hl,varName-1 _copyLoop: inc de inc hl ld a,(hl) ld (de),a djnz _copyLoop ld bc,(wProgSize) dec bc ld a,b or c jr nz,_endHook inc de _placeZero: xor a ld (de),a _endHook: ld a,(rawKeyHookByte) or a ret _findProglogVar: ld hl,sProgName rst 20h B_CALL ChkFindSym ret SoftKey: push hl ld bc,0007h ld de,95*256+7 ld h,1 B_CALL ILine ld b,19 ld d,b ld e,0 B_CALL ILine ld b,38 ld d,b B_CALL ILine ld b,57 ld d,b B_CALL ILine ld b,76 ld d,b B_CALL ILine ld b,0 ld d,b B_CALL ILine ld b,95 ld d,b B_CALL ILine pop hl ld a,57 ld (penRow),a ld a,3 SoftKeyLoop: ld (penCol),a push af call VPutSApp pop af add a,19 cp 98 jr nz,SoftKeyLoop ret SoftKey2: ld bc,0007h ld de,95*256+7 ld h,1 B_CALL ILine ld b,38 ld d,b ld e,0 B_CALL ILine ld b,76 ld d,b B_CALL ILine ld b,0 ld d,b B_CALL ILine ld b,95 ld d,b B_CALL ILine ld hl,sKeyName rst 20h B_CALL ChkFindSym jr c,_skipKeyName ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de inc de inc de ld (wOffset),de ld (wSize),hl ld hl,57*256+11 ld (penCol),hl ld hl,sKeys call VPutSApp set keySearch,(iy+kloggerFlags) _skipKeyName: ld hl,sProgName rst 20h B_CALL ChkFindSym jr c,_skipProgName ld a,(de) ld l,a inc de ld a,(de) ld h,a inc de inc de inc de ld (wOffset),de ld (wSize),hl ld hl,57*256+48 ld (penCol),hl ld hl,sProgs call VPutSApp set progSearch,(iy+kloggerFlags) _skipProgName: ld hl,57*256+81 ld (penCol),hl ld hl,sESC jr VPutSApp PutSApp: ld a,(hl) or a ret z B_CALL PutMap ld a,(curCol) inc a ld (curCol),a inc hl jr PutSApp VPutSApp: ld a,(hl) inc hl inc a dec a ret z push hl push de B_CALL VPutMap pop de pop hl jr VPutSApp sTitle: db " KLogger v1.0",0 sMainMenu1: db "New",0 db "Stop",0 db 0 db 0 db "Exit",0 sMainMenu2: db "New",0 db 0 db 0 db 0 db "Exit",0 sLogEnabled: db "Log Enabled",0 sLogDisabled: db "Log Disabled",0 sRAMFree: db "RAM Free: ",0 sRAMAfter: db "RAM After: ",0 sAdjustSize1: db "Adjust size for key AppVar:",0 sAdjustSize2: db "Adjust size for program/",0 db "application AppVar:",0 sView: db "Select key or prog AppVar.",0 sViewMenu: sKeys: db "Keys",0 sProgs: db "Progs",0 db 0 db 0 sESC: db "ESC",0 sNewTable: db "OK",0 db "Skip",0 db 0 db 0 db "ESC",0 sError1: db "An unexpected ",0 sError2: db "error occurred.",0 sError3: db "Press any key.",0 sKeyName: db AppVarObj,"Keylog",0 sProgName: db AppVarObj,"Proglog",0 sCurProg: db ProgObj,"#",0 sHook1: db "The rawkey hook already",0 sHook2: db "exists. Overwrite it?",0 sHookTable: db "YES",0 db 0 db 0 db 0 db "NO",0 db 1 sKeyTable: db 0 db "[right]",0 db "[left]",0