From 1d5ca8034c5d20459d983be781a2bbb7e6d5ac4b Mon Sep 17 00:00:00 2001 From: v1ctor Date: Sat, 10 Oct 2015 19:20:09 -0300 Subject: [PATCH 1/8] first emscripten prot commit --- changelog.txt | 1 + inc/SDL/SDL.bi | 137 ++++++++++++++++ makefile | 6 + src/compiler/fb.bas | 15 +- src/compiler/fb.bi | 4 + src/compiler/fbc.bas | 141 ++++++++++++---- src/compiler/symb-define.bas | 3 + src/gfxlib2/js/gfx_driver.c | 216 +++++++++++++++++++++++++ src/rtlib/fb_config.h | 3 + src/rtlib/init.c | 11 ++ src/rtlib/js/drv_intl_get.c | 9 ++ src/rtlib/js/drv_intl_getdateformat.c | 9 ++ src/rtlib/js/drv_intl_getmonthname.c | 9 ++ src/rtlib/js/drv_intl_gettimeformat.c | 9 ++ src/rtlib/js/drv_intl_getweekdayname.c | 9 ++ src/rtlib/js/fb_js.h | 17 ++ src/rtlib/js/fb_private_console.h | 17 ++ src/rtlib/js/file_copy.c | 8 + src/rtlib/js/file_dir.c | 8 + src/rtlib/js/file_hlock.c | 13 ++ src/rtlib/js/file_hreset.c | 6 + src/rtlib/js/hinit.c | 28 ++++ src/rtlib/js/io_cls.c | 7 + src/rtlib/js/io_color.c | 13 ++ src/rtlib/js/io_getsize.c | 7 + src/rtlib/js/io_getx.c | 6 + src/rtlib/js/io_getxy.c | 5 + src/rtlib/js/io_gety.c | 6 + src/rtlib/js/io_inkey.c | 35 ++++ src/rtlib/js/io_input.c | 26 +++ src/rtlib/js/io_isredir.c | 6 + src/rtlib/js/io_locate.c | 8 + src/rtlib/js/io_maxrow.c | 6 + src/rtlib/js/io_mouse.c | 13 ++ src/rtlib/js/io_multikey.c | 9 ++ src/rtlib/js/io_pageset.c | 8 + src/rtlib/js/io_pcopy.c | 8 + src/rtlib/js/io_printbuff.c | 13 ++ src/rtlib/js/io_printbuff_wstr.c | 22 +++ src/rtlib/js/io_printer.c | 23 +++ src/rtlib/js/io_readstr.c | 8 + src/rtlib/js/io_readxy.c | 8 + src/rtlib/js/io_scroll.c | 7 + src/rtlib/js/io_serial.c | 35 ++++ src/rtlib/js/io_viewupdate.c | 7 + src/rtlib/js/io_width.c | 8 + src/rtlib/js/sys_beep.c | 8 + src/rtlib/js/sys_delay.c | 6 + src/rtlib/js/sys_dylib.c | 22 +++ src/rtlib/js/sys_execex.c | 6 + src/rtlib/js/sys_fmem.c | 8 + src/rtlib/js/sys_getcwd.c | 10 ++ src/rtlib/js/sys_getexename.c | 10 ++ src/rtlib/js/sys_getexepath.c | 10 ++ src/rtlib/js/sys_getshortpath.c | 8 + src/rtlib/js/sys_hshell.c | 8 + src/rtlib/js/thread_cond.c | 24 +++ src/rtlib/js/thread_core.c | 24 +++ src/rtlib/js/thread_detach.c | 9 ++ src/rtlib/js/thread_mutex.c | 20 +++ src/rtlib/js/time_setdate.c | 9 ++ src/rtlib/js/time_settime.c | 7 + src/rtlib/js/time_timer.c | 12 ++ src/rtlib/xbox/io_getsize.c | 2 + 64 files changed, 1143 insertions(+), 33 deletions(-) create mode 100644 src/gfxlib2/js/gfx_driver.c create mode 100644 src/rtlib/js/drv_intl_get.c create mode 100644 src/rtlib/js/drv_intl_getdateformat.c create mode 100644 src/rtlib/js/drv_intl_getmonthname.c create mode 100644 src/rtlib/js/drv_intl_gettimeformat.c create mode 100644 src/rtlib/js/drv_intl_getweekdayname.c create mode 100644 src/rtlib/js/fb_js.h create mode 100644 src/rtlib/js/fb_private_console.h create mode 100644 src/rtlib/js/file_copy.c create mode 100644 src/rtlib/js/file_dir.c create mode 100644 src/rtlib/js/file_hlock.c create mode 100644 src/rtlib/js/file_hreset.c create mode 100644 src/rtlib/js/hinit.c create mode 100644 src/rtlib/js/io_cls.c create mode 100644 src/rtlib/js/io_color.c create mode 100644 src/rtlib/js/io_getsize.c create mode 100644 src/rtlib/js/io_getx.c create mode 100644 src/rtlib/js/io_getxy.c create mode 100644 src/rtlib/js/io_gety.c create mode 100644 src/rtlib/js/io_inkey.c create mode 100644 src/rtlib/js/io_input.c create mode 100644 src/rtlib/js/io_isredir.c create mode 100644 src/rtlib/js/io_locate.c create mode 100644 src/rtlib/js/io_maxrow.c create mode 100644 src/rtlib/js/io_mouse.c create mode 100644 src/rtlib/js/io_multikey.c create mode 100644 src/rtlib/js/io_pageset.c create mode 100644 src/rtlib/js/io_pcopy.c create mode 100644 src/rtlib/js/io_printbuff.c create mode 100644 src/rtlib/js/io_printbuff_wstr.c create mode 100644 src/rtlib/js/io_printer.c create mode 100644 src/rtlib/js/io_readstr.c create mode 100644 src/rtlib/js/io_readxy.c create mode 100644 src/rtlib/js/io_scroll.c create mode 100644 src/rtlib/js/io_serial.c create mode 100644 src/rtlib/js/io_viewupdate.c create mode 100644 src/rtlib/js/io_width.c create mode 100644 src/rtlib/js/sys_beep.c create mode 100644 src/rtlib/js/sys_delay.c create mode 100644 src/rtlib/js/sys_dylib.c create mode 100644 src/rtlib/js/sys_execex.c create mode 100644 src/rtlib/js/sys_fmem.c create mode 100644 src/rtlib/js/sys_getcwd.c create mode 100644 src/rtlib/js/sys_getexename.c create mode 100644 src/rtlib/js/sys_getexepath.c create mode 100644 src/rtlib/js/sys_getshortpath.c create mode 100644 src/rtlib/js/sys_hshell.c create mode 100644 src/rtlib/js/thread_cond.c create mode 100644 src/rtlib/js/thread_core.c create mode 100644 src/rtlib/js/thread_detach.c create mode 100644 src/rtlib/js/thread_mutex.c create mode 100644 src/rtlib/js/time_setdate.c create mode 100644 src/rtlib/js/time_settime.c create mode 100644 src/rtlib/js/time_timer.c diff --git a/changelog.txt b/changelog.txt index ca68876b5b..b6eaf3c342 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ Version 1.05.0 [changed] [added] +- emscripten port (WIP) [fixed] - 0.90.0 regression: Self-op optimizations stopped handling some cases and should now work again, for example: optimizing A=A+1 => A+=1 where A is a Long, should give nice ASM code with -gen gas again diff --git a/inc/SDL/SDL.bi b/inc/SDL/SDL.bi index 334f017b7f..dfb4cbb7c8 100644 --- a/inc/SDL/SDL.bi +++ b/inc/SDL/SDL.bi @@ -1106,6 +1106,7 @@ const SDL_PRESSED = 1 type SDL_EventType as long enum +#ifndef __FB_JS__ SDL_NOEVENT = 0 SDL_ACTIVEEVENT SDL_KEYDOWN @@ -1132,11 +1133,52 @@ enum SDL_EVENT_RESERVED7 SDL_USEREVENT = 24 SDL_NUMEVENTS = 32 +#else + SDL_NOEVENT = 0 + SDL_FIRSTEVENT = 0 + SDL_QUIT_ = &h100 + SDL_WINDOWEVENT = &h200 + SDL_SYSWMEVENT + SDL_KEYDOWN = &h300 + SDL_KEYUP + SDL_TEXTEDITING + SDL_TEXTINPUT + SDL_MOUSEMOTION = &h400 + SDL_MOUSEBUTTONDOWN + SDL_MOUSEBUTTONUP + SDL_MOUSEWHEEL + SDL_INPUTMOTION = &h500 + SDL_INPUTBUTTONDOWN + SDL_INPUTBUTTONUP + SDL_INPUTWHEEL + SDL_INPUTPROXIMITYIN + SDL_INPUTPROXIMITYOUT + SDL_JOYAXISMOTION = &h600 + SDL_JOYBALLMOTION + SDL_JOYHATMOTION + SDL_JOYBUTTONDOWN + SDL_JOYBUTTONUP + SDL_FINGERDOWN = &h700 + SDL_FINGERUP + SDL_FINGERMOTION + SDL_TOUCHBUTTONDOWN + SDL_TOUCHBUTTONUP + SDL_DOLLARGESTURE = &h800 + SDL_DOLLARRECORD + SDL_MULTIGESTURE + SDL_CLIPBOARDUPDATE = &h900 + SDL_EVENT_COMPAT1 = &h7000 + SDL_EVENT_COMPAT2 + SDL_EVENT_COMPAT3 + SDL_USEREVENT = &h8000 + SDL_LASTEVENT = &hFFFF +#endif end enum #define SDL_EVENTMASK(X) (1 shl (X)) type SDL_EventMask_ as long +#ifndef __FB_JS__ enum SDL_ACTIVEEVENTMASK = SDL_EVENTMASK(SDL_ACTIVEEVENT) SDL_KEYDOWNMASK = SDL_EVENTMASK(SDL_KEYDOWN) @@ -1157,72 +1199,148 @@ enum SDL_QUITMASK = SDL_EVENTMASK(SDL_QUIT_) SDL_SYSWMEVENTMASK = SDL_EVENTMASK(SDL_SYSWMEVENT) end enum +#endif const SDL_ALLEVENTS = &hFFFFFFFF type SDL_ActiveEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif gain as Uint8 state as Uint8 end type type SDL_KeyboardEvent +#ifndef __FB_JS__ as Uint8 type which as Uint8 state as Uint8 +#else + as Uint32 type + windowID as Uint32 + state as Uint8 + repeat as Uint8 + padding2 as Uint8 + padding3 as Uint8 +#endif keysym as SDL_keysym end type type SDL_MouseMotionEvent +#ifndef __FB_JS__ as Uint8 type which as Uint8 state as Uint8 x as Uint16 y as Uint16 +#else + as Uint32 type + timestamp as Uint32 + windowID as Uint32 + which as Uint32 + state as Uint32 + x as Sint16 + y as Sint16 +#endif xrel as Sint16 yrel as Sint16 end type type SDL_MouseButtonEvent +#ifndef __FB_JS__ as Uint8 type which as Uint8 button as Uint8 state as Uint8 x as Uint16 y as Uint16 +#else + as Uint32 type + timestamp as Uint32 + windowID as Uint32 + which as Uint32 + button as Uint8 + state as Uint8 + padding1 as Uint8 + padding2 as Uint8 + x as Sint16 + y as Sint16 +#endif end type type SDL_JoyAxisEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif which as Uint8 axis as Uint8 +#ifndef __FB_JS__ value as Sint16 +#else + padding1 as Uint8 + padding2 as Uint8 + value as integer +#endif end type type SDL_JoyBallEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif which as Uint8 ball as Uint8 +#ifndef __FB_JS__ xrel as Sint16 yrel as Sint16 +#else + padding1 as Uint8 + padding2 as Uint8 + xrel as integer + yrel as integer +#endif end type type SDL_JoyHatEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif which as Uint8 hat as Uint8 value as Uint8 +#ifdef __FB_JS__ + as Uint8 padding1 +#endif end type type SDL_JoyButtonEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif which as Uint8 button as Uint8 state as Uint8 +#ifdef __FB_JS__ + as Uint8 padding1 +#endif end type type SDL_ResizeEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif w as long h as long end type @@ -1232,11 +1350,20 @@ type SDL_ExposeEvent end type type SDL_QuitEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif end type type SDL_UserEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type + windowID as Uint32 +#endif code as long data1 as any ptr data2 as any ptr @@ -1245,12 +1372,20 @@ end type type SDL_SysWMmsg as SDL_SysWMmsg_ type SDL_SysWMEvent +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif msg as SDL_SysWMmsg ptr end type union SDL_Event +#ifndef __FB_JS__ as Uint8 type +#else + as Uint32 type +#endif active as SDL_ActiveEvent key as SDL_KeyboardEvent motion as SDL_MouseMotionEvent @@ -1276,10 +1411,12 @@ enum end enum declare function SDL_PeepEvents(byval events as SDL_Event ptr, byval numevents as long, byval action as SDL_eventaction, byval mask as Uint32) as long +#ifndef __FB_JS__ private function SDL_QuitRequested() as SDL_bool SDL_PumpEvents() function = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_QUITMASK) end function +#endif declare function SDL_PollEvent(byval event as SDL_Event ptr) as long declare function SDL_WaitEvent(byval event as SDL_Event ptr) as long declare function SDL_PushEvent(byval event as SDL_Event ptr) as long diff --git a/makefile b/makefile index 9eb77a0b01..b39b4b6bb4 100644 --- a/makefile +++ b/makefile @@ -197,6 +197,12 @@ ifdef TARGET ifneq ($(filter xbox%,$(triplet)),) TARGET_OS := xbox endif + ifneq ($(filter emscripten%,$(triplet)),) + TARGET_OS := js + AS = llvm-as + AR = emar + CC = emcc + endif endif ifndef TARGET_ARCH diff --git a/src/compiler/fb.bas b/src/compiler/fb.bas index b8657cf337..a06636c6f7 100644 --- a/src/compiler/fb.bas +++ b/src/compiler/fb.bas @@ -178,6 +178,15 @@ dim shared as FBTARGET targetinfo(0 to FB_COMPTARGETS-1) = _ 0 or FB_TARGETOPT_UNIX _ or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _ or FB_TARGETOPT_RETURNINREGS _ + ), _ + ( _ + @"js", _ + FB_DATATYPE_USHORT, _ '' wchar + FB_FUNCMODE_CDECL, _ + FB_FUNCMODE_STDCALL_MS, _ + 0 or FB_TARGETOPT_UNIX _ + or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _ + or FB_TARGETOPT_RETURNINREGS _ ) _ } @@ -191,7 +200,8 @@ dim shared as FBCPUFAMILYINFO cpufamilyinfo(0 to FB_CPUFAMILY__COUNT-1) = _ (@"x86" , FB_DEFAULT_CPUTYPE_X86 ), _ (@"x86_64" , FB_DEFAULT_CPUTYPE_X86_64 ), _ (@"arm" , FB_DEFAULT_CPUTYPE_ARM ), _ - (@"aarch64", FB_DEFAULT_CPUTYPE_AARCH64) _ + (@"aarch64", FB_DEFAULT_CPUTYPE_AARCH64), _ + (@"asmjs" , FB_DEFAULT_CPUTYPE_ASMJS ) _ } type FBCPUTYPEINFO @@ -219,7 +229,8 @@ dim shared as FBCPUTYPEINFO cputypeinfo(0 to FB_CPUTYPE__COUNT-1) = _ ( NULL , @"x86-64" , FB_CPUFAMILY_X86_64 , 64 ), _ '' FB_CPUTYPE_X86_64 ( NULL , @"armv6" , FB_CPUFAMILY_ARM , 32 ), _ '' FB_CPUTYPE_ARMV6 ( NULL , @"armv7-a" , FB_CPUFAMILY_ARM , 32 ), _ '' FB_CPUTYPE_ARMV7A - ( NULL , @"aarch64" , FB_CPUFAMILY_AARCH64, 64 ) _ '' FB_CPUTYPE_AARCH64 + ( NULL , @"aarch64" , FB_CPUFAMILY_AARCH64, 64 ), _ '' FB_CPUTYPE_AARCH64 + ( NULL , @"asmjs" , FB_CPUFAMILY_ASMJS , 32 ) _ '' FB_CPUTYPE_ASMJS } '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/src/compiler/fb.bi b/src/compiler/fb.bi index 759edc290a..61a92c34b9 100644 --- a/src/compiler/fb.bi +++ b/src/compiler/fb.bi @@ -131,6 +131,7 @@ enum FB_CPUTYPE FB_CPUTYPE_ARMV6 FB_CPUTYPE_ARMV7A FB_CPUTYPE_AARCH64 + FB_CPUTYPE_ASMJS FB_CPUTYPE__COUNT end enum @@ -139,6 +140,7 @@ enum FB_CPUFAMILY_X86_64 FB_CPUFAMILY_ARM FB_CPUFAMILY_AARCH64 + FB_CPUFAMILY_ASMJS FB_CPUFAMILY__COUNT end enum @@ -187,6 +189,7 @@ enum FB_COMPTARGET FB_COMPTARGET_OPENBSD FB_COMPTARGET_DARWIN FB_COMPTARGET_NETBSD + FB_COMPTARGET_JS FB_COMPTARGETS end enum @@ -333,6 +336,7 @@ const FB_DEFAULT_CPUTYPE_X86 = FB_CPUTYPE_486 const FB_DEFAULT_CPUTYPE_X86_64 = FB_CPUTYPE_X86_64 const FB_DEFAULT_CPUTYPE_ARM = FB_CPUTYPE_ARMV7A const FB_DEFAULT_CPUTYPE_AARCH64 = FB_CPUTYPE_AARCH64 +const FB_DEFAULT_CPUTYPE_ASMJS = FB_CPUTYPE_ASMJS #ifdef __FB_ARM__ const FB_DEFAULT_CPUTYPE32 = FB_DEFAULT_CPUTYPE_ARM diff --git a/src/compiler/fbc.bas b/src/compiler/fbc.bas index 13ce319ddf..2d7cb5c6f5 100644 --- a/src/compiler/fbc.bas +++ b/src/compiler/fbc.bas @@ -120,12 +120,28 @@ enum FBCTOOL_GORC FBCTOOL_WINDRES FBCTOOL_CXBE + FBCTOOL_EMAS + FBCTOOL_EMAR + FBCTOOL_EMLD + FBCTOOL_EMCC FBCTOOL__COUNT end enum -static shared as zstring * 8 toolnames(0 to FBCTOOL__COUNT-1) = _ +static shared as zstring * 16 toolnames(0 to FBCTOOL__COUNT-1) = _ { _ - "as", "ar", "ld", "gcc", "llc", "dlltool", "GoRC", "windres", "cxbe" _ + "as", _ + "ar", _ + "ld", _ + "gcc", _ + "llc", _ + "dlltool", _ + "GoRC", _ + "windres", _ + "cxbe", _ + "llvm-as", _ + "emar", _ + "emcc", _ + "emcc" _ } declare sub fbcFindBin _ @@ -198,6 +214,8 @@ private sub hSetOutName( ) '' Note: XBox target creates an .exe first, '' then uses cxbe to turn it into an .xbe later fbc.outname += ".exe" + case FB_COMPTARGET_JS + fbc.outname += ".html" end select case FB_OUTTYPE_DYNAMICLIB select case( fbGetOption( FB_COMPOPT_TARGET ) ) @@ -357,7 +375,11 @@ sub fbcFindBin _ #ifndef ENABLE_STANDALONE if( hFileExists( path ) = FALSE ) then '' c) Rely on PATH - path = fbc.targetprefix + toolnames(tool) + FB_HOST_EXEEXT + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + path = fbc.targetprefix + toolnames(tool) + FB_HOST_EXEEXT + else + path = toolnames(tool) + end if relying_on_system = TRUE end if #endif @@ -655,6 +677,9 @@ private function hLinkFiles( ) as integer case FB_COMPTARGET_XBOX ldcline += " -nostdlib --file-alignment 0x20 --section-alignment 0x20 -shared" + case FB_COMPTARGET_JS + ldcline += " -O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + ldcline += " -Wno-warn-absolute-paths -s LEGACY_GL_EMULATION=1 -s ALLOW_MEMORY_GROWTH=1" end select if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) then @@ -664,8 +689,10 @@ private function hLinkFiles( ) as integer '' (needed until binutils' default DJGPP ldscripts are fixed) ldcline += " -T """ + fbc.libpath + (FB_HOST_PATHDIV + "i386go32.x""") else - '' Supplementary ld script to drop the fbctinf objinfo section - ldcline += " """ + fbc.libpath + (FB_HOST_PATHDIV + "fbextra.x""") + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + '' Supplementary ld script to drop the fbctinf objinfo section + ldcline += " """ + fbc.libpath + (FB_HOST_PATHDIV + "fbextra.x""") + end if end if select case as const fbGetOption( FB_COMPOPT_TARGET ) @@ -703,15 +730,25 @@ private function hLinkFiles( ) as integer if( fbGetOption( FB_COMPOPT_DEBUG ) = FALSE ) then if( fbGetOption( FB_COMPOPT_PROFILE ) = FALSE ) then - ldcline += " -s" + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ldcline += " -s" + end if end if end if '' Add the library search paths scope dim as TSTRSETITEM ptr i = listGetHead(@fbc.finallibpaths.list) + + dim as string L + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + L = " -L """ + else + L = " -L""" + end if + while (i) - ldcline += " -L """ + i->s + """" + ldcline += L + i->s + """" i = listGetNext(i) wend end scope @@ -792,13 +829,16 @@ private function hLinkFiles( ) as integer end select if( fbc.nodeflibs = FALSE ) then - ldcline += " """ + fbc.libpath + FB_HOST_PATHDIV - if( fbGetOption( FB_COMPOPT_PIC ) ) then - ldcline += "fbrt0pic.o" - else - ldcline += "fbrt0.o" + '' don't add the fbrt0 if compiling for javascript, because global constructors and destructors are not supported by emscripten + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ldcline += " """ + fbc.libpath + FB_HOST_PATHDIV + if( fbGetOption( FB_COMPOPT_PIC ) ) then + ldcline += "fbrt0pic.o" + else + ldcline += "fbrt0.o" + end if + ldcline += """" end if - ldcline += """" end if scope @@ -813,7 +853,9 @@ private function hLinkFiles( ) as integer '' All libraries are passed inside -( -) so we don't need to worry as '' much about their order and/or listing them repeatedly. if ( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN ) then - ldcline += " ""-(""" + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ldcline += " ""-(""" + end if end if '' Add libraries passed by file name @@ -842,8 +884,12 @@ private function hLinkFiles( ) as integer end scope if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then - '' End of lib group - ldcline += " ""-)""" + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + '' End of lib group + ldcline += " ""-)""" + else + ldcline += " -lfb" + end if end if '' crt end @@ -918,7 +964,12 @@ private function hLinkFiles( ) as integer #endif '' invoke ld - if( fbcRunBin( "linking", FBCTOOL_LD, ldcline ) = FALSE ) then + var ld = FBCTOOL_LD + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then + ld = FBCTOOL_EMLD + end if + + if( fbcRunBin( "linking", ld, ldcline ) = FALSE ) then exit function end if @@ -2414,7 +2465,11 @@ private function hGetAsmName _ '' Based on the objfile name so it's also affected by -o asmfile = hStripExt( *module->objfile ) - ext = @".asm" + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ext = @".asm" + else + ext = @".llvm" + end if if( stage = 1 ) then select case( fbGetOption( FB_COMPOPT_BACKEND ) ) @@ -2742,10 +2797,12 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege ln += "-m64 " end select - if( fbc.cputype_is_native ) then - ln += "-march=native " - else - ln += "-march=" + *fbGetGccArch( ) + " " + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + if( fbc.cputype_is_native ) then + ln += "-march=native " + else + ln += "-march=" + *fbGetGccArch( ) + " " + end if end if if( fbGetOption( FB_COMPOPT_PIC ) ) then @@ -2753,8 +2810,13 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege end if ln += "-S -nostdlib -nostdinc -Wall -Wno-unused-label " + _ - "-Wno-unused-function -Wno-unused-variable " + _ - "-Wno-unused-but-set-variable " + "-Wno-unused-function -Wno-unused-variable " + + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ln += "-Wno-unused-but-set-variable " + else + ln += "-Wno-warn-absolute-paths -s LEGACY_GL_EMULATION=1 " + end if '' Don't warn about non-standard main() signature '' (we emit "ubyte **argv" instead of "char **argv") @@ -2763,13 +2825,17 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege '' helps finding ir-hlc bugs ln += "-Werror-implicit-function-declaration " - ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " " + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " " + end if '' Do not let gcc make assumptions about pointers; FB isn't strict about it. ln += "-fno-strict-aliasing " '' The rtlib sets its own rounding mode, don't let gcc make assumptions. - ln += "-frounding-math " + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ln += "-frounding-math " + end if '' ? ln += "-fno-math-errno " @@ -2833,7 +2899,11 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege select case( fbGetOption( FB_COMPOPT_BACKEND ) ) case FB_BACKEND_GCC - function = fbcRunBin( "compiling C", FBCTOOL_GCC, ln ) + var gcc = FBCTOOL_GCC + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then + gcc = FBCTOOL_EMCC + end if + function = fbcRunBin( "compiling C", gcc, ln ) case FB_BACKEND_LLVM function = fbcRunBin( "compiling LLVM IR", FBCTOOL_LLC, ln ) end select @@ -2869,14 +2939,21 @@ private function hAssembleModule( byval module as FBCIOFILE ptr ) as integer if( fbGetOption( FB_COMPOPT_DEBUG ) = FALSE ) then if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then - ln += "--strip-local-absolute " + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + ln += "--strip-local-absolute " + end if endif end if ln += """" + hGetAsmName( module, 2 ) + """ " ln += "-o """ + *module->objfile + """" ln += fbc.extopt.gas - - if( fbcRunBin( "assembling", FBCTOOL_AS, ln ) = FALSE ) then + + var gas = FBCTOOL_AS + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then + gas = FBCTOOL_EMAS + end if + + if( fbcRunBin( "assembling", gas, ln ) = FALSE ) then exit function end if @@ -3058,7 +3135,9 @@ private sub hSetDefaultLibPaths( ) '' Add gcc's private lib directory, to find libgcc '' This is for installing into Unix-like systems, and not for '' standalone, which has libgcc in the main lib/. - fbcAddLibPathFor( "libgcc.a" ) + if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then + fbcAddLibPathFor( "libgcc.a" ) + end if select case( fbGetOption( FB_COMPOPT_TARGET ) ) case FB_COMPTARGET_DOS diff --git a/src/compiler/symb-define.bas b/src/compiler/symb-define.bas index 2554d3b03e..a5babfb31d 100644 --- a/src/compiler/symb-define.bas +++ b/src/compiler/symb-define.bas @@ -238,6 +238,9 @@ sub symbDefineInit _ '' Add __FB___ define symbAddDefine( "__FB_" + ucase( *env.target.id ) + "__", NULL, 0 ) + if( env.clopt.target = FB_COMPTARGET_JS ) then + symbAddDefine( @"__FB_LINUX__", NULL, 0 ) + end if '' add __FB_UNIX__ / __FB_PCOS__ defines, as necessary if( env.target.options and FB_TARGETOPT_UNIX ) then diff --git a/src/gfxlib2/js/gfx_driver.c b/src/gfxlib2/js/gfx_driver.c new file mode 100644 index 0000000000..c67feddd1e --- /dev/null +++ b/src/gfxlib2/js/gfx_driver.c @@ -0,0 +1,216 @@ +/* asmjs fbgfx driver */ + +#include "../fb_gfx.h" +#include +#include + +#define SCREENLIST(w, h) ((h) | (w) << 16) + +#define GFX_JS_FPS 60 + +static void driver_exit(void); + +typedef struct JS_GFXDRIVER_CTX_ +{ + int inited; + int changingScreen; + int updated ; + SDL_Surface *canvas; +} JS_GFXDRIVER_CTX; + +static JS_GFXDRIVER_CTX __js_ctx = { 0, 0, 0, NULL }; + +static void driver_blit() +{ + SDL_Surface *tmp = SDL_CreateRGBSurfaceFrom( + __fb_gfx->framebuffer, + __fb_gfx->w, __fb_gfx->h, __fb_gfx->depth, __fb_gfx->pitch, + 0x0f00, 0x00f0, 0x000f, 0xf000); + + SDL_BlitSurface(tmp, NULL, __js_ctx.canvas, NULL); + + SDL_FreeSurface(tmp); + + SDL_Flip(__js_ctx.canvas); +} + +static void driver_update(void *unused) +{ + if( !__js_ctx.inited || __fb_gfx == NULL || __fb_gfx->framebuffer == NULL ) + return; + + if( !__js_ctx.changingScreen ) + { + driver_blit(); + + SDL_PumpEvents(); + + __js_ctx.updated = 1; + } + + emscripten_async_call(driver_update, NULL, 1000/GFX_JS_FPS); +} + +static void fb_js_kb_init(void) +{ + __fb_ctx.hooks.inkeyproc = NULL; + __fb_ctx.hooks.getkeyproc = NULL; + __fb_ctx.hooks.keyhitproc = NULL; + __fb_ctx.hooks.multikeyproc = NULL; + __fb_ctx.hooks.sleepproc = NULL; + + return; +} + + +static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rate, int flags) +{ + if( w == 0 || h == 0 || depth_arg == 0 ) + return 0; + + __js_ctx.changingScreen = TRUE; + + if( !__js_ctx.inited ) + SDL_Init(SDL_INIT_VIDEO); + + if( __js_ctx.canvas != NULL ) + SDL_FreeSurface(__js_ctx.canvas); + + __js_ctx.canvas = SDL_SetVideoMode(w, h, 32, SDL_HWSURFACE); + + // in JS we should not hook the key routines + fb_js_kb_init(); + + __js_ctx.changingScreen = FALSE; + int was_inited = __js_ctx.inited; + __js_ctx.inited = TRUE; + + if( !was_inited ) + { + __js_ctx.updated = 0; + emscripten_async_call(driver_update, NULL, 1000/GFX_JS_FPS); + } + + return 0; +} + +static void driver_exit(void) +{ + if( __js_ctx.inited ) + { + __js_ctx.inited = FALSE; + + if( __js_ctx.updated == 0 ) + driver_blit(); + + if( __js_ctx.canvas != NULL ) + { + SDL_FreeSurface(__js_ctx.canvas); + __js_ctx.canvas = NULL; + } + + SDL_Quit(); + } +} + +static void driver_lock(void) +{ + /* !!!WRITEME!!! */ +} + +static void driver_unlock(void) +{ + /* !!!WRITEME!!! */ +} + +static void driver_set_palette(int index, int r, int g, int b) +{ + /* !!!WRITEME!!! */ +} + +static void driver_wait_vsync(void) +{ + /* !!!WRITEME!!! */ +} + +static int driver_get_mouse(int *x, int *y, int *z, int *buttons, int *clip) +{ + /* !!!WRITEME!!! */ + return 0; +} + +static void driver_set_mouse(int x, int y, int cursor, int clip) +{ + /* !!!WRITEME!!! */ +} + +static int *driver_fetch_modes(int depth, int *size) +{ + int num = 0; + int *modes = NULL, *new_modes; + + ++num; + new_modes = realloc(modes, sizeof(int) * num); + if (!new_modes) { + *size = num - 1; + return modes; + } + + modes = new_modes; + modes[num - 1] = SCREENLIST(320, 200); + + *size = num; + return modes; +} + +static void driver_poll_events(void) +{ + /* !!!WRITEME!!! */ +} + +static const GFXDRIVER fb_gfxDriverJS = +{ + "asmjs", /* char *name; */ + driver_init, /* int (*init)(char *title, int w, int h, int depth, int refresh_rate, int flags); */ + driver_exit, /* void (*exit)(void); */ + driver_lock, /* void (*lock)(void); */ + driver_unlock, /* void (*unlock)(void); */ + driver_set_palette, /* void (*set_palette)(int index, int r, int g, int b); */ + driver_wait_vsync, /* void (*wait_vsync)(void); */ + driver_get_mouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */ + driver_set_mouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */ + NULL, /* void (*set_window_title)(char *title); */ + NULL, /* int (*set_window_pos)(int x, int y); */ + driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */ + NULL, /* void (*flip)(void); */ + driver_poll_events /* void (*poll_events)(void); */ +}; + +const GFXDRIVER *__fb_gfx_drivers_list[] = { + &fb_gfxDriverJS, + NULL +}; + +void fb_hScreenInfo(ssize_t *width, ssize_t *height, ssize_t *depth, ssize_t *refresh) +{ + *width = __fb_gfx->w; + *height = __fb_gfx->h; + *depth = __fb_gfx->depth; + *refresh = GFX_JS_FPS; +} + +FBCALL int fb_GfxGetJoystick(int id, ssize_t *buttons, float *a1, float *a2, float *a3, float *a4, float *a5, float *a6, float *a7, float *a8) +{ + FB_GRAPHICS_LOCK( ); + + *buttons = -1; + *a1 = *a2 = *a3 = *a4 = *a5 = *a6 = *a7 = *a8 = -1000.0f; + + if ((id < 0) || (id >= 4)) { + FB_GRAPHICS_UNLOCK( ); + return fb_ErrorSetNum(FB_RTERROR_ILLEGALFUNCTIONCALL); + } + + FB_GRAPHICS_UNLOCK( ); + return fb_ErrorSetNum( FB_RTERROR_OK ); +} diff --git a/src/rtlib/fb_config.h b/src/rtlib/fb_config.h index 3be8f0c7c9..74f7ef7340 100644 --- a/src/rtlib/fb_config.h +++ b/src/rtlib/fb_config.h @@ -35,6 +35,9 @@ #elif (defined sun || defined __sun) && defined __SVR4 #define HOST_SOLARIS #define HOST_UNIX +#elif defined __EMSCRIPTEN__ + #define HOST_JS + #define HOST_UNIX #else #error "Couldn't identify target system!" #endif diff --git a/src/rtlib/init.c b/src/rtlib/init.c index 6866fd792b..75706df255 100644 --- a/src/rtlib/init.c +++ b/src/rtlib/init.c @@ -106,6 +106,11 @@ FBCALL void fb_Init( int argc, char **argv, int lang ) __fb_ctx.argc = argc; __fb_ctx.argv = argv; __fb_ctx.lang = lang; + +#ifdef HOST_JS + // global constructors and destructors are not supported by emscripten + fb_hRtInit(); +#endif // HOST_JS } /* called by FB program, @@ -114,5 +119,11 @@ FBCALL void fb_End( int errlevel ) { if( __fb_ctx.exit_gfxlib2 ) __fb_ctx.exit_gfxlib2( ); + +#ifdef HOST_JS + // global constructors and destructors are not supported by emscripten + fb_hRtExit(); +#endif // HOST_JS + exit( errlevel ); } diff --git a/src/rtlib/js/drv_intl_get.c b/src/rtlib/js/drv_intl_get.c new file mode 100644 index 0000000000..64202e6693 --- /dev/null +++ b/src/rtlib/js/drv_intl_get.c @@ -0,0 +1,9 @@ +/* get i18n data */ + +#include "../fb.h" + +const char *fb_DrvIntlGet( eFbIntlIndex Index ) +{ + /* No I18N information available */ + return NULL; +} diff --git a/src/rtlib/js/drv_intl_getdateformat.c b/src/rtlib/js/drv_intl_getdateformat.c new file mode 100644 index 0000000000..1cdd24ca6e --- /dev/null +++ b/src/rtlib/js/drv_intl_getdateformat.c @@ -0,0 +1,9 @@ +/* get localized short DATE format */ + +#include "../fb.h" + +int fb_DrvIntlGetDateFormat( char *buffer, size_t len ) +{ + /* No localized date format available! */ + return FALSE; +} diff --git a/src/rtlib/js/drv_intl_getmonthname.c b/src/rtlib/js/drv_intl_getmonthname.c new file mode 100644 index 0000000000..fe5d71e21a --- /dev/null +++ b/src/rtlib/js/drv_intl_getmonthname.c @@ -0,0 +1,9 @@ +/* get localized month name */ + +#include "../fb.h" + +FBSTRING *fb_DrvIntlGetMonthName( int month, int short_names ) +{ + /* No localized month name available */ + return NULL; +} diff --git a/src/rtlib/js/drv_intl_gettimeformat.c b/src/rtlib/js/drv_intl_gettimeformat.c new file mode 100644 index 0000000000..efb7330a01 --- /dev/null +++ b/src/rtlib/js/drv_intl_gettimeformat.c @@ -0,0 +1,9 @@ +/* get localized short TIME format */ + +#include "../fb.h" + +int fb_DrvIntlGetTimeFormat( char *buffer, size_t len ) +{ + /* No localized time format available! */ + return FALSE; +} diff --git a/src/rtlib/js/drv_intl_getweekdayname.c b/src/rtlib/js/drv_intl_getweekdayname.c new file mode 100644 index 0000000000..12880dfd84 --- /dev/null +++ b/src/rtlib/js/drv_intl_getweekdayname.c @@ -0,0 +1,9 @@ +/* get localized weekday name */ + +#include "../fb.h" + +FBSTRING *fb_DrvIntlGetWeekdayName( int weekday, int short_names ) +{ + /* No localized weekday name available */ + return NULL; +} diff --git a/src/rtlib/js/fb_js.h b/src/rtlib/js/fb_js.h new file mode 100644 index 0000000000..0fe7ab5c41 --- /dev/null +++ b/src/rtlib/js/fb_js.h @@ -0,0 +1,17 @@ +#define FBCALL __stdcall + +/* newline for console/file I/O */ +#define FB_NEWLINE "\r\n" +#define FB_NEWLINE_WSTR _LC("\r\n") + +/* newline for printer I/O */ +#define FB_BINARY_NEWLINE "\r\n" +#define FB_BINARY_NEWLINE_WSTR _LC("\r\n") +#define FB_LL_FMTMOD "ll" +#define FB_CONSOLE_MAXPAGES 1 +#define FB_DYLIB HANDLE + +typedef long fb_off_t; +#define fseeko(stream, offset, whence) fseek(stream, offset, whence) +#define ftello(stream) ftell(stream) + diff --git a/src/rtlib/js/fb_private_console.h b/src/rtlib/js/fb_private_console.h new file mode 100644 index 0000000000..9cf2535a7a --- /dev/null +++ b/src/rtlib/js/fb_private_console.h @@ -0,0 +1,17 @@ +#include +#include + +#define KEY_BUFFER_LEN 256 + +typedef struct _FB_CONSOLE_CTX { + int active, visible; + int w, h; + unsigned long key_buffer[KEY_BUFFER_LEN]; + int key_head; + int key_tail; +} FB_CONSOLE_CTX; + +extern FB_CONSOLE_CTX __fb_con; + +extern EM_BOOL fb_hKeyPressedCB(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); + diff --git a/src/rtlib/js/file_copy.c b/src/rtlib/js/file_copy.c new file mode 100644 index 0000000000..9759b49c12 --- /dev/null +++ b/src/rtlib/js/file_copy.c @@ -0,0 +1,8 @@ +/* file copy */ + +#include "../fb.h" + +FBCALL int fb_FileCopy( const char *source, const char *destination ) +{ + return fb_CrtFileCopy( source, destination ); +} diff --git a/src/rtlib/js/file_dir.c b/src/rtlib/js/file_dir.c new file mode 100644 index 0000000000..5115f080cd --- /dev/null +++ b/src/rtlib/js/file_dir.c @@ -0,0 +1,8 @@ +/* dir() */ + +#include "../fb.h" + +FBCALL FBSTRING *fb_Dir( FBSTRING *filespec, int attrib, int *out_attrib ) +{ + return &__fb_ctx.null_desc; +} diff --git a/src/rtlib/js/file_hlock.c b/src/rtlib/js/file_hlock.c new file mode 100644 index 0000000000..22f7e337db --- /dev/null +++ b/src/rtlib/js/file_hlock.c @@ -0,0 +1,13 @@ +/* low-level lock and unlock functions */ + +#include "../fb.h" + +int fb_hFileLock( FILE *f, fb_off_t inipos, fb_off_t size ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILEIO ); +} + +int fb_hFileUnlock( FILE *f, fb_off_t inipos, fb_off_t size ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILEIO ); +} diff --git a/src/rtlib/js/file_hreset.c b/src/rtlib/js/file_hreset.c new file mode 100644 index 0000000000..303afca519 --- /dev/null +++ b/src/rtlib/js/file_hreset.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +int fb_hFileResetEx( int streamno ) +{ + return FALSE; +} diff --git a/src/rtlib/js/hinit.c b/src/rtlib/js/hinit.c new file mode 100644 index 0000000000..84f6e4768e --- /dev/null +++ b/src/rtlib/js/hinit.c @@ -0,0 +1,28 @@ +/* libfb initialization for js */ + +#include "../fb.h" +#include "fb_private_console.h" +#include +#include + +FB_CONSOLE_CTX __fb_con; + +#ifdef ENABLE_MT +FBCALL void fb_Lock( void ) { return; } +FBCALL void fb_Unlock( void ) { return; } +FBCALL void fb_StrLock( void ) { return; } +FBCALL void fb_StrUnlock( void ) { return; } +FBCALL void fb_GraphicsLock ( void ) { return; } +FBCALL void fb_GraphicsUnlock( void ) { return; } +#endif + +void fb_hInit( void ) +{ + memset( &__fb_con, 0, sizeof(__fb_con) ); + + emscripten_set_keypress_callback( 0, 0, 1, fb_hKeyPressedCB ); +} + +void fb_hEnd( int unused ) +{ +} diff --git a/src/rtlib/js/io_cls.c b/src/rtlib/js/io_cls.c new file mode 100644 index 0000000000..24efcc10be --- /dev/null +++ b/src/rtlib/js/io_cls.c @@ -0,0 +1,7 @@ +/* console CLS statement */ + +#include "../fb.h" + +void fb_ConsoleClear( int mode ) +{ +} diff --git a/src/rtlib/js/io_color.c b/src/rtlib/js/io_color.c new file mode 100644 index 0000000000..24f6ae14a1 --- /dev/null +++ b/src/rtlib/js/io_color.c @@ -0,0 +1,13 @@ +/* console COLOR statement */ + +#include "../fb.h" + +int fb_ConsoleColor( int fc, int bc, int flags ) +{ + return 0; +} + +int fb_ConsoleGetColorAtt( void ) +{ + return 0; +} diff --git a/src/rtlib/js/io_getsize.c b/src/rtlib/js/io_getsize.c new file mode 100644 index 0000000000..2d9eb1415f --- /dev/null +++ b/src/rtlib/js/io_getsize.c @@ -0,0 +1,7 @@ +#include "../fb.h" + +FBCALL void fb_ConsoleGetSize( int *cols, int *rows ) +{ + *cols = 80; + *rows = 25; +} diff --git a/src/rtlib/js/io_getx.c b/src/rtlib/js/io_getx.c new file mode 100644 index 0000000000..49604ae5fa --- /dev/null +++ b/src/rtlib/js/io_getx.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +int fb_ConsoleGetX( void ) +{ + return 0; +} diff --git a/src/rtlib/js/io_getxy.c b/src/rtlib/js/io_getxy.c new file mode 100644 index 0000000000..a80e2a5f40 --- /dev/null +++ b/src/rtlib/js/io_getxy.c @@ -0,0 +1,5 @@ +#include "../fb.h" + +FBCALL void fb_ConsoleGetXY( int *col, int *row ) +{ +} diff --git a/src/rtlib/js/io_gety.c b/src/rtlib/js/io_gety.c new file mode 100644 index 0000000000..8809660948 --- /dev/null +++ b/src/rtlib/js/io_gety.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +int fb_ConsoleGetY( void ) +{ + return 0; +} diff --git a/src/rtlib/js/io_inkey.c b/src/rtlib/js/io_inkey.c new file mode 100644 index 0000000000..9cc724f4af --- /dev/null +++ b/src/rtlib/js/io_inkey.c @@ -0,0 +1,35 @@ +/* console INKEY() function */ + +#include "../fb.h" +#include "fb_private_console.h" + +/* Caller is expected to hold FB_LOCK() */ +FBSTRING *fb_ConsoleInkey( void ) +{ + FBSTRING *res = &__fb_ctx.null_desc; + + if( fb_ConsoleKeyHit( ) != 0 ) + { + res = fb_hMakeInkeyStr( fb_ConsoleGetkey( ) ); + } + + return res; +} + +int fb_ConsoleGetkey( void ) +{ + /* !!!FIXME!!! getkey() should block */ + if( __fb_con.key_head == __fb_con.key_tail) + return 0; + + int key = __fb_con.key_buffer[__fb_con.key_head]; + __fb_con.key_head = (__fb_con.key_head + 1) % KEY_BUFFER_LEN; + + return key; +} + +/* Caller is expected to hold FB_LOCK() */ +int fb_ConsoleKeyHit( void ) +{ + return __fb_con.key_head != __fb_con.key_tail; +} diff --git a/src/rtlib/js/io_input.c b/src/rtlib/js/io_input.c new file mode 100644 index 0000000000..9e15096d15 --- /dev/null +++ b/src/rtlib/js/io_input.c @@ -0,0 +1,26 @@ +/* console input helpers */ + +#include "../fb.h" +#include "fb_private_console.h" + +EM_BOOL fb_hKeyPressedCB(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +{ + if( eventType != EMSCRIPTEN_EVENT_KEYPRESS ) + return 0; + + // !!!FIXME!!! convert ctrlKey, shiftKey and altKey + // !!!FIXME!!! check repeat + + __fb_con.key_buffer[__fb_con.key_tail] = keyEvent->keyCode != 0? keyEvent->keyCode: keyEvent->charCode; + __fb_con.key_tail = (__fb_con.key_tail + 1) % KEY_BUFFER_LEN; + + if( __fb_con.key_tail == __fb_con.key_head ) + __fb_con.key_head = (__fb_con.key_head + 1) % KEY_BUFFER_LEN; + + return 1; +} + +int fb_hConsoleInputBufferChanged( void ) +{ + return fb_ConsoleKeyHit(); +} diff --git a/src/rtlib/js/io_isredir.c b/src/rtlib/js/io_isredir.c new file mode 100644 index 0000000000..0bcc1c66bc --- /dev/null +++ b/src/rtlib/js/io_isredir.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +int fb_ConsoleIsRedirected( int is_input ) +{ + return FB_TRUE; +} diff --git a/src/rtlib/js/io_locate.c b/src/rtlib/js/io_locate.c new file mode 100644 index 0000000000..6b889743de --- /dev/null +++ b/src/rtlib/js/io_locate.c @@ -0,0 +1,8 @@ +/* console LOCATE statement */ + +#include "../fb.h" + +int fb_ConsoleLocate( int row, int col, int cursor ) +{ + return 0; +} diff --git a/src/rtlib/js/io_maxrow.c b/src/rtlib/js/io_maxrow.c new file mode 100644 index 0000000000..090adce923 --- /dev/null +++ b/src/rtlib/js/io_maxrow.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +int fb_ConsoleGetMaxRow( void ) +{ + return 25; +} diff --git a/src/rtlib/js/io_mouse.c b/src/rtlib/js/io_mouse.c new file mode 100644 index 0000000000..7884422e3a --- /dev/null +++ b/src/rtlib/js/io_mouse.c @@ -0,0 +1,13 @@ +/* console mode mouse functions */ + +#include "../fb.h" + +int fb_ConsoleGetMouse( int *x, int *y, int *z, int *buttons, int *clip ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} + +int fb_ConsoleSetMouse( int x, int y, int cursor, int clip ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} diff --git a/src/rtlib/js/io_multikey.c b/src/rtlib/js/io_multikey.c new file mode 100644 index 0000000000..1951c9b38b --- /dev/null +++ b/src/rtlib/js/io_multikey.c @@ -0,0 +1,9 @@ +/* console multikey() */ + +#include "../fb.h" + +int fb_ConsoleMultikey( int scancode ) +{ + fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); + return FB_FALSE; +} diff --git a/src/rtlib/js/io_pageset.c b/src/rtlib/js/io_pageset.c new file mode 100644 index 0000000000..796de72101 --- /dev/null +++ b/src/rtlib/js/io_pageset.c @@ -0,0 +1,8 @@ +/* console 'screen , pg, pg' function */ + +#include "../fb.h" + +int fb_ConsolePageSet( int active, int visible ) +{ + return -1; +} diff --git a/src/rtlib/js/io_pcopy.c b/src/rtlib/js/io_pcopy.c new file mode 100644 index 0000000000..d00eac3a18 --- /dev/null +++ b/src/rtlib/js/io_pcopy.c @@ -0,0 +1,8 @@ +/* console pcopy function */ + +#include "../fb.h" + +int fb_ConsolePageCopy( int src, int dst ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} diff --git a/src/rtlib/js/io_printbuff.c b/src/rtlib/js/io_printbuff.c new file mode 100644 index 0000000000..88794cf36e --- /dev/null +++ b/src/rtlib/js/io_printbuff.c @@ -0,0 +1,13 @@ +/* low-level print to console function stub */ + +#include "../fb.h" + +void fb_ConsolePrintBufferEx( const void *buffer, size_t len, int mask ) +{ + fwrite(buffer, 1, len, stdout); +} + +void fb_ConsolePrintBuffer( const char *buffer, int mask ) +{ + fb_ConsolePrintBufferEx( buffer, strlen(buffer), mask ); +} diff --git a/src/rtlib/js/io_printbuff_wstr.c b/src/rtlib/js/io_printbuff_wstr.c new file mode 100644 index 0000000000..cb69f21a5c --- /dev/null +++ b/src/rtlib/js/io_printbuff_wstr.c @@ -0,0 +1,22 @@ +/* low-level print to console function */ + +#include "../fb.h" + +void fb_ConsolePrintBufferWstrEx + ( + const FB_WCHAR *buffer, + size_t chars, + int mask + ) +{ + /* !!!WRITEME!!! */ +} + +void fb_ConsolePrintBufferWstr + ( + const FB_WCHAR *buffer, + int mask + ) +{ + return fb_ConsolePrintBufferWstrEx( buffer, fb_wstr_Len( buffer ), mask ); +} diff --git a/src/rtlib/js/io_printer.c b/src/rtlib/js/io_printer.c new file mode 100644 index 0000000000..b54445a432 --- /dev/null +++ b/src/rtlib/js/io_printer.c @@ -0,0 +1,23 @@ +/* printer access stubs */ + +#include "../fb.h" + +int fb_PrinterOpen( DEV_LPT_INFO *devInfo, int iPort, const char *pszDevice ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILENOTFOUND ); +} + +int fb_PrinterWrite( DEV_LPT_INFO *devInfo, const void *data, size_t length ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILEIO ); +} + +int fb_PrinterWriteWstr( DEV_LPT_INFO *devInfo, const FB_WCHAR *data, size_t length ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILEIO ); +} + +int fb_PrinterClose( DEV_LPT_INFO *devInfo ) +{ + return fb_ErrorSetNum( FB_RTERROR_FILEIO ); +} diff --git a/src/rtlib/js/io_readstr.c b/src/rtlib/js/io_readstr.c new file mode 100644 index 0000000000..8ad2f7c4ec --- /dev/null +++ b/src/rtlib/js/io_readstr.c @@ -0,0 +1,8 @@ +/* console line input function */ + +#include "../fb.h" + +char *fb_ConsoleReadStr( char *buffer, ssize_t len ) +{ + return fgets( buffer, len, stdin ); +} diff --git a/src/rtlib/js/io_readxy.c b/src/rtlib/js/io_readxy.c new file mode 100644 index 0000000000..f552a6a803 --- /dev/null +++ b/src/rtlib/js/io_readxy.c @@ -0,0 +1,8 @@ +/* console SCREEN() function (character/color query) */ + +#include "../fb.h" + +FBCALL unsigned int fb_ConsoleReadXY( int col, int row, int colorflag ) +{ + return 0; +} diff --git a/src/rtlib/js/io_scroll.c b/src/rtlib/js/io_scroll.c new file mode 100644 index 0000000000..2050d82dad --- /dev/null +++ b/src/rtlib/js/io_scroll.c @@ -0,0 +1,7 @@ +/* console scrolling for when VIEW is used */ + +#include "../fb.h" + +void fb_ConsoleScroll( int nrows ) +{ +} diff --git a/src/rtlib/js/io_serial.c b/src/rtlib/js/io_serial.c new file mode 100644 index 0000000000..670f62196d --- /dev/null +++ b/src/rtlib/js/io_serial.c @@ -0,0 +1,35 @@ +/* serial port access stubs */ + +#include "../fb.h" + +int fb_SerialOpen + ( + FB_FILE *handle, + int iPort, + FB_SERIAL_OPTIONS *options, + const char *pszDevice, + void **ppvHandle + ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} + +int fb_SerialGetRemaining( FB_FILE *handle, void *pvHandle, fb_off_t *pLength ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} + +int fb_SerialWrite( FB_FILE *handle, void *pvHandle, const void *data, size_t length ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} + +int fb_SerialRead( FB_FILE *handle, void *pvHandle, void *data, size_t *pLength ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} + +int fb_SerialClose( FB_FILE *handle, void *pvHandle ) +{ + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); +} diff --git a/src/rtlib/js/io_viewupdate.c b/src/rtlib/js/io_viewupdate.c new file mode 100644 index 0000000000..799ee210b3 --- /dev/null +++ b/src/rtlib/js/io_viewupdate.c @@ -0,0 +1,7 @@ +/* view print update (console, no gfx) */ + +#include "../fb.h" + +void fb_ConsoleViewUpdate( void ) +{ +} diff --git a/src/rtlib/js/io_width.c b/src/rtlib/js/io_width.c new file mode 100644 index 0000000000..5add1b321d --- /dev/null +++ b/src/rtlib/js/io_width.c @@ -0,0 +1,8 @@ +/* console width() function */ + +#include "../fb.h" + +int fb_ConsoleWidth( int cols, int rows ) +{ + return 0; +} diff --git a/src/rtlib/js/sys_beep.c b/src/rtlib/js/sys_beep.c new file mode 100644 index 0000000000..177112fcc6 --- /dev/null +++ b/src/rtlib/js/sys_beep.c @@ -0,0 +1,8 @@ +/* beep function */ + +#include "../fb.h" + +FBCALL void fb_Beep( void ) +{ + return; +} diff --git a/src/rtlib/js/sys_delay.c b/src/rtlib/js/sys_delay.c new file mode 100644 index 0000000000..9d21b87ade --- /dev/null +++ b/src/rtlib/js/sys_delay.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +FBCALL void fb_Delay( int msecs ) +{ + return; +} diff --git a/src/rtlib/js/sys_dylib.c b/src/rtlib/js/sys_dylib.c new file mode 100644 index 0000000000..b6ee97e279 --- /dev/null +++ b/src/rtlib/js/sys_dylib.c @@ -0,0 +1,22 @@ +/* Dynamic library loading functions */ + +#include "../fb.h" + +FBCALL void *fb_DylibLoad( FBSTRING *library ) +{ + return NULL; +} + +FBCALL void *fb_DylibSymbol( void *library, FBSTRING *symbol ) +{ + return NULL; +} + +FBCALL void *fb_DylibSymbolByOrd( void *library, short int symbol ) +{ + return NULL; +} + +FBCALL void fb_DylibFree( void *library ) +{ +} diff --git a/src/rtlib/js/sys_execex.c b/src/rtlib/js/sys_execex.c new file mode 100644 index 0000000000..439a36064e --- /dev/null +++ b/src/rtlib/js/sys_execex.c @@ -0,0 +1,6 @@ +#include "../fb.h" + +FBCALL int fb_ExecEx( FBSTRING *program, FBSTRING *args, int do_fork ) +{ + return fb_ErrorSetNum(FB_RTERROR_FILENOTFOUND); +} diff --git a/src/rtlib/js/sys_fmem.c b/src/rtlib/js/sys_fmem.c new file mode 100644 index 0000000000..137961b424 --- /dev/null +++ b/src/rtlib/js/sys_fmem.c @@ -0,0 +1,8 @@ +/* fre() function */ + +#include "../fb.h" + +FBCALL size_t fb_GetMemAvail( int mode ) +{ + return 16 * 1024 * 1024; +} diff --git a/src/rtlib/js/sys_getcwd.c b/src/rtlib/js/sys_getcwd.c new file mode 100644 index 0000000000..09782b4be3 --- /dev/null +++ b/src/rtlib/js/sys_getcwd.c @@ -0,0 +1,10 @@ +/* get current dir */ + +#include "../fb.h" + +ssize_t fb_hGetCurrentDir( char *dst, ssize_t maxlen ) +{ + /* !!!WRITEME!!! */ + *dst = '\0'; + return 0; +} diff --git a/src/rtlib/js/sys_getexename.c b/src/rtlib/js/sys_getexename.c new file mode 100644 index 0000000000..ed15d23906 --- /dev/null +++ b/src/rtlib/js/sys_getexename.c @@ -0,0 +1,10 @@ +/* get the executable's name */ + +#include "../fb.h" + +char *fb_hGetExeName( char *dst, ssize_t maxlen ) +{ + /* !!!WRITEME!!! */ + dst[0] = '\0'; + return dst; +} diff --git a/src/rtlib/js/sys_getexepath.c b/src/rtlib/js/sys_getexepath.c new file mode 100644 index 0000000000..238f875b57 --- /dev/null +++ b/src/rtlib/js/sys_getexepath.c @@ -0,0 +1,10 @@ +/* get the executable path */ + +#include "../fb.h" + +char *fb_hGetExePath( char *dst, ssize_t maxlen ) +{ + /* !!!WRITEME!!! */ + dst[0] = '\0'; + return dst; +} diff --git a/src/rtlib/js/sys_getshortpath.c b/src/rtlib/js/sys_getshortpath.c new file mode 100644 index 0000000000..838d90fe04 --- /dev/null +++ b/src/rtlib/js/sys_getshortpath.c @@ -0,0 +1,8 @@ +#include "../fb.h" + +char *fb_hGetShortPath( char *src, char *dst, ssize_t maxlen ) +{ + /* !!!WRITEME!!! */ + strncpy(dst, src, maxlen); + return dst; +} diff --git a/src/rtlib/js/sys_hshell.c b/src/rtlib/js/sys_hshell.c new file mode 100644 index 0000000000..98a96292e7 --- /dev/null +++ b/src/rtlib/js/sys_hshell.c @@ -0,0 +1,8 @@ +/* SHELL command */ + +#include "../fb.h" + +int fb_hShell( char *program ) +{ + return -1; +} diff --git a/src/rtlib/js/thread_cond.c b/src/rtlib/js/thread_cond.c new file mode 100644 index 0000000000..84dc273fff --- /dev/null +++ b/src/rtlib/js/thread_cond.c @@ -0,0 +1,24 @@ +/* condition variable functions */ + +#include "../fb.h" + +FBCALL FBCOND *fb_CondCreate( void ) +{ + return NULL; +} + +FBCALL void fb_CondDestroy( FBCOND *cond ) +{ +} + +FBCALL void fb_CondSignal( FBCOND *cond ) +{ +} + +FBCALL void fb_CondBroadcast( FBCOND *cond ) +{ +} + +FBCALL void fb_CondWait( FBCOND *cond, FBMUTEX *mutex ) +{ +} diff --git a/src/rtlib/js/thread_core.c b/src/rtlib/js/thread_core.c new file mode 100644 index 0000000000..b63803d0be --- /dev/null +++ b/src/rtlib/js/thread_core.c @@ -0,0 +1,24 @@ +/* thread creation and destruction functions */ + +#include "../fb.h" +#include "../fb_private_thread.h" + +FBCALL FBTHREAD *fb_ThreadCreate( FB_THREADPROC proc, void *param, ssize_t stack_size ) +{ + FBTHREAD *thread; + + thread = (FBTHREAD *)malloc( sizeof( FBTHREAD ) ); + if( thread == NULL ) { + return NULL; + } + + return thread; +} + +FBCALL void fb_ThreadWait( FBTHREAD *thread ) +{ + if( !thread ) + return; + + free( thread ); +} diff --git a/src/rtlib/js/thread_detach.c b/src/rtlib/js/thread_detach.c new file mode 100644 index 0000000000..8c9d73be04 --- /dev/null +++ b/src/rtlib/js/thread_detach.c @@ -0,0 +1,9 @@ +#include "../fb.h" + +FBCALL void fb_ThreadDetach( FBTHREAD *thread ) +{ + if( thread == NULL ) + return; + + free( thread ); +} diff --git a/src/rtlib/js/thread_mutex.c b/src/rtlib/js/thread_mutex.c new file mode 100644 index 0000000000..3ad2495a95 --- /dev/null +++ b/src/rtlib/js/thread_mutex.c @@ -0,0 +1,20 @@ +/* mutex handling routines */ + +#include "../fb.h" + +FBCALL FBMUTEX *fb_MutexCreate( void ) +{ + return NULL; +} + +FBCALL void fb_MutexDestroy( FBMUTEX *mutex ) +{ +} + +FBCALL void fb_MutexLock( FBMUTEX *mutex ) +{ +} + +FBCALL void fb_MutexUnlock( FBMUTEX *mutex ) +{ +} diff --git a/src/rtlib/js/time_setdate.c b/src/rtlib/js/time_setdate.c new file mode 100644 index 0000000000..cd0599c15e --- /dev/null +++ b/src/rtlib/js/time_setdate.c @@ -0,0 +1,9 @@ +/* set date function */ + +#include "../fb.h" + +int fb_hSetDate( int y, int m, int d ) +{ + /* TODO: use NtSetSystemTime */ + return 0; +} diff --git a/src/rtlib/js/time_settime.c b/src/rtlib/js/time_settime.c new file mode 100644 index 0000000000..33e167d9dc --- /dev/null +++ b/src/rtlib/js/time_settime.c @@ -0,0 +1,7 @@ +#include "../fb.h" + +int fb_hSetTime( int h, int m, int s ) +{ + /* TODO: use NtSetSystemTime */ + return 0; +} diff --git a/src/rtlib/js/time_timer.c b/src/rtlib/js/time_timer.c new file mode 100644 index 0000000000..fe12971fd1 --- /dev/null +++ b/src/rtlib/js/time_timer.c @@ -0,0 +1,12 @@ +/* timer() function */ + +#include "../fb.h" +#include +#include + +FBCALL double fb_Timer( void ) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (((double)tv.tv_sec * 1000000.0) + (double)tv.tv_usec) * 0.000001; +} diff --git a/src/rtlib/xbox/io_getsize.c b/src/rtlib/xbox/io_getsize.c index 452f178c15..2d9eb1415f 100644 --- a/src/rtlib/xbox/io_getsize.c +++ b/src/rtlib/xbox/io_getsize.c @@ -2,4 +2,6 @@ FBCALL void fb_ConsoleGetSize( int *cols, int *rows ) { + *cols = 80; + *rows = 25; } From 0deb5151496b05cd7021767e443d45e273f7c499 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Sun, 11 Oct 2015 16:18:04 -0300 Subject: [PATCH 2/8] fixed: screen update + inkey (gfxlib2) --- src/gfxlib2/gfx_screen.c | 2 + src/gfxlib2/js/fb_gfx_js.h | 29 +++++++++++ src/gfxlib2/js/gfx_driver.c | 98 ++++++++++++++++--------------------- src/gfxlib2/js/gfx_events.c | 77 +++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 57 deletions(-) create mode 100644 src/gfxlib2/js/fb_gfx_js.h create mode 100644 src/gfxlib2/js/gfx_events.c diff --git a/src/gfxlib2/gfx_screen.c b/src/gfxlib2/gfx_screen.c index 265519d3c2..997fa21499 100644 --- a/src/gfxlib2/gfx_screen.c +++ b/src/gfxlib2/gfx_screen.c @@ -96,8 +96,10 @@ static void release_gfx_mem(void) static void exit_proc(void) { +#ifndef HOST_JS if( __fb_gfx ) set_mode( 0, 0, 0, 0, 0, 1, 0, 0, 0, SCREEN_EXIT, 0.0, 0, 0 ); +#endif } /* Dummy function to ensure that the CONSOLE "update" hook for a VIEW PRINT diff --git a/src/gfxlib2/js/fb_gfx_js.h b/src/gfxlib2/js/fb_gfx_js.h new file mode 100644 index 0000000000..dba337d016 --- /dev/null +++ b/src/gfxlib2/js/fb_gfx_js.h @@ -0,0 +1,29 @@ +#include +#include + +#define SCREENLIST(w, h) ((h) | (w) << 16) + +#define GFX_JS_FPS 60 + +#define KEY_BUFFER_LEN 256 + +typedef struct JS_GFXDRIVER_CTX_ +{ + int inited; + int changingScreen; + int updated; + int blitting; + + SDL_Surface *canvas; + BLITTER *blit; + + unsigned long key_buffer[KEY_BUFFER_LEN]; + int key_head; + int key_tail; +} JS_GFXDRIVER_CTX; + +extern JS_GFXDRIVER_CTX __fb_js_ctx; + + +void fb_js_events_init(void); +void fb_js_events_check(void); diff --git a/src/gfxlib2/js/gfx_driver.c b/src/gfxlib2/js/gfx_driver.c index c67feddd1e..d93b00ed28 100644 --- a/src/gfxlib2/js/gfx_driver.c +++ b/src/gfxlib2/js/gfx_driver.c @@ -1,65 +1,45 @@ /* asmjs fbgfx driver */ #include "../fb_gfx.h" -#include -#include +#include "fb_gfx_js.h" -#define SCREENLIST(w, h) ((h) | (w) << 16) - -#define GFX_JS_FPS 60 +JS_GFXDRIVER_CTX __fb_js_ctx = { FALSE, FALSE, FALSE, FALSE, NULL }; static void driver_exit(void); -typedef struct JS_GFXDRIVER_CTX_ -{ - int inited; - int changingScreen; - int updated ; - SDL_Surface *canvas; -} JS_GFXDRIVER_CTX; - -static JS_GFXDRIVER_CTX __js_ctx = { 0, 0, 0, NULL }; - static void driver_blit() { - SDL_Surface *tmp = SDL_CreateRGBSurfaceFrom( - __fb_gfx->framebuffer, - __fb_gfx->w, __fb_gfx->h, __fb_gfx->depth, __fb_gfx->pitch, - 0x0f00, 0x00f0, 0x000f, 0xf000); - - SDL_BlitSurface(tmp, NULL, __js_ctx.canvas, NULL); + if(SDL_LockSurface(__fb_js_ctx.canvas) == 0) + { + __fb_js_ctx.blit(__fb_js_ctx.canvas->pixels, __fb_js_ctx.canvas->pitch); - SDL_FreeSurface(tmp); + SDL_UnlockSurface(__fb_js_ctx.canvas); + } - SDL_Flip(__js_ctx.canvas); + SDL_Flip(__fb_js_ctx.canvas); } static void driver_update(void *unused) { - if( !__js_ctx.inited || __fb_gfx == NULL || __fb_gfx->framebuffer == NULL ) + if( !__fb_js_ctx.inited || __fb_gfx == NULL || __fb_gfx->framebuffer == NULL ) return; - if( !__js_ctx.changingScreen ) + int ini_time = SDL_GetTicks(); + + if( !__fb_js_ctx.changingScreen && !__fb_js_ctx.blitting ) { + __fb_js_ctx.blitting = TRUE; driver_blit(); + __fb_js_ctx.blitting = FALSE; - SDL_PumpEvents(); + __fb_js_ctx.updated = TRUE; - __js_ctx.updated = 1; + fb_js_events_check( ); } - emscripten_async_call(driver_update, NULL, 1000/GFX_JS_FPS); -} - -static void fb_js_kb_init(void) -{ - __fb_ctx.hooks.inkeyproc = NULL; - __fb_ctx.hooks.getkeyproc = NULL; - __fb_ctx.hooks.keyhitproc = NULL; - __fb_ctx.hooks.multikeyproc = NULL; - __fb_ctx.hooks.sleepproc = NULL; + int delay = (1000/GFX_JS_FPS) - (SDL_GetTicks() - ini_time); - return; + emscripten_async_call(driver_update, NULL, MAX( delay, 1 ) ); } @@ -68,26 +48,30 @@ static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rat if( w == 0 || h == 0 || depth_arg == 0 ) return 0; - __js_ctx.changingScreen = TRUE; + __fb_js_ctx.changingScreen = TRUE; - if( !__js_ctx.inited ) - SDL_Init(SDL_INIT_VIDEO); + if( !__fb_js_ctx.inited ) + { + fb_js_events_init(); + SDL_Init(SDL_INIT_VIDEO); + } + + if( __fb_js_ctx.canvas != NULL ) + SDL_FreeSurface(__fb_js_ctx.canvas); - if( __js_ctx.canvas != NULL ) - SDL_FreeSurface(__js_ctx.canvas); + __fb_js_ctx.canvas = SDL_SetVideoMode(w, h, 32, SDL_HWSURFACE); - __js_ctx.canvas = SDL_SetVideoMode(w, h, 32, SDL_HWSURFACE); + __fb_js_ctx.blit = fb_hGetBlitter(__fb_js_ctx.canvas->format->BitsPerPixel, TRUE); - // in JS we should not hook the key routines - fb_js_kb_init(); + __fb_js_ctx.changingScreen = FALSE; + __fb_js_ctx.blitting = FALSE; - __js_ctx.changingScreen = FALSE; - int was_inited = __js_ctx.inited; - __js_ctx.inited = TRUE; + int was_inited = __fb_js_ctx.inited; + __fb_js_ctx.inited = TRUE; if( !was_inited ) { - __js_ctx.updated = 0; + __fb_js_ctx.updated = 0; emscripten_async_call(driver_update, NULL, 1000/GFX_JS_FPS); } @@ -96,17 +80,17 @@ static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rat static void driver_exit(void) { - if( __js_ctx.inited ) + if( __fb_js_ctx.inited ) { - __js_ctx.inited = FALSE; + __fb_js_ctx.inited = FALSE; - if( __js_ctx.updated == 0 ) + if( !__fb_js_ctx.updated ) driver_blit(); - if( __js_ctx.canvas != NULL ) + if( __fb_js_ctx.canvas != NULL ) { - SDL_FreeSurface(__js_ctx.canvas); - __js_ctx.canvas = NULL; + SDL_FreeSurface(__fb_js_ctx.canvas); + __fb_js_ctx.canvas = NULL; } SDL_Quit(); @@ -165,7 +149,7 @@ static int *driver_fetch_modes(int depth, int *size) static void driver_poll_events(void) { - /* !!!WRITEME!!! */ + fb_js_events_check( ); } static const GFXDRIVER fb_gfxDriverJS = diff --git a/src/gfxlib2/js/gfx_events.c b/src/gfxlib2/js/gfx_events.c new file mode 100644 index 0000000000..431d54de64 --- /dev/null +++ b/src/gfxlib2/js/gfx_events.c @@ -0,0 +1,77 @@ +#include "../fb_gfx.h" +#include "fb_gfx_js.h" + +static int fb_js_gfx_Getkey( void ) +{ + if( __fb_js_ctx.key_head == __fb_js_ctx.key_tail) + return 0; + + int key = __fb_js_ctx.key_buffer[__fb_js_ctx.key_head]; + __fb_js_ctx.key_head = (__fb_js_ctx.key_head + 1) % KEY_BUFFER_LEN; + + return key; +} + +static int fb_js_gfx_KeyHit( void ) +{ + return __fb_js_ctx.key_head != __fb_js_ctx.key_tail; +} + +static FBSTRING *fb_js_gfx_Inkey( void ) +{ + FBSTRING *res = &__fb_ctx.null_desc; + + if( fb_js_gfx_KeyHit( ) != 0 ) + { + res = fb_hMakeInkeyStr( fb_js_gfx_Getkey( ) ); + } + + return res; +} + +static void fb_js_key_down(SDL_Event *event) +{ + __fb_js_ctx.key_buffer[__fb_js_ctx.key_tail] = event->key.keysym.sym; + __fb_js_ctx.key_tail = (__fb_js_ctx.key_tail + 1) % KEY_BUFFER_LEN; + + if( __fb_js_ctx.key_tail == __fb_js_ctx.key_head ) + __fb_js_ctx.key_head = (__fb_js_ctx.key_head + 1) % KEY_BUFFER_LEN; + + //keys(event.key.keysym.sym) = 1 +} + +static void fb_js_key_up(SDL_Event *event) +{ + //keys(event.key.keysym.sym) = 0 +} + +void fb_js_events_check(void) +{ + SDL_PumpEvents(); + + SDL_Event event; + + while( SDL_PollEvent(&event) ) + { + switch( event.type ) + { + case SDL_KEYDOWN: + fb_js_key_down(&event); + break; + case SDL_KEYUP: + fb_js_key_up(&event); + break; + } + } +} + +void fb_js_events_init(void) +{ + __fb_ctx.hooks.inkeyproc = fb_js_gfx_Inkey; + __fb_ctx.hooks.getkeyproc = fb_js_gfx_Getkey; + __fb_ctx.hooks.keyhitproc = fb_js_gfx_KeyHit; + __fb_ctx.hooks.multikeyproc = NULL; + __fb_ctx.hooks.sleepproc = NULL; + + return; +} From 6d78209fad8d088cf3f514a0b563357064cb2728 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Mon, 12 Oct 2015 00:09:24 -0300 Subject: [PATCH 3/8] fixed: some extended keys --- src/gfxlib2/js/gfx_events.c | 19 +++++++++++++++++-- src/rtlib/js/io_input.c | 6 +++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/gfxlib2/js/gfx_events.c b/src/gfxlib2/js/gfx_events.c index 431d54de64..43b9acaaee 100644 --- a/src/gfxlib2/js/gfx_events.c +++ b/src/gfxlib2/js/gfx_events.c @@ -1,6 +1,8 @@ #include "../fb_gfx.h" #include "fb_gfx_js.h" +static int sleep_called = 0; + static int fb_js_gfx_Getkey( void ) { if( __fb_js_ctx.key_head == __fb_js_ctx.key_tail) @@ -31,7 +33,11 @@ static FBSTRING *fb_js_gfx_Inkey( void ) static void fb_js_key_down(SDL_Event *event) { - __fb_js_ctx.key_buffer[__fb_js_ctx.key_tail] = event->key.keysym.sym; + unsigned long key = event->key.keysym.sym; + + //emscripten_log(EM_LOG_CONSOLE, "%d, %d, %d", event->key.keysym.sym, event->key.keysym.scancode, key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key); + + __fb_js_ctx.key_buffer[__fb_js_ctx.key_tail] = key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key; __fb_js_ctx.key_tail = (__fb_js_ctx.key_tail + 1) % KEY_BUFFER_LEN; if( __fb_js_ctx.key_tail == __fb_js_ctx.key_head ) @@ -65,13 +71,22 @@ void fb_js_events_check(void) } } +static void fb_js_sleep(int msecs) +{ + if( !sleep_called ) + { + sleep_called = 1; + emscripten_log(EM_LOG_WARN, "Warning: Call to SLEEP() ignored. It should not be used in Javascript"); + } +} + void fb_js_events_init(void) { __fb_ctx.hooks.inkeyproc = fb_js_gfx_Inkey; __fb_ctx.hooks.getkeyproc = fb_js_gfx_Getkey; __fb_ctx.hooks.keyhitproc = fb_js_gfx_KeyHit; __fb_ctx.hooks.multikeyproc = NULL; - __fb_ctx.hooks.sleepproc = NULL; + __fb_ctx.hooks.sleepproc = fb_js_sleep; return; } diff --git a/src/rtlib/js/io_input.c b/src/rtlib/js/io_input.c index 9e15096d15..691a5e7ee7 100644 --- a/src/rtlib/js/io_input.c +++ b/src/rtlib/js/io_input.c @@ -11,7 +11,11 @@ EM_BOOL fb_hKeyPressedCB(int eventType, const EmscriptenKeyboardEvent *keyEvent, // !!!FIXME!!! convert ctrlKey, shiftKey and altKey // !!!FIXME!!! check repeat - __fb_con.key_buffer[__fb_con.key_tail] = keyEvent->keyCode != 0? keyEvent->keyCode: keyEvent->charCode; + unsigned long key = keyEvent->keyCode != 0? keyEvent->keyCode: keyEvent->charCode; + + //emscripten_log(EM_LOG_CONSOLE, "%d, %d, %d, %d, %d", keyEvent->keyCode, keyEvent->charCode, key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key, keyEvent->key[0], keyEvent->code[0]); + + __fb_con.key_buffer[__fb_con.key_tail] = key; __fb_con.key_tail = (__fb_con.key_tail + 1) % KEY_BUFFER_LEN; if( __fb_con.key_tail == __fb_con.key_head ) From 38d477d80979996d96580f9edcd8a20ddef689b8 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Mon, 12 Oct 2015 00:40:05 -0300 Subject: [PATCH 4/8] Emscripten can't do unaligned memory access, so even in QB mode we must pad the UDT fields --- src/compiler/symb-struct.bas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/compiler/symb-struct.bas b/src/compiler/symb-struct.bas index cc91fdb208..0822d77f77 100644 --- a/src/compiler/symb-struct.bas +++ b/src/compiler/symb-struct.bas @@ -73,7 +73,10 @@ function symbStructBegin _ '' Assume FIELD = 1 under -lang qb, because QB didn't do any alignment if( fbLangIsSet( FB_LANG_QB ) ) then if( align = 0 ) then - align = 1 + '' emcripten doesn't support unaligned memory access + if( env.clopt.target <> FB_COMPTARGET_JS ) then + align = 1 + end if end if end if @@ -167,7 +170,6 @@ private function hCalcPadding _ '' default? if( align = 0 ) then - assert( fbLangIsSet( FB_LANG_QB ) = FALSE ) align = natalign '' packed.. else From d599239684532776eac929759e1d4d5ced5cb460 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Wed, 14 Oct 2015 20:11:31 -0300 Subject: [PATCH 5/8] added: mouse, keyboard and event functions --- inc/fbgfx.bi | 2 +- makefile | 4 + src/gfxlib2/fb_gfx.h | 42 ---- src/gfxlib2/gfx_screen.c | 1 + src/gfxlib2/js/fb_gfx_js.h | 10 +- src/gfxlib2/js/gfx_driver.c | 84 +++++-- src/gfxlib2/js/gfx_events.c | 110 ++++----- src/rtlib/fb.h | 116 +-------- src/rtlib/fb_event.h | 159 ++++++++++++ src/rtlib/fb_hook.h | 3 + src/rtlib/js/fb_private_console.h | 25 +- src/rtlib/js/hinit.c | 12 +- src/rtlib/js/io_input.c | 394 +++++++++++++++++++++++++++++- src/rtlib/js/io_mouse.c | 40 ++- src/rtlib/js/io_multikey.c | 7 +- 15 files changed, 745 insertions(+), 264 deletions(-) create mode 100644 src/rtlib/fb_event.h diff --git a/inc/fbgfx.bi b/inc/fbgfx.bi index 5fa26dcc2a..724f9632a7 100644 --- a/inc/fbgfx.bi +++ b/inc/fbgfx.bi @@ -9,7 +9,7 @@ #inclib "gdi32" #inclib "winmm" #inclib "user32" -#elseif defined(__FB_LINUX__) +#elseif defined(__FB_LINUX__) and not defined(__FB_JS__) #libpath "/usr/X11R6/lib" #inclib "X11" #inclib "Xext" diff --git a/makefile b/makefile index b39b4b6bb4..b736df582d 100644 --- a/makefile +++ b/makefile @@ -443,6 +443,10 @@ ifneq ($(filter cygwin win32,$(TARGET_OS)),) ALLFBLFLAGS += -t 2048 endif +ifeq ($(TARGET_OS),js) + DISABLE_MT := YesPlease +endif + # Pass the configuration defines on to the compiler source code ifdef ENABLE_STANDALONE ALLFBCFLAGS += -d ENABLE_STANDALONE diff --git a/src/gfxlib2/fb_gfx.h b/src/gfxlib2/fb_gfx.h index 7a1c3f9782..aa8816f3ba 100644 --- a/src/gfxlib2/fb_gfx.h +++ b/src/gfxlib2/fb_gfx.h @@ -88,29 +88,6 @@ #define WINDOW_TITLE_SIZE 128 -#define EVENT_KEY_PRESS 1 -#define EVENT_KEY_RELEASE 2 -#define EVENT_KEY_REPEAT 3 -#define EVENT_MOUSE_MOVE 4 -#define EVENT_MOUSE_BUTTON_PRESS 5 -#define EVENT_MOUSE_BUTTON_RELEASE 6 -#define EVENT_MOUSE_DOUBLE_CLICK 7 -#define EVENT_MOUSE_WHEEL 8 -#define EVENT_MOUSE_ENTER 9 -#define EVENT_MOUSE_EXIT 10 -#define EVENT_WINDOW_GOT_FOCUS 11 -#define EVENT_WINDOW_LOST_FOCUS 12 -#define EVENT_WINDOW_CLOSE 13 -#define EVENT_MOUSE_HWHEEL 14 - -#define MAX_EVENTS 128 - -#define BUTTON_LEFT 0x1 -#define BUTTON_RIGHT 0x2 -#define BUTTON_MIDDLE 0x4 -#define BUTTON_X1 0x8 -#define BUTTON_X2 0x10 - #define GET_WINDOW_POS 0 #define GET_WINDOW_TITLE 1 #define GET_WINDOW_HANDLE 2 @@ -158,25 +135,6 @@ typedef struct _GFX_CHAR_CELL { unsigned fg, bg; } GFX_CHAR_CELL; -struct _EVENT { - int type; - union { - struct { /* keyboard events */ - int scancode; - int ascii; - }; - struct { /* mouse events */ - int x, y; - int dx, dy; - }; - int button; - int z; - int w; - }; -} FBPACKED; - -typedef struct _EVENT EVENT; - typedef struct FBGFX { int id; /**< Mode id number for contexts identification */ diff --git a/src/gfxlib2/gfx_screen.c b/src/gfxlib2/gfx_screen.c index 997fa21499..7047f104b5 100644 --- a/src/gfxlib2/gfx_screen.c +++ b/src/gfxlib2/gfx_screen.c @@ -231,6 +231,7 @@ static int set_mode __fb_ctx.hooks.isredirproc = fb_GfxIsRedir; __fb_ctx.hooks.pagecopyproc = fb_GfxPageCopy; __fb_ctx.hooks.pagesetproc = fb_GfxPageSet; + __fb_ctx.hooks.posteventproc = NULL; __fb_gfx = (FBGFX *)calloc(1, sizeof(FBGFX)); } diff --git a/src/gfxlib2/js/fb_gfx_js.h b/src/gfxlib2/js/fb_gfx_js.h index dba337d016..1a91c07800 100644 --- a/src/gfxlib2/js/fb_gfx_js.h +++ b/src/gfxlib2/js/fb_gfx_js.h @@ -17,13 +17,13 @@ typedef struct JS_GFXDRIVER_CTX_ SDL_Surface *canvas; BLITTER *blit; - unsigned long key_buffer[KEY_BUFFER_LEN]; - int key_head; - int key_tail; + int doNotCaptureKeyboard; } JS_GFXDRIVER_CTX; extern JS_GFXDRIVER_CTX __fb_js_ctx; -void fb_js_events_init(void); -void fb_js_events_check(void); +extern void fb_js_events_init(void); +extern void fb_js_events_exit(void); +extern void fb_js_events_check(void); +extern int fb_js_sdl_buttons_to_fb_buttons(int sdl_buttons); diff --git a/src/gfxlib2/js/gfx_driver.c b/src/gfxlib2/js/gfx_driver.c index d93b00ed28..355b7158ed 100644 --- a/src/gfxlib2/js/gfx_driver.c +++ b/src/gfxlib2/js/gfx_driver.c @@ -3,7 +3,15 @@ #include "../fb_gfx.h" #include "fb_gfx_js.h" -JS_GFXDRIVER_CTX __fb_js_ctx = { FALSE, FALSE, FALSE, FALSE, NULL }; +JS_GFXDRIVER_CTX __fb_js_ctx = +{ + .inited = FALSE, + .changingScreen = FALSE, + .updated = FALSE, + .blitting = FALSE, + .canvas = NULL, + .doNotCaptureKeyboard = 0, +}; static void driver_exit(void); @@ -93,6 +101,8 @@ static void driver_exit(void) __fb_js_ctx.canvas = NULL; } + fb_js_events_exit(); + SDL_Quit(); } } @@ -107,44 +117,61 @@ static void driver_unlock(void) /* !!!WRITEME!!! */ } -static void driver_set_palette(int index, int r, int g, int b) +static void driver_wait_vsync(void) { /* !!!WRITEME!!! */ } -static void driver_wait_vsync(void) +int fb_js_sdl_buttons_to_fb_buttons(int sdl_buttons) { - /* !!!WRITEME!!! */ + int fb_buttons = 0; + + if( sdl_buttons & SDL_BUTTON_LMASK) + fb_buttons |= BUTTON_LEFT; + if( sdl_buttons & SDL_BUTTON_MMASK) + fb_buttons |= BUTTON_MIDDLE; + if( sdl_buttons & SDL_BUTTON_RMASK) + fb_buttons |= BUTTON_RIGHT; + if( sdl_buttons & SDL_BUTTON_X1MASK) + fb_buttons |= BUTTON_X1; + if( sdl_buttons & SDL_BUTTON_X2MASK) + fb_buttons |= BUTTON_X2; + + return fb_buttons; } static int driver_get_mouse(int *x, int *y, int *z, int *buttons, int *clip) { - /* !!!WRITEME!!! */ + SDL_PumpEvents(); + + *buttons = fb_js_sdl_buttons_to_fb_buttons(SDL_GetMouseState(x, y)); + + *z = 0; + *clip = 0; + return 0; } static void driver_set_mouse(int x, int y, int cursor, int clip) { - /* !!!WRITEME!!! */ + //SDL_WarpMouseInWindow(NULL, x, y); } +static int modes[] = { + SCREENLIST(640, 480), + SCREENLIST(512, 512), + SCREENLIST(320, 240), + SCREENLIST(320, 200), + SCREENLIST(320, 100), + SCREENLIST(256, 256), + SCREENLIST(160, 120), + SCREENLIST(80, 80) +}; + static int *driver_fetch_modes(int depth, int *size) { - int num = 0; - int *modes = NULL, *new_modes; - - ++num; - new_modes = realloc(modes, sizeof(int) * num); - if (!new_modes) { - *size = num - 1; - return modes; - } - - modes = new_modes; - modes[num - 1] = SCREENLIST(320, 200); - - *size = num; - return modes; + *size = sizeof(modes) / sizeof(int); + return memcpy((void*)malloc(sizeof(modes)), modes, sizeof(modes)); } static void driver_poll_events(void) @@ -152,6 +179,11 @@ static void driver_poll_events(void) fb_js_events_check( ); } +static void driver_set_window_title(char *title) +{ + SDL_WM_SetCaption(title, NULL); +} + static const GFXDRIVER fb_gfxDriverJS = { "asmjs", /* char *name; */ @@ -159,11 +191,11 @@ static const GFXDRIVER fb_gfxDriverJS = driver_exit, /* void (*exit)(void); */ driver_lock, /* void (*lock)(void); */ driver_unlock, /* void (*unlock)(void); */ - driver_set_palette, /* void (*set_palette)(int index, int r, int g, int b); */ + NULL, /* void (*set_palette)(int index, int r, int g, int b); */ driver_wait_vsync, /* void (*wait_vsync)(void); */ driver_get_mouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */ driver_set_mouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */ - NULL, /* void (*set_window_title)(char *title); */ + driver_set_window_title, /* void (*set_window_title)(char *title); */ NULL, /* int (*set_window_pos)(int x, int y); */ driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */ NULL, /* void (*flip)(void); */ @@ -177,9 +209,9 @@ const GFXDRIVER *__fb_gfx_drivers_list[] = { void fb_hScreenInfo(ssize_t *width, ssize_t *height, ssize_t *depth, ssize_t *refresh) { - *width = __fb_gfx->w; - *height = __fb_gfx->h; - *depth = __fb_gfx->depth; + *width = 512; + *height = 512; + *depth = 32; *refresh = GFX_JS_FPS; } diff --git a/src/gfxlib2/js/gfx_events.c b/src/gfxlib2/js/gfx_events.c index 43b9acaaee..45300d6b03 100644 --- a/src/gfxlib2/js/gfx_events.c +++ b/src/gfxlib2/js/gfx_events.c @@ -3,54 +3,6 @@ static int sleep_called = 0; -static int fb_js_gfx_Getkey( void ) -{ - if( __fb_js_ctx.key_head == __fb_js_ctx.key_tail) - return 0; - - int key = __fb_js_ctx.key_buffer[__fb_js_ctx.key_head]; - __fb_js_ctx.key_head = (__fb_js_ctx.key_head + 1) % KEY_BUFFER_LEN; - - return key; -} - -static int fb_js_gfx_KeyHit( void ) -{ - return __fb_js_ctx.key_head != __fb_js_ctx.key_tail; -} - -static FBSTRING *fb_js_gfx_Inkey( void ) -{ - FBSTRING *res = &__fb_ctx.null_desc; - - if( fb_js_gfx_KeyHit( ) != 0 ) - { - res = fb_hMakeInkeyStr( fb_js_gfx_Getkey( ) ); - } - - return res; -} - -static void fb_js_key_down(SDL_Event *event) -{ - unsigned long key = event->key.keysym.sym; - - //emscripten_log(EM_LOG_CONSOLE, "%d, %d, %d", event->key.keysym.sym, event->key.keysym.scancode, key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key); - - __fb_js_ctx.key_buffer[__fb_js_ctx.key_tail] = key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key; - __fb_js_ctx.key_tail = (__fb_js_ctx.key_tail + 1) % KEY_BUFFER_LEN; - - if( __fb_js_ctx.key_tail == __fb_js_ctx.key_head ) - __fb_js_ctx.key_head = (__fb_js_ctx.key_head + 1) % KEY_BUFFER_LEN; - - //keys(event.key.keysym.sym) = 1 -} - -static void fb_js_key_up(SDL_Event *event) -{ - //keys(event.key.keysym.sym) = 0 -} - void fb_js_events_check(void) { SDL_PumpEvents(); @@ -61,12 +13,44 @@ void fb_js_events_check(void) { switch( event.type ) { - case SDL_KEYDOWN: - fb_js_key_down(&event); + case SDL_MOUSEMOTION: + { + EVENT e = + { + .type = EVENT_MOUSE_MOVE, + .x = event.motion.x, + .y = event.motion.y, + .dx = event.motion.xrel, + .dy = event.motion.yrel, + }; + + fb_hPostEvent(&e); break; - case SDL_KEYUP: - fb_js_key_up(&event); + } + + case SDL_MOUSEBUTTONDOWN: + { + EVENT e = + { + .type = EVENT_MOUSE_BUTTON_PRESS, + .button = fb_js_sdl_buttons_to_fb_buttons(event.button.button), + }; + + fb_hPostEvent(&e); break; + } + + case SDL_MOUSEBUTTONUP: + { + EVENT e = + { + .type = EVENT_MOUSE_BUTTON_RELEASE, + .button = fb_js_sdl_buttons_to_fb_buttons(event.button.button), + }; + + fb_hPostEvent(&e); + break; + } } } } @@ -82,11 +66,25 @@ static void fb_js_sleep(int msecs) void fb_js_events_init(void) { - __fb_ctx.hooks.inkeyproc = fb_js_gfx_Inkey; - __fb_ctx.hooks.getkeyproc = fb_js_gfx_Getkey; - __fb_ctx.hooks.keyhitproc = fb_js_gfx_KeyHit; - __fb_ctx.hooks.multikeyproc = NULL; __fb_ctx.hooks.sleepproc = fb_js_sleep; + // we can't use SDL's key events because CAPSLOCK isn't handled by emscripten and the printable chars are always lowercase in SDL + __fb_ctx.hooks.inkeyproc = NULL; + __fb_ctx.hooks.getkeyproc = NULL; + __fb_ctx.hooks.keyhitproc = NULL; + __fb_ctx.hooks.multikeyproc = NULL; + __fb_ctx.hooks.posteventproc = fb_hPostEvent; + + // don't let SDL capture the keyboard + __fb_js_ctx.doNotCaptureKeyboard = emscripten_run_script_int("Module['doNotCaptureKeyboard']? 1: 0;"); + if(!__fb_js_ctx.doNotCaptureKeyboard) + emscripten_run_script("Module['doNotCaptureKeyboard']=1;"); + return; } + +void fb_js_events_exit(void) +{ + if(!__fb_js_ctx.doNotCaptureKeyboard) + emscripten_run_script("Module['doNotCaptureKeyboard']=null;"); +} diff --git a/src/rtlib/fb.h b/src/rtlib/fb.h index eff681088c..811046bdf5 100644 --- a/src/rtlib/fb.h +++ b/src/rtlib/fb.h @@ -322,125 +322,11 @@ void fb_hListDynElemRemove ( FB_LIST *list, FB_LISTELEM *elem ) #include "fb_printer.h" #include "fb_datetime.h" #include "fb_thread.h" +#include "fb_event.h" #include "fb_hook.h" #include "fb_oop.h" #include "fb_legacy.h" -/* DOS keyboard scancodes */ -#define SC_ESCAPE 0x01 -#define SC_1 0x02 -#define SC_2 0x03 -#define SC_3 0x04 -#define SC_4 0x05 -#define SC_5 0x06 -#define SC_6 0x07 -#define SC_7 0x08 -#define SC_8 0x09 -#define SC_9 0x0A -#define SC_0 0x0B -#define SC_MINUS 0x0C -#define SC_EQUALS 0x0D -#define SC_BACKSPACE 0x0E -#define SC_TAB 0x0F -#define SC_Q 0x10 -#define SC_W 0x11 -#define SC_E 0x12 -#define SC_R 0x13 -#define SC_T 0x14 -#define SC_Y 0x15 -#define SC_U 0x16 -#define SC_I 0x17 -#define SC_O 0x18 -#define SC_P 0x19 -#define SC_LEFTBRACKET 0x1A -#define SC_RIGHTBRACKET 0x1B -#define SC_ENTER 0x1C -#define SC_CONTROL 0x1D -#define SC_A 0x1E -#define SC_S 0x1F -#define SC_D 0x20 -#define SC_F 0x21 -#define SC_G 0x22 -#define SC_H 0x23 -#define SC_J 0x24 -#define SC_K 0x25 -#define SC_L 0x26 -#define SC_SEMICOLON 0x27 -#define SC_QUOTE 0x28 -#define SC_TILDE 0x29 -#define SC_LSHIFT 0x2A -#define SC_BACKSLASH 0x2B -#define SC_Z 0x2C -#define SC_X 0x2D -#define SC_C 0x2E -#define SC_V 0x2F -#define SC_B 0x30 -#define SC_N 0x31 -#define SC_M 0x32 -#define SC_COMMA 0x33 -#define SC_PERIOD 0x34 -#define SC_SLASH 0x35 -#define SC_RSHIFT 0x36 -#define SC_MULTIPLY 0x37 -#define SC_ALT 0x38 -#define SC_SPACE 0x39 -#define SC_CAPSLOCK 0x3A -#define SC_F1 0x3B -#define SC_F2 0x3C -#define SC_F3 0x3D -#define SC_F4 0x3E -#define SC_F5 0x3F -#define SC_F6 0x40 -#define SC_F7 0x41 -#define SC_F8 0x42 -#define SC_F9 0x43 -#define SC_F10 0x44 -#define SC_NUMLOCK 0x45 -#define SC_SCROLLLOCK 0x46 -#define SC_HOME 0x47 -#define SC_UP 0x48 -#define SC_PAGEUP 0x49 -#define SC_LEFT 0x4B -#define SC_CLEAR 0x4C -#define SC_RIGHT 0x4D -#define SC_PLUS 0x4E -#define SC_END 0x4F -#define SC_DOWN 0x50 -#define SC_PAGEDOWN 0x51 -#define SC_INSERT 0x52 -#define SC_DELETE 0x53 -#define SC_F11 0x57 -#define SC_F12 0x58 -#define SC_LWIN 0x5B -#define SC_RWIN 0x5C -#define SC_MENU 0x5D -#define SC_ALTGR 0x64 - -#define KEY_BACKSPACE 8 -#define KEY_TAB '\t' -#define KEY_F1 FB_MAKE_EXT_KEY( ';' ) -#define KEY_F2 FB_MAKE_EXT_KEY( '<' ) -#define KEY_F3 FB_MAKE_EXT_KEY( '=' ) -#define KEY_F4 FB_MAKE_EXT_KEY( '>' ) -#define KEY_F5 FB_MAKE_EXT_KEY( '?' ) -#define KEY_F6 FB_MAKE_EXT_KEY( '@' ) -#define KEY_F7 FB_MAKE_EXT_KEY( 'A' ) -#define KEY_F8 FB_MAKE_EXT_KEY( 'B' ) -#define KEY_F9 FB_MAKE_EXT_KEY( 'C' ) -#define KEY_F10 FB_MAKE_EXT_KEY( 'D' ) -#define KEY_HOME FB_MAKE_EXT_KEY( 'G' ) -#define KEY_UP FB_MAKE_EXT_KEY( 'H' ) -#define KEY_PAGE_UP FB_MAKE_EXT_KEY( 'I' ) -#define KEY_LEFT FB_MAKE_EXT_KEY( 'K' ) -#define KEY_CLEAR FB_MAKE_EXT_KEY( 'L' ) -#define KEY_RIGHT FB_MAKE_EXT_KEY( 'M' ) -#define KEY_END FB_MAKE_EXT_KEY( 'O' ) -#define KEY_DOWN FB_MAKE_EXT_KEY( 'P' ) -#define KEY_PAGE_DOWN FB_MAKE_EXT_KEY( 'Q' ) -#define KEY_INS FB_MAKE_EXT_KEY( 'R' ) -#define KEY_DEL FB_MAKE_EXT_KEY( 'S' ) -#define KEY_QUIT FB_MAKE_EXT_KEY( 'k' ) - FBSTRING *fb_hMakeInkeyStr( int ch ); int fb_hScancodeToExtendedKey( int scancode ); diff --git a/src/rtlib/fb_event.h b/src/rtlib/fb_event.h new file mode 100644 index 0000000000..2b182a3dda --- /dev/null +++ b/src/rtlib/fb_event.h @@ -0,0 +1,159 @@ +struct _EVENT { + int type; + union { + struct { /* keyboard events */ + int scancode; + int ascii; + }; + struct { /* mouse events */ + int x, y; + int dx, dy; + }; + int button; + int z; + int w; + }; +} FBPACKED; + +typedef struct _EVENT EVENT; + +#define EVENT_KEY_PRESS 1 +#define EVENT_KEY_RELEASE 2 +#define EVENT_KEY_REPEAT 3 +#define EVENT_MOUSE_MOVE 4 +#define EVENT_MOUSE_BUTTON_PRESS 5 +#define EVENT_MOUSE_BUTTON_RELEASE 6 +#define EVENT_MOUSE_DOUBLE_CLICK 7 +#define EVENT_MOUSE_WHEEL 8 +#define EVENT_MOUSE_ENTER 9 +#define EVENT_MOUSE_EXIT 10 +#define EVENT_WINDOW_GOT_FOCUS 11 +#define EVENT_WINDOW_LOST_FOCUS 12 +#define EVENT_WINDOW_CLOSE 13 +#define EVENT_MOUSE_HWHEEL 14 + +#define MAX_EVENTS 128 + +#define BUTTON_LEFT 0x1 +#define BUTTON_RIGHT 0x2 +#define BUTTON_MIDDLE 0x4 +#define BUTTON_X1 0x8 +#define BUTTON_X2 0x10 + +/* DOS keyboard scancodes */ +#define SC_ESCAPE 0x01 +#define SC_1 0x02 +#define SC_2 0x03 +#define SC_3 0x04 +#define SC_4 0x05 +#define SC_5 0x06 +#define SC_6 0x07 +#define SC_7 0x08 +#define SC_8 0x09 +#define SC_9 0x0A +#define SC_0 0x0B +#define SC_MINUS 0x0C +#define SC_EQUALS 0x0D +#define SC_BACKSPACE 0x0E +#define SC_TAB 0x0F +#define SC_Q 0x10 +#define SC_W 0x11 +#define SC_E 0x12 +#define SC_R 0x13 +#define SC_T 0x14 +#define SC_Y 0x15 +#define SC_U 0x16 +#define SC_I 0x17 +#define SC_O 0x18 +#define SC_P 0x19 +#define SC_LEFTBRACKET 0x1A +#define SC_RIGHTBRACKET 0x1B +#define SC_ENTER 0x1C +#define SC_CONTROL 0x1D +#define SC_A 0x1E +#define SC_S 0x1F +#define SC_D 0x20 +#define SC_F 0x21 +#define SC_G 0x22 +#define SC_H 0x23 +#define SC_J 0x24 +#define SC_K 0x25 +#define SC_L 0x26 +#define SC_SEMICOLON 0x27 +#define SC_QUOTE 0x28 +#define SC_TILDE 0x29 +#define SC_LSHIFT 0x2A +#define SC_BACKSLASH 0x2B +#define SC_Z 0x2C +#define SC_X 0x2D +#define SC_C 0x2E +#define SC_V 0x2F +#define SC_B 0x30 +#define SC_N 0x31 +#define SC_M 0x32 +#define SC_COMMA 0x33 +#define SC_PERIOD 0x34 +#define SC_SLASH 0x35 +#define SC_RSHIFT 0x36 +#define SC_MULTIPLY 0x37 +#define SC_ALT 0x38 +#define SC_SPACE 0x39 +#define SC_CAPSLOCK 0x3A +#define SC_F1 0x3B +#define SC_F2 0x3C +#define SC_F3 0x3D +#define SC_F4 0x3E +#define SC_F5 0x3F +#define SC_F6 0x40 +#define SC_F7 0x41 +#define SC_F8 0x42 +#define SC_F9 0x43 +#define SC_F10 0x44 +#define SC_NUMLOCK 0x45 +#define SC_SCROLLLOCK 0x46 +#define SC_HOME 0x47 +#define SC_UP 0x48 +#define SC_PAGEUP 0x49 +#define SC_LEFT 0x4B +#define SC_CLEAR 0x4C +#define SC_RIGHT 0x4D +#define SC_PLUS 0x4E +#define SC_END 0x4F +#define SC_DOWN 0x50 +#define SC_PAGEDOWN 0x51 +#define SC_INSERT 0x52 +#define SC_DELETE 0x53 +#define SC_F11 0x57 +#define SC_F12 0x58 +#define SC_LWIN 0x5B +#define SC_RWIN 0x5C +#define SC_MENU 0x5D +#define SC_ALTGR 0x64 + +#define KEY_BACKSPACE 8 +#define KEY_TAB '\t' +#define KEY_F1 FB_MAKE_EXT_KEY( ';' ) +#define KEY_F2 FB_MAKE_EXT_KEY( '<' ) +#define KEY_F3 FB_MAKE_EXT_KEY( '=' ) +#define KEY_F4 FB_MAKE_EXT_KEY( '>' ) +#define KEY_F5 FB_MAKE_EXT_KEY( '?' ) +#define KEY_F6 FB_MAKE_EXT_KEY( '@' ) +#define KEY_F7 FB_MAKE_EXT_KEY( 'A' ) +#define KEY_F8 FB_MAKE_EXT_KEY( 'B' ) +#define KEY_F9 FB_MAKE_EXT_KEY( 'C' ) +#define KEY_F10 FB_MAKE_EXT_KEY( 'D' ) +#define KEY_HOME FB_MAKE_EXT_KEY( 'G' ) +#define KEY_UP FB_MAKE_EXT_KEY( 'H' ) +#define KEY_PAGE_UP FB_MAKE_EXT_KEY( 'I' ) +#define KEY_LEFT FB_MAKE_EXT_KEY( 'K' ) +#define KEY_CLEAR FB_MAKE_EXT_KEY( 'L' ) +#define KEY_RIGHT FB_MAKE_EXT_KEY( 'M' ) +#define KEY_END FB_MAKE_EXT_KEY( 'O' ) +#define KEY_DOWN FB_MAKE_EXT_KEY( 'P' ) +#define KEY_PAGE_DOWN FB_MAKE_EXT_KEY( 'Q' ) +#define KEY_INS FB_MAKE_EXT_KEY( 'R' ) +#define KEY_DEL FB_MAKE_EXT_KEY( 'S' ) +#define KEY_QUIT FB_MAKE_EXT_KEY( 'k' ) + +#define QB_EXTK(x)(((unsigned short)(x))<<8|0xff) + diff --git a/src/rtlib/fb_hook.h b/src/rtlib/fb_hook.h index 9b4ef32948..684beef7bb 100644 --- a/src/rtlib/fb_hook.h +++ b/src/rtlib/fb_hook.h @@ -88,6 +88,8 @@ typedef int (*FB_PAGECOPYPROC) ( int src, int dst ); FBCALL int fb_PageSet ( int active, int visible ); typedef int (*FB_PAGESETPROC) ( int active, int visible ); +typedef void (*FB_POSTEVENTPROC) (EVENT *e); + typedef struct FB_HOOKSTB { FB_INKEYPROC inkeyproc; FB_GETKEYPROC getkeyproc; @@ -116,4 +118,5 @@ typedef struct FB_HOOKSTB { FB_ISREDIRPROC isredirproc; FB_PAGECOPYPROC pagecopyproc; FB_PAGESETPROC pagesetproc; + FB_POSTEVENTPROC posteventproc; } FB_HOOKSTB; diff --git a/src/rtlib/js/fb_private_console.h b/src/rtlib/js/fb_private_console.h index 9cf2535a7a..8d2b0a27fb 100644 --- a/src/rtlib/js/fb_private_console.h +++ b/src/rtlib/js/fb_private_console.h @@ -3,15 +3,28 @@ #define KEY_BUFFER_LEN 256 +typedef struct _FB_CONSOLE_MOUSE { + int x; + int y; + int z; + int dx; + int dy; + int button; +} FB_CONSOLE_MOUSE; + typedef struct _FB_CONSOLE_CTX { - int active, visible; - int w, h; - unsigned long key_buffer[KEY_BUFFER_LEN]; - int key_head; - int key_tail; + int active, visible; + int w, h; + unsigned long key_buffer[KEY_BUFFER_LEN]; + int key_head; + int key_tail; + unsigned char multikey[128]; + FB_CONSOLE_MOUSE mouse; } FB_CONSOLE_CTX; extern FB_CONSOLE_CTX __fb_con; -extern EM_BOOL fb_hKeyPressedCB(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); +extern EM_BOOL fb_hKeyEventHandler(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData); +extern EM_BOOL fb_hMouseEventHandler(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); +extern EM_BOOL fb_hMouseWheelEventHandler(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData); diff --git a/src/rtlib/js/hinit.c b/src/rtlib/js/hinit.c index 84f6e4768e..43575a38a4 100644 --- a/src/rtlib/js/hinit.c +++ b/src/rtlib/js/hinit.c @@ -20,7 +20,17 @@ void fb_hInit( void ) { memset( &__fb_con, 0, sizeof(__fb_con) ); - emscripten_set_keypress_callback( 0, 0, 1, fb_hKeyPressedCB ); + // keyboard + emscripten_set_keypress_callback( 0, NULL, 1, fb_hKeyEventHandler ); + emscripten_set_keydown_callback( 0, NULL, 1, fb_hKeyEventHandler ); + emscripten_set_keyup_callback( 0, NULL, 1, fb_hKeyEventHandler ); + + // mouse + emscripten_set_mousemove_callback( 0, NULL, 1, fb_hMouseEventHandler ); + emscripten_set_mousedown_callback( 0, NULL, 1, fb_hMouseEventHandler ); + emscripten_set_mouseup_callback( 0, NULL, 1, fb_hMouseEventHandler ); + emscripten_set_dblclick_callback( 0, NULL, 1, fb_hMouseEventHandler ); + //emscripten_set_wheel_callback( 0, NULL, 1, fb_hMouseWheelEventHandler ); } void fb_hEnd( int unused ) diff --git a/src/rtlib/js/io_input.c b/src/rtlib/js/io_input.c index 691a5e7ee7..aae35d12ec 100644 --- a/src/rtlib/js/io_input.c +++ b/src/rtlib/js/io_input.c @@ -2,29 +2,407 @@ #include "../fb.h" #include "fb_private_console.h" +#include -EM_BOOL fb_hKeyPressedCB(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +// QB key codes that are processed by keydown +static const unsigned short js_keycode_to_qb_key_tb[128] = { - if( eventType != EMSCRIPTEN_EVENT_KEYPRESS ) - return 0; + [ 8] = 8, /* backspace */ + [ 9] = 9, /* tab */ + [ 13] = 13, /* enter */ + [ 27] = 27, /* esc */ + [ 33] = QB_EXTK(73), /* pgup */ + [ 34] = QB_EXTK(81), /* pgdown */ + [ 35] = QB_EXTK(79), /* end */ + [ 36] = QB_EXTK(71), /* home */ + [ 37] = QB_EXTK(75), /* left */ + [ 38] = QB_EXTK(72), /* up */ + [ 39] = QB_EXTK(77), /* right */ + [ 40] = QB_EXTK(80), /* down */ + [ 45] = QB_EXTK(82), /* insert */ + [ 46] = QB_EXTK(83), /* delete */ + [112] = QB_EXTK(59), /* F1 */ + [113] = QB_EXTK(60), /* F2 */ + [114] = QB_EXTK(61), /* F3 */ + [115] = QB_EXTK(62), /* F4 */ + [116] = QB_EXTK(63), /* F5 */ + [117] = QB_EXTK(64), /* F6 */ + [118] = QB_EXTK(65), /* F7 */ + [119] = QB_EXTK(66), /* F8 */ + [120] = QB_EXTK(67), /* F9 */ + [121] = QB_EXTK(68), /* F10 */ + [122] = QB_EXTK(133), /* F11 */ + [123] = QB_EXTK(134), /* F12 */ +}; - // !!!FIXME!!! convert ctrlKey, shiftKey and altKey - // !!!FIXME!!! check repeat +// QB key codes returned when CTRL is pressed +static const unsigned short js_keycode_to_qb_key_ctrl_tb[128] = +{ + [ 8] = 127, /* backspace */ + [ 13] = 10, /* enter */ + [ 32] = 32, /* espace */ + [ 33] = QB_EXTK(132), /* pgup */ + [ 34] = QB_EXTK(118), /* pgdown */ + [ 35] = QB_EXTK(117), /* end */ + [ 36] = QB_EXTK(119), /* home */ + [ 37] = QB_EXTK(115), /* left */ + [ 38] = QB_EXTK(141), /* up */ + [ 39] = QB_EXTK(116), /* right */ + [ 40] = QB_EXTK(145), /* down */ + [ 45] = QB_EXTK(146), /* insert */ + [ 46] = QB_EXTK(147), /* delete */ + [ 65] = 1, /* A */ + [ 66] = 2, /* B */ + [ 67] = 3, /* C */ + [ 68] = 4, /* D */ + [ 69] = 5, /* E */ + [ 70] = 6, /* F */ + [ 71] = 7, /* G */ + [ 72] = 8, /* H */ + [ 73] = 9, /* I */ + [ 74] = 10, /* J */ + [ 75] = 11, /* K */ + [ 76] = 12, /* L */ + [ 77] = 13, /* M */ + [ 78] = 14, /* N */ + [ 79] = 15, /* O */ + [ 80] = 16, /* P */ + [ 81] = 17, /* Q */ + [ 82] = 18, /* R */ + [ 83] = 19, /* S */ + [ 84] = 20, /* T */ + [ 85] = 21, /* U */ + [ 86] = 22, /* V */ + [ 87] = 23, /* W */ + [ 88] = 24, /* X */ + [ 89] = 25, /* Y */ + [ 90] = 26, /* Z */ + [ 91] = 27, /* [ */ + [ 92] = 28, /* \ */ + [ 93] = 29, /* ] */ + [112] = QB_EXTK(94), /* F1 */ + [113] = QB_EXTK(95), /* F2 */ + [114] = QB_EXTK(96), /*__fb_ctx.hooks.posteventproc(&fb_event); F3 */ + [115] = QB_EXTK(97), /* F4 */ + [116] = QB_EXTK(98), /* F5 */ + [117] = QB_EXTK(99), /* F6 */ + [118] = QB_EXTK(100), /* F7 */ + [119] = QB_EXTK(101), /* F8 */ + [120] = QB_EXTK(102), /* F9 */ + [121] = QB_EXTK(103), /* F10 */ + [122] = QB_EXTK(137), /* F11 */ + [123] = QB_EXTK(138), /* F12 */ +}; + +// keycodes that should not be remapped by keydown +static const unsigned char js_keycode_to_not_process_tb[256] = +{ + [ 16] = 1, /* shift */ + [ 17] = 1, /* ctrl */ + [ 18] = 1, /* alt */ + [ 20] = 1, /* capslock */ + [ 32] = 1, /* espace */ + [ 59] = 1, /* ; */ + [ 61] = 1, /* = */ + [ 91] = 1, /* lwin */ + [ 93] = 1, /* menu */ + [144] = 1, /* numlock */ + [145] = 1, /* scrolllock */ + [173] = 1, /* - */ + [176] = 1, /* ~ */ + [188] = 1, /* , */ + [190] = 1, /* . */ + [191] = 1, /* / */ + [219] = 1, /* [ */ + [220] = 1, /* \ */ + [221] = 1, /* ] */ + [222] = 1, /* ' */ +}; + +// keyboard scan codes returned my MultiKey() +static const unsigned char js_keycode_to_qb_scancode_tb[256] = +{ + [ 8] = SC_BACKSPACE, + [ 9] = SC_TAB, + [ 13] = SC_ENTER, + [ 20] = SC_CAPSLOCK, + [ 27] = SC_ESCAPE, + [ 32] = SC_SPACE, + [ 33] = SC_PAGEUP, + [ 34] = SC_PAGEDOWN, + [ 35] = SC_END, + [ 36] = SC_HOME, + [ 37] = SC_LEFT, + [ 38] = SC_UP, + [ 39] = SC_RIGHT, + [ 40] = SC_DOWN, + [ 45] = SC_INSERT, + [ 46] = SC_DELETE, + [ 48] = SC_0, + [ 49] = SC_1, + [ 50] = SC_2, + [ 51] = SC_3, + [ 52] = SC_4, + [ 53] = SC_5, + [ 54] = SC_6, + [ 55] = SC_7, + [ 56] = SC_8, + [ 57] = SC_9, + [ 59] = SC_SEMICOLON, + [ 61] = SC_EQUALS, + [ 65] = SC_A, + [ 66] = SC_B, + [ 67] = SC_C, + [ 68] = SC_D, + [ 69] = SC_E, + [ 70] = SC_F, + [ 71] = SC_G, + [ 72] = SC_H, + [ 73] = SC_I, + [ 74] = SC_J, + [ 75] = SC_K, + [ 76] = SC_L, + [ 77] = SC_M, + [ 78] = SC_N, + [ 79] = SC_O, + [ 80] = SC_P, + [ 81] = SC_Q, + [ 82] = SC_R, + [ 83] = SC_S, + [ 84] = SC_T, + [ 85] = SC_U, + [ 86] = SC_V, + [ 87] = SC_W, + [ 88] = SC_X, + [ 89] = SC_Y, + [ 90] = SC_Z, + [ 93] = SC_MENU, + [106] = SC_MULTIPLY, /* * (numpad) */ + [107] = SC_PLUS, /* + (numpad) */ + [108] = SC_PERIOD, /* . (numpad) */ + [109] = SC_MINUS, /* - (numpad) */ + [110] = SC_COMMA, /* , (numpad) */ + [111] = SC_SLASH, /* / (numpad) */ + [112] = SC_F1, + [113] = SC_F2, + [114] = SC_F3, + [115] = SC_F4, + [116] = SC_F5, + [117] = SC_F6, + [118] = SC_F7, + [119] = SC_F8, + [120] = SC_F9, + [121] = SC_F10, + [122] = SC_F11, + [123] = SC_F12, + [144] = SC_NUMLOCK, + [145] = SC_SCROLLLOCK, + [173] = SC_MINUS, + [176] = SC_TILDE, + [188] = SC_COMMA, + [190] = SC_PERIOD, + [191] = SC_SLASH, + [219] = SC_LEFTBRACKET, + [220] = SC_BACKSLASH, + [221] = SC_RIGHTBRACKET, + [222] = SC_QUOTE, +}; + +static unsigned int js_keycode_to_qb_key(const EmscriptenKeyboardEvent *keyEvent) +{ + unsigned int key = keyEvent->keyCode; + + // numpad? + if( keyEvent->location == 3 ) + { + // numlock on? let keypress process it + if( key > 46 ) + return 0; + } + + // ctrl? remap to the special qb keys + if( keyEvent->ctrlKey ) + { + if( key < 128 ) + key = js_keycode_to_qb_key_ctrl_tb[key]; + } + else + { + // printable character or other key that should not be returned to inkey()? let keypress do the rest + if( (key >= 'A' && key <= 'Z') || + (key >= '0' && key <= '9') || + (key < 256 && js_keycode_to_not_process_tb[key] != 0) ) + { + return 0; + } + else + { + // remap to QB key code + if( key < 128 ) + { + unsigned short qbkey = js_keycode_to_qb_key_tb[key]; + if( qbkey != 0 ) + key = qbkey; + } + } + } + + return key; +} + +static unsigned int js_multikey_handler(unsigned long key, unsigned long location, int isKeyDown) +{ + unsigned int scancode = 0; + + if( key < 256 ) + { + switch( key ) + { + // shift? + case 16: + /* location == 1? left-shift: right-shift */ + scancode = location == 1? SC_LSHIFT: SC_RSHIFT; + break; + + // ctrl? + case 17: + /* location == 1? left-ctrl: right-ctrl */ + scancode = location == 1? SC_CONTROL: SC_CONTROL; + break; - unsigned long key = keyEvent->keyCode != 0? keyEvent->keyCode: keyEvent->charCode; + // alt? + case 18: + /* location == 1? left-alt: alt-gr */ + scancode = location == 1? SC_ALT: SC_ALTGR; + break; - //emscripten_log(EM_LOG_CONSOLE, "%d, %d, %d, %d, %d", keyEvent->keyCode, keyEvent->charCode, key > 0x00FF? ((key & 0x00FF) << 8 | 0x00FF): key, keyEvent->key[0], keyEvent->code[0]); + // win? + case 91: + /* location == 1? lwin: rwin */ + scancode = location == 1? SC_LWIN: SC_RWIN; + break; + default: + scancode = js_keycode_to_qb_scancode_tb[key]; + break; + } + + __fb_con.multikey[scancode] = isKeyDown? 1: 0; + } + + return scancode; +} + +static void js_key_buffer_add(unsigned int key) +{ __fb_con.key_buffer[__fb_con.key_tail] = key; __fb_con.key_tail = (__fb_con.key_tail + 1) % KEY_BUFFER_LEN; if( __fb_con.key_tail == __fb_con.key_head ) __fb_con.key_head = (__fb_con.key_head + 1) % KEY_BUFFER_LEN; - return 1; +} + +EM_BOOL fb_hKeyEventHandler(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +{ + static unsigned int scancode; + static unsigned int keycode; + + switch( eventType ) + { + case EMSCRIPTEN_EVENT_KEYDOWN: + { + EM_BOOL supress_keypress = 0; + if( keyEvent->keyCode != 0) + { + keycode = js_keycode_to_qb_key( keyEvent ); + if( keycode != 0 ) + { + js_key_buffer_add(keycode); + // as the key code was added to Inkey's buffer, supress the keypress handler + supress_keypress = 1; + } + + scancode = js_multikey_handler(keyEvent->keyCode, keyEvent->location, TRUE); + + if( supress_keypress ) + { + if(__fb_ctx.hooks.posteventproc != NULL) + { + EVENT fb_event = { .type = EVENT_KEY_PRESS, .scancode = scancode, .ascii = scancode }; + __fb_ctx.hooks.posteventproc(&fb_event); + } + + } + } + + return supress_keypress; + } + + case EMSCRIPTEN_EVENT_KEYPRESS: + { + // printable char and CTRL not pressed? add it to Inkey's buffer.. + keycode = keyEvent->charCode; + if( keycode != 0) + { + if( keyEvent->ctrlKey == 0) + { + js_key_buffer_add(keycode); + + if(__fb_ctx.hooks.posteventproc != NULL) + { + EVENT fb_event = { .type = EVENT_KEY_PRESS, .scancode = scancode, .ascii = keycode }; + __fb_ctx.hooks.posteventproc(&fb_event); + } + } + } + + return 0; + } + + case EMSCRIPTEN_EVENT_KEYUP: + { + scancode = js_multikey_handler(keyEvent->keyCode, keyEvent->location, FALSE); + + if(__fb_ctx.hooks.posteventproc != NULL) + { + EVENT fb_event = { .type = EVENT_KEY_RELEASE, .scancode = scancode, .ascii = keycode }; + __fb_ctx.hooks.posteventproc(&fb_event); + } + + return 1; + } + + default: + { + return 0; + } + } +} + +EM_BOOL fb_hMouseEventHandler(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + switch( eventType ) + { + case EMSCRIPTEN_EVENT_MOUSEMOVE: + case EMSCRIPTEN_EVENT_MOUSEDOWN: + case EMSCRIPTEN_EVENT_MOUSEUP: + case EMSCRIPTEN_EVENT_DBLCLICK: + { + __fb_con.mouse.x = mouseEvent->clientX; + __fb_con.mouse.y = mouseEvent->clientY; + __fb_con.mouse.dx = mouseEvent->movementX; + __fb_con.mouse.dy = mouseEvent->movementY; + __fb_con.mouse.button = mouseEvent->button == 0? BUTTON_LEFT: (mouseEvent->button == 1? BUTTON_MIDDLE: BUTTON_RIGHT); + break; + } + } + + return 0; } int fb_hConsoleInputBufferChanged( void ) { return fb_ConsoleKeyHit(); } + diff --git a/src/rtlib/js/io_mouse.c b/src/rtlib/js/io_mouse.c index 7884422e3a..c9b6017ff6 100644 --- a/src/rtlib/js/io_mouse.c +++ b/src/rtlib/js/io_mouse.c @@ -1,13 +1,49 @@ /* console mode mouse functions */ #include "../fb.h" +#include "fb_private_console.h" +#include "../../gfxlib2/fb_gfx.h" int fb_ConsoleGetMouse( int *x, int *y, int *z, int *buttons, int *clip ) { - return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); + EmscriptenMouseEvent mouseState; + + if( emscripten_get_mouse_status( &mouseState ) != EMSCRIPTEN_RESULT_SUCCESS ) + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); + + if( x != NULL ) + *x = mouseState.clientX; + + if( y != NULL ) + *y = mouseState.clientY; + + if( z != NULL ) + *z = 0; + + if( buttons != NULL ) + { + int mbuttons = 0; + if( mouseState.buttons & 1) + mbuttons |= BUTTON_LEFT; + if( mouseState.buttons & 2) + mbuttons |= BUTTON_RIGHT; + if( mouseState.buttons & 4) + mbuttons |= BUTTON_MIDDLE; + if( mouseState.buttons & 8) + mbuttons |= BUTTON_X1; + if( mouseState.buttons & 16) + mbuttons |= BUTTON_X2; + + *buttons = mbuttons; + } + + if( clip != NULL ) + *clip = 0; + + return fb_ErrorSetNum( FB_RTERROR_OK ); } int fb_ConsoleSetMouse( int x, int y, int cursor, int clip ) { - return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); + return fb_ErrorSetNum( FB_RTERROR_OK ); } diff --git a/src/rtlib/js/io_multikey.c b/src/rtlib/js/io_multikey.c index 1951c9b38b..59aff525c7 100644 --- a/src/rtlib/js/io_multikey.c +++ b/src/rtlib/js/io_multikey.c @@ -1,9 +1,12 @@ /* console multikey() */ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleMultikey( int scancode ) { - fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); - return FB_FALSE; + if( scancode < 0 || scancode > 255 ) + fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); + + return __fb_con.multikey[scancode] != 0? FB_TRUE: FB_FALSE; } From 8d652fe0536c218f464d3e7d82b7e00dd3707316 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Thu, 15 Oct 2015 22:06:23 -0300 Subject: [PATCH 6/8] added: new shell and terminal --- lib/termlib_min.js | 370 ++++++++++++++++++++++++++++++ makefile | 6 + src/compiler/fbc.bas | 21 +- src/rtlib/con_lineinp.c | 2 +- src/rtlib/js/fb_private_console.h | 18 ++ src/rtlib/js/hinit.c | 30 ++- src/rtlib/js/io_color.c | 22 +- src/rtlib/js/io_getxy.c | 5 + src/rtlib/js/io_locate.c | 7 +- src/rtlib/js/io_pageset.c | 2 +- src/rtlib/js/io_printbuff_wstr.c | 3 +- src/rtlib/js/io_readxy.c | 1 + src/rtlib/js/io_scroll.c | 1 + src/rtlib/js/io_width.c | 2 +- src/rtlib/js/sys_getcwd.c | 1 - src/rtlib/js/sys_getexename.c | 1 - src/rtlib/js/sys_getexepath.c | 1 - src/rtlib/js/sys_getshortpath.c | 1 - src/rtlib/js/time_setdate.c | 1 - src/rtlib/js/time_settime.c | 1 - 20 files changed, 480 insertions(+), 16 deletions(-) create mode 100644 lib/termlib_min.js diff --git a/lib/termlib_min.js b/lib/termlib_min.js new file mode 100644 index 0000000000..0d979adbf7 --- /dev/null +++ b/lib/termlib_min.js @@ -0,0 +1,370 @@ +/* + termlib.js - JS-WebTerminal Object v1.66 (source compacted using jsmin.php) + + (c) Norbert Landsteiner 2003-2015 + mass:werk - media environments + + + Creates [multiple] Terminal instances. + + Synopsis: + + myTerminal = new Terminal(); + myTerminal.open(); + + See file "readme.txt" for documentation and usage. + + License: + This JavaScript-library is free. + Include a visible backlink to in the + embedding web page or application. + The library should always be accompanied by the 'readme.txt' and the + sample HTML-documents. + + Any changes should be commented and must be reflected in `Terminal.version' + in the format: "Version.Subversion (compatibility)". + + Disclaimer: + This software is distributed AS IS and in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. The entire risk as to + the quality and performance of the product is borne by the user. No use of + the product is authorized hereunder except under this disclaimer. +*/ +var Terminal=function(conf){if(typeof conf!='object')conf=new Object();for(var i in this.Defaults){if(typeof conf[i]=='undefined')conf[i]=this.Defaults[i];} +if(typeof conf.handler!='function')conf.handler=Terminal.prototype.defaultHandler;this.conf=conf;this.setInitValues();} +Terminal.prototype={version:'1.66 (original)',Defaults:{cols:80,rows:24,x:100,y:100,termDiv:'termDiv',bgColor:'#181818',frameColor:'#555555',frameWidth:1,rowHeight:15,blinkDelay:500,fontClass:'term',crsrBlinkMode:false,crsrBlockMode:true,DELisBS:false,printTab:true,printEuro:true,catchCtrlH:true,closeOnESC:true,historyUnique:false,id:0,ps:'>',greeting:'%+r Terminal ready. %-r',handler:null,ctrlHandler:null,initHandler:null,exitHandler:null,wrapping:false,mapANSI:false,ANSItrueBlack:false,textBlur:0,textColor:''},setInitValues:function(){this.isSafari=(navigator.userAgent.indexOf('Safari')>=0||navigator.userAgent.indexOf('WebKit')>=0)?true:false;this.isOpera=(window.opera&&navigator.userAgent.indexOf('Opera')>=0)?true:false;this.isChrome=(navigator.userAgent.indexOf('Chrome/')>=0&&navigator.userAgent.indexOf('WebKit')>=0)?true:false;this.domAPI=(document&&document.createElement)?true:false;this.isMac=(navigator.userAgent.indexOf('Mac')>=0)?true:false;this.id=this.conf.id;this.maxLines=this.conf.rows;this.maxCols=this.conf.cols;this.termDiv=this.conf.termDiv;this.crsrBlinkMode=this.conf.crsrBlinkMode;this.crsrBlockMode=this.conf.crsrBlockMode;this.blinkDelay=this.conf.blinkDelay;this.DELisBS=this.conf.DELisBS;this.printTab=this.conf.printTab;this.printEuro=this.conf.printEuro;this.catchCtrlH=this.conf.catchCtrlH;this.closeOnESC=this.conf.closeOnESC;this.historyUnique=this.conf.historyUnique;this.ps=this.conf.ps;this.closed=false;this.r;this.c;this.charBuf=new Array();this.styleBuf=new Array();this.scrollBuf=null;this.blinkBuffer=0;this.blinkTimer;this.cursoractive=false;this.lock=true;this.insert=false;this.charMode=false;this.rawMode=false;this.lineBuffer='';this.inputChar=0;this.lastLine='';this.guiCounter=0;this.history=new Array();this.histPtr=0;this.env=new Object();this.buckupBuffer=null;this.handler=this.conf.handler;this.wrapping=this.conf.wrapping;this.mapANSI=this.conf.mapANSI;this.ANSItrueBlack=this.conf.ANSItrueBlack;this.ctrlHandler=this.conf.ctrlHandler;this.initHandler=this.conf.initHandler;this.exitHandler=this.conf.exitHandler;this.fieldMode=false;this.fieldStart=this.fieldEnd=this.fieldC=0;if(typeof this.conf.textBlur==='object'&&this.conf.textBlur.length){var a=[];for(var i=0;i0)a.push(b);} +this.textBlur=(a.length)?a:0;} +else{this.textBlur=Number(this.conf.textBlur);if(isNaN(this.textBlur)||this.textBlur<0||this.textBlur>40)this.textBlur=0;} +this.textColor=this.conf.textColor||'';},defaultHandler:function(){this.newLine();if(this.lineBuffer!=''){this.type('You typed: '+this.lineBuffer);this.newLine();} +this.prompt();},open:function(){if(this.termDivReady()){if(!this.closed)this._makeTerm();this.init();return true;} +else{return false;}},close:function(){this.lock=true;this.cursorOff();if(this.exitHandler)this.exitHandler();this.globals.setVisible(this.termDiv,0);this.closed=true;},init:function(){if(this.guiReady()){this.guiCounter=0;if(this.closed){this.setInitValues();} +this.clear();this.globals.setVisible(this.termDiv,1);this.globals.enableKeyboard(this);if(this.initHandler){this.initHandler();} +else{this.write(this.conf.greeting);this.newLine();this.prompt();}} +else{this.guiCounter++;if(this.guiCounter>18000){if(confirm('Terminal:\nYour browser hasn\'t responded for more than 2 minutes.\nRetry?')){this.guiCounter=0;} +else{return;}};this.globals.termToInitialze=this;window.setTimeout('Terminal.prototype.globals.termToInitialze.init()',200);}},getRowArray:function(l,v){var a=new Array();for(var i=0;i0)a.push(b);} +this.textBlur=(a.length)?a:0;rerender=true;} +else{v=Number(v);if(isNaN(v)||v<0||v>40)v=0;if(v!=this.textBlur){this.textBlur=v;rerender=true;}} +if(rerender){for(var r=0,l=this.conf.rows;r=0){var ta=text.split('\n');text=ta.join('%n');}} +else{if(text.join){text=text.join('%n');} +else{text=''+text;} +if(text.indexOf('\n')>=0){var ta=text.split('\n');text=ta.join('%n');}} +if(this.mapANSI)text=this.globals.ANSI_map(text,this.ANSItrueBlack);this._sbInit(usemore);var chunks=text.split('%');var esc=(text.charAt(0)!='%');var style=0;var styleMarkUp=this.globals.termStyleMarkup;for(var i=0;i0){this._sbType(chunks[i],style);} +else if(i>0){this._sbType('%',style);} +esc=false;} +else{var func=chunks[i].charAt(0);if(chunks[i].length==0&&i>0){this._sbType("%",style);esc=true;} +else if(func=='n'){this._sbNewLine(true);if(chunks[i].length>1)this._sbType(chunks[i].substring(1),style);} +else if(func=='+'){var opt=chunks[i].charAt(1);opt=opt.toLowerCase();if(opt=='p'){style=0;} +else if(styleMarkUp[opt]){style|=styleMarkUp[opt];} +if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} +else if(func=='-'){var opt=chunks[i].charAt(1);opt=opt.toLowerCase();if(opt=='p'){style=0;} +else if(styleMarkUp[opt]){style&=~styleMarkUp[opt];} +if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} +else if(chunks[i].length>1&&func=='c'){var cinfo=this._parseColor(chunks[i].substring(1));style=(style&(~0xfffff0))|cinfo.style;if(cinfo.rest)this._sbType(cinfo.rest,style);} +else if(chunks[i].length>1&&chunks[i].charAt(0)=='C'&&chunks[i].charAt(1)=='S'){this.clear();this._sbInit();if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} +else{if(chunks[i].length>0)this._sbType(chunks[i],style);}}} +this._sbOut();},_parseColor:function(chunk){var rest='';var style=0;if(chunk.length){if(chunk.charAt(0)=='('){var clabel='';for(var i=1;ii)rest=chunk.substring(i+1);break;} +clabel+=c;} +if(clabel){if(clabel.charAt(0)=='@'){var sc=this.globals.nsColors[clabel.substring(1).toLowerCase()];if(sc)style=(16+sc)*0x100;} +else if(clabel.charAt(0)=='#'){var cl=clabel.substring(1).toLowerCase();var sc=this.globals.webColors[cl];if(sc){style=sc*0x10000;} +else{cl=this.globals.webifyColor(cl);if(cl)style=this.globals.webColors[cl]*0x10000;}} +else if(clabel.length&&clabel.length<=2){var isHex=false;for(var i=0;i=this.maxCols)this._sbNewLine();}},_sbNewLine:function(forced){var sb=this.scrollBuf;if(this.wrapping&&forced){sb.lines[sb.r][sb.c]=10;sb.lines[sb.r].length=sb.c+1;} +sb.r++;sb.c=0;sb.lines[sb.r]=this.getRowArray(this.conf.cols,0);sb.styles[sb.r]=this.getRowArray(this.conf.cols,0);},_sbWrap:function(){var wb=new Object();wb.lines=new Array();wb.styles=new Array();wb.lines[0]=this.getRowArray(this.conf.cols,0);wb.styles[0]=this.getRowArray(this.conf.cols,0);wb.r=0;wb.c=0;var sb=this.scrollBuf;var sbl=sb.lines;var sbs=sb.styles;var ch,st,wrap,lc,ls;var l=this.c;var lastR=0;var lastC=0;wb.cBreak=false;for(var r=0;r=this.maxCols)this._wbIncLine(wb);} +if(wrap==3){lastR=r;lastC=c;l=1;} +else{l=0;lastR=r;lastC=c+1;if(lastC==lc.length){lastR++;lastC=0;} +if(wrap==4)wb.cBreak=true;}} +else{l++;}} +else{continue;}}} +if(l){if(wb.cBreak&&wb.c!=0)wb.c--;this._wbOut(wb,lastR,lastC,l);} +sb.lines=wb.lines;sb.styles=wb.styles;sb.r=wb.r;sb.c=wb.c;},_wbOut:function(wb,br,bc,l){var sb=this.scrollBuf;var sbl=sb.lines;var sbs=sb.styles;var ofs=0;var lc,ls;if(l+wb.c>this.maxCols){if(l=ml-1)this.clear();}} +if(this.r+buflen-sb.line<=ml){for(var i=sb.line;i=ml){var ofs=buflen-ml;for(var i=0;i0){r=this.conf.rows-offset;} +else{r=this.conf.rows-1;} +for(var i=0;i=0&&r=this.maxCols){this.c=0;this._incRow();}},_incRow:function(){this.r++;if(this.r>=this.maxLines){this._scrollLines(0,this.maxLines);this.r=this.maxLines-1;}},_scrollLines:function(start,end){window.status='Scrolling lines ...';start++;for(var ri=start;ri=start;r--)this.redraw(r-1);window.status='';},clear:function(){window.status='Clearing display ...';this.cursorOff();this.insert=false;for(var ri=0;ri0)this.newLine();this.type(this.ps);this._charOut(1);this.lock=false;this.cursorOn();},isPrintable:function(ch,unicodePage1only){if(this.wrapping&&this.globals.wrapChars[ch]==4)return true;if(unicodePage1only&&ch>255){return(ch==this.termKey.EURO&&this.printEuro)?true:false;} +return((ch>=32&&ch!=this.termKey.DEL)||(this.printTab&&ch==this.termKey.TAB));},cursorSet:function(r,c){var crsron=this.cursoractive;if(crsron)this.cursorOff();this.r=r%this.maxLines;this.c=c%this.maxCols;this._cursorReset(crsron);},cursorOn:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);this.blinkBuffer=this.styleBuf[this.r][this.c];this._cursorBlink();this.cursoractive=true;},cursorOff:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);if(this.cursoractive){this.styleBuf[this.r][this.c]=this.blinkBuffer;this.redraw(this.r);this.cursoractive=false;}},cursorLeft:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();var r=this.r;var c=this.c;if(c>0){c--;} +else if(r>0){c=this.maxCols-1;r--;} +if(this.isPrintable(this.charBuf[r][c])){this.r=r;this.c=c;} +this.insert=true;this._cursorReset(crsron);},cursorRight:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();var r=this.r;var c=this.c;if(c0)c-- +else if(r>0){c=this.maxCols-1;r--;};if(this.isPrintable(this.charBuf[r][c])){this._scrollLeft(r,c);this.r=r;this.c=c;};this._cursorReset(crsron);},fwdDelete:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();if(this.isPrintable(this.charBuf[this.r][this.c])){this._scrollLeft(this.r,this.c);if(!this.isPrintable(this.charBuf[this.r][this.c]))this.insert=false;} +this._cursorReset(crsron);},_cursorReset:function(crsron){if(crsron){this.cursorOn();} +else{this.blinkBuffer=this.styleBuf[this.r][this.c];}},_cursorBlink:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);if(this==this.globals.activeTerm){if(this.crsrBlockMode){this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&1)?this.styleBuf[this.r][this.c]&0xfffffe:this.styleBuf[this.r][this.c]|1;} +else{this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&2)?this.styleBuf[this.r][this.c]&0xffffd:this.styleBuf[this.r][this.c]|2;} +this.redraw(this.r);} +if(this.crsrBlinkMode)this.blinkTimer=setTimeout('Terminal.prototype.globals.activeTerm._cursorBlink()',this.blinkDelay);},_scrollLeft:function(r,c){var rows=new Array();rows[0]=r;while(this.isPrintable(this.charBuf[r][c])){var ri=r;var ci=c+1;if(ci==this.maxCols){if(ri0){r--;c=this.maxCols-1;} +else{c=0;}}} +if(this.isPrintable(this.charBuf[r][c])){while(true){var ri=r;var ci=c+1;if(ci==this.maxCols){if(ri=this.maxCols)this.c=this.maxCols-1;} +var line=new Array();while(this.isPrintable(this.charBuf[r][c])){line[line.length]=String.fromCharCode(this.charBuf[r][c]);if(c>0){c--;} +else if(r>0){c=this.maxCols-1;r--;} +else{break;}} +line.reverse();return line.join('');},_clearLine:function(){var end=this._getLineEnd(this.r,this.c);var r=end[0];var c=end[1];var line='';while(this.isPrintable(this.charBuf[r][c])){this.charBuf[r][c]=0;if(c>0){c--;} +else if(r>0){this.redraw(r);c=this.maxCols-1;r--;} +else{break;}} +if(r!=end[0])this.redraw(r);c++;this.cursorSet(r,c);this.insert=false;},backupScreen:function(){var backup=this.backupBuffer=new Object();var rl=this.conf.rows;var cl=this.conf.cols;backup.cbuf=new Array(rl);backup.sbuf=new Array(rl);backup.maxCols=this.maxCols;backup.maxLines=this.maxLines;backup.r=this.r;backup.c=this.c;backup.charMode=this.charMode;backup.rawMode=this.rawMode;backup.handler=this.handler;backup.ctrlHandler=this.ctrlHandler;backup.cursoractive=this.cursoractive;backup.crsrBlinkMode=this.crsrBlinkMode;backup.crsrBlockMode=this.crsrBlockMode;backup.blinkDelay=this.blinkDelay;backup.DELisBS=this.DELisBS;backup.printTab=this.printTab;backup.printEuro=this.printEuro;backup.catchCtrlH=this.catchCtrlH;backup.closeOnESC=this.closeOnESC;backup.historyUnique=this.historyUnique;backup.ps=this.ps;backup.lineBuffer=this.lineBuffer;backup.inputChar=this.inputChar;backup.lastLine=this.lastLine;backup.historyLength=this.history.length;backup.histPtr=this.histPtr;backup.wrapping=this.wrapping;backup.mapANSI=this.mapANSI;backup.ANSItrueBlack=this.ANSItrueBlack;if(this.cursoractive)this.cursorOff();for(var r=0;rbackup.historyLength){this.history.length=backup.historyLength;this.histPtr=backup.histPtr;} +this.wrapping=backup.wrapping;this.mapANSI=backup.mapANSI;this.ANSItrueBlack=backup.ANSItrueBlack;if(this.cursoractive)this.cursorOn();this.backupBuffer=null;},swapBackup:function(){var backup=this.backupBuffer;this.backupScreen;if(backup){var backup2=this.backupBuffer;this.backupBuffer=backup;this.restoreScreen();this.backupBuffer=backup2;}},escapeMarkup:function(t){return t.replace(/%/g,'%%');},enterFieldMode:function(start,end,style){this.cursorOff();if(start===undefined||start<0)start=this.c;if(end===undefined||endthis.maxCols)end=this.maxCols;if(!style)style=0;this.fieldStart=start;this.fieldEnd=end;this.fieldStyle=style;this.fieldC=0;this.lastLine='';this.fieldMode=true;this.rawMode=this.charMode=false;if(style&1){this._crsrWasBlockMode=this.crsrBlockMode;this._crsrWasBlinkMode=this.crsrBlinkMode;this.crsrBlockMode=false;this.crsrBlinkMode=true;} +this.drawField();this.lock=false;},exitFieldMode:function(){this.drawField(true);this.fieldMode=false;this.c=this.fieldEnd;if(this.c==this.maxLine)this.newLine();this.lock=true;},drawField:function(isfinal){this.cursorOff();if(isfinal)this.fieldC=0;var fl=this.fieldEnd-this.fieldStart;if(this.fieldC==this.lastLine.length)fl--;var ofs=this.fieldC-fl;if(ofs<0)ofs=0;var line=(ofs)?this.lastLine.substring(ofs):this.lastLine;var sb=this.styleBuf[this.r];var cb=this.charBuf[this.r];var max=line.length;for(var i=this.fieldStart,k=0;i\n';s+='
\n';var rstr='';for(var c=0;c'+rstr+'<\/td><\/tr>\n';} +s+='<\/table><\/td><\/tr>\n';s+='<\/table><\/td><\/tr>\n';s+='<\/table>\n';var termOffset=2+this.conf.frameWidth;if(this.globals.hasSubDivs){for(var r=0;r<\/div>\n';} +this.globals.termStringStart='
';this.globals.termStringEnd='<\/td><\/tr><\/table>';} +this.globals.writeElement(this.termDiv,s);} +if(!rebuild){this.globals.setElementXY(this.termDiv,this.conf.x,this.conf.y);this.globals.setVisible(this.termDiv,1);} +window.status='';},rebuild:function(){var rl=this.conf.rows;var cl=this.conf.cols;for(var r=0;r=rl){r=rl-1;resetcrsr=true;} +if(this.c>=cl){c=cl-1;resetcrsr=true;} +if(resetcrsr&&this.cursoractive)this.cursorOn();this._makeTerm(true);for(var r=0;r';for(var k=tstls.length-1;k>=0;k--){var st=tstls[k];if(curStyle&st)s+=tscls[st];}} +curStyle=cs;for(var k=0;k>>8;clr=(cc<16)?tclrs[cc]:'#'+tnclrs[cc-16];} +else if(curStyle&0xff0000){clr='#'+twclrs[(curStyle&0xff0000)>>>16];} +if(clr){if(curStyle&1){s+='';} +else if(typeof blur==='object'){s+='';} +else if(blur){s+='';} +else{s+='';}}} +s+=(tspcl[c])?tspcl[c]:String.fromCharCode(c);} +if(curStyle>0){if(curStyle&0xffff00)s+='';for(var k=tstls.length-1;k>=0;k--){var st=tstls[k];if(curStyle&st)s+=tscls[st];}} +s+=this.globals.termStringEnd;this.globals.writeElement(this.termDiv+'_r'+r,s);},guiReady:function(){var ready=true;if(this.globals.guiElementsReady(this.termDiv)){for(var r=0;r='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F'))?true:false;},isHexOnlyChar:function(c){return((c>='a'&&c<='f')||(c>='A'&&c<='F'))?true:false;},hexToNum:{'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'a':10,'b':11,'c':12,'d':13,'e':14,'f':15,'A':10,'B':11,'C':12,'D':13,'E':14,'F':15},webColors:[],webColorCodes:[''],colors:{black:1,red:2,green:3,yellow:4,blue:5,magenta:6,cyan:7,white:8,grey:9,red2:10,green2:11,yellow2:12,blue2:13,magenta2:14,cyan2:15,red1:2,green1:3,yellow1:4,blue1:5,magenta1:6,cyan1:7,gray:9,darkred:10,darkgreen:11,darkyellow:12,darkblue:13,darkmagenta:14,darkcyan:15,'default':0,clear:0},colorCodes:['','#000000','#ff0000','#00ff00','#ffff00','#0066ff','#ff00ff','#00ffff','#ffffff','#808080','#990000','#009900','#999900','#003399','#990099','#009999'],nsColors:{'aliceblue':1,'antiquewhite':2,'aqua':3,'aquamarine':4,'azure':5,'beige':6,'black':7,'blue':8,'blueviolet':9,'brown':10,'burlywood':11,'cadetblue':12,'chartreuse':13,'chocolate':14,'coral':15,'cornflowerblue':16,'cornsilk':17,'crimson':18,'darkblue':19,'darkcyan':20,'darkgoldenrod':21,'darkgray':22,'darkgreen':23,'darkkhaki':24,'darkmagenta':25,'darkolivegreen':26,'darkorange':27,'darkorchid':28,'darkred':29,'darksalmon':30,'darkseagreen':31,'darkslateblue':32,'darkslategray':33,'darkturquoise':34,'darkviolet':35,'deeppink':36,'deepskyblue':37,'dimgray':38,'dodgerblue':39,'firebrick':40,'floralwhite':41,'forestgreen':42,'fuchsia':43,'gainsboro':44,'ghostwhite':45,'gold':46,'goldenrod':47,'gray':48,'green':49,'greenyellow':50,'honeydew':51,'hotpink':52,'indianred':53,'indigo':54,'ivory':55,'khaki':56,'lavender':57,'lavenderblush':58,'lawngreen':59,'lemonchiffon':60,'lightblue':61,'lightcoral':62,'lightcyan':63,'lightgoldenrodyellow':64,'lightgreen':65,'lightgrey':66,'lightpink':67,'lightsalmon':68,'lightseagreen':69,'lightskyblue':70,'lightslategray':71,'lightsteelblue':72,'lightyellow':73,'lime':74,'limegreen':75,'linen':76,'maroon':77,'mediumaquamarine':78,'mediumblue':79,'mediumorchid':80,'mediumpurple':81,'mediumseagreen':82,'mediumslateblue':83,'mediumspringgreen':84,'mediumturquoise':85,'mediumvioletred':86,'midnightblue':87,'mintcream':88,'mistyrose':89,'moccasin':90,'navajowhite':91,'navy':92,'oldlace':93,'olive':94,'olivedrab':95,'orange':96,'orangered':97,'orchid':98,'palegoldenrod':99,'palegreen':100,'paleturquoise':101,'palevioletred':102,'papayawhip':103,'peachpuff':104,'peru':105,'pink':106,'plum':107,'powderblue':108,'purple':109,'red':110,'rosybrown':111,'royalblue':112,'saddlebrown':113,'salmon':114,'sandybrown':115,'seagreen':116,'seashell':117,'sienna':118,'silver':119,'skyblue':120,'slateblue':121,'slategray':122,'snow':123,'springgreen':124,'steelblue':125,'tan':126,'teal':127,'thistle':128,'tomato':129,'turquoise':130,'violet':131,'wheat':132,'white':133,'whitesmoke':134,'yellow':135,'yellowgreen':136},nsColorCodes:['','f0f8ff','faebd7','00ffff','7fffd4','f0ffff','f5f5dc','000000','0000ff','8a2be2','a52a2a','deb887','5f9ea0','7fff00','d2691e','ff7f50','6495ed','fff8dc','dc143c','00008b','008b8b','b8860b','a9a9a9','006400','bdb76b','8b008b','556b2f','ff8c00','9932cc','8b0000','e9967a','8fbc8f','483d8b','2f4f4f','00ced1','9400d3','ff1493','00bfff','696969','1e90ff','b22222','fffaf0','228b22','ff00ff','dcdcdc','f8f8ff','ffd700','daa520','808080','008000','adff2f','f0fff0','ff69b4','cd5c5c','4b0082','fffff0','f0e68c','e6e6fa','fff0f5','7cfc00','fffacd','add8e6','f08080','e0ffff','fafad2','90ee90','d3d3d3','ffb6c1','ffa07a','20b2aa','87cefa','778899','b0c4de','ffffe0','00ff00','32cd32','faf0e6','800000','66cdaa','0000cd','ba55d3','9370db','3cb371','7b68ee','00fa9a','48d1cc','c71585','191970','f5fffa','ffe4e1','ffe4b5','ffdead','000080','fdf5e6','808000','6b8e23','ffa500','ff4500','da70d6','eee8aa','98fb98','afeeee','db7093','ffefd5','ffdab9','cd853f','ffc0cb','dda0dd','b0e0e6','800080','ff0000','bc8f8f','4169e1','8b4513','fa8072','f4a460','2e8b57','fff5ee','a0522d','c0c0c0','87ceeb','6a5acd','708090','fffafa','00ff7f','4682b4','d2b48c','008080','d8bfd8','ff6347','40e0d0','ee82ee','f5deb3','ffffff','f5f5f5','ffff00','9acd32'],_webSwatchChars:['0','3','6','9','c','f'],_initWebColors:function(){var tg=Terminal.prototype.globals;var ws=tg._webColorSwatch;var wn=tg.webColors;var cc=tg.webColorCodes;var n=1;var a,b,c,al,bl,bs,cl;for(var i=0;i<6;i++){a=tg._webSwatchChars[i];al=a+a;for(var j=0;j<6;j++){b=tg._webSwatchChars[j];bl=al+b+b;bs=a+b;for(var k=0;k<6;k++){c=tg._webSwatchChars[k];cl=bl+c+c;wn[bs+c]=wn[cl]=n;cc[n]=cl;n++;}}}},webifyColor:function(s){var tg=Terminal.prototype.globals;if(s.length==6){var c='';for(var i=0;i<6;i+=2){var a=s.charAt(i);var b=s.charAt(i+1);if(tg.isHexChar(a)&&tg.isHexChar(b)){c+=tg._webSwatchChars[Math.round(parseInt(a+b,16)/255*5)];} +else{return'';}} +return c;} +else if(s.length==3){var c='';for(var i=0;i<3;i++){var a=s.charAt(i);if(tg.isHexChar(a)){c+=tg._webSwatchChars[Math.round(parseInt(a,16)/15*5)];} +else{return'';}} +return c;} +else{return'';}},setColor:function(label,value){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=1&&label<=15){tg.colorCodes[label]=value;} +else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){var n=tg.hexToNum[label];if(n)tg.colorCodes[n]=value;} +else if(typeof tg.colors[label]!='undefined'){var n=tg.colors[label];if(n)tg.colorCodes[n]=value;}}},getColorString:function(label){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=0&&label<=15){return tg.colorCodes[label];} +else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){return tg.colorCodes[tg.hexToNum[label]];} +else if(typeof tg.colors[label]!='undefined'){return tg.colorCodes[tg.colors[label]];}} +return'';},getColorCode:function(label){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=0&&label<=15){return label;} +else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){return parseInt(label,16);} +else if(typeof tg.colors[label]!='undefined'){return tg.colors[label];}} +return 0;},insertText:function(text){var tg=Terminal.prototype.globals;var termRef=tg.activeTerm;if(!termRef||termRef.closed||tg.keylock||termRef.lock||termRef.charMode||termRef.fieldMode)return false;for(var i=0;i=0){t=t.substring(0,ofs)+s2+t.substring(ofs+l1);ofs=t.indexOf(s1,ofs+l2);} +return t;},wrapChars:{9:1,10:1,12:4,13:1,32:1,40:3,45:2,61:2,91:3,94:3,123:3},setFocus:function(termref){Terminal.prototype.globals.activeTerm=termref;Terminal.prototype.globals.clearRepeatTimer();},termKey:{'NUL':0x00,'SOH':0x01,'STX':0x02,'ETX':0x03,'EOT':0x04,'ENQ':0x05,'ACK':0x06,'BEL':0x07,'BS':0x08,'BACKSPACE':0x08,'HT':0x09,'TAB':0x09,'LF':0x0A,'VT':0x0B,'FF':0x0C,'CR':0x0D,'SO':0x0E,'SI':0x0F,'DLE':0x10,'DC1':0x11,'DC2':0x12,'DC3':0x13,'DC4':0x14,'NAK':0x15,'SYN':0x16,'ETB':0x17,'CAN':0x18,'EM':0x19,'SUB':0x1A,'ESC':0x1B,'IS4':0x1C,'IS3':0x1D,'IS2':0x1E,'IS1':0x1F,'DEL':0x7F,'EURO':0x20AC,'LEFT':0x1C,'RIGHT':0x1D,'UP':0x1E,'DOWN':0x1F},termDomKeyRef:{},_domKeyMappingData:{'LEFT':'LEFT','RIGHT':'RIGHT','UP':'UP','DOWN':'DOWN','BACK_SPACE':'BS','RETURN':'CR','ENTER':'CR','ESCAPE':'ESC','DELETE':'DEL','TAB':'TAB'},_initDomKeyRef:function(){var tg=Terminal.prototype.globals;var m=tg._domKeyMappingData;var r=tg.termDomKeyRef;var k=tg.termKey;for(var i in m)r['DOM_VK_'+i]=k[m[i]];},registerEvent:function(obj,eventType,handler,capture){if(obj.addEventListener){obj.addEventListener(eventType.toLowerCase(),handler,capture);} +else{var et=eventType.toUpperCase();if(window.Event&&window.Event[et]&&obj.captureEvents)obj.captureEvents(Event[et]);obj['on'+eventType.toLowerCase()]=handler;}},releaseEvent:function(obj,eventType,handler,capture){if(obj.removeEventListener){obj.removeEventListener(eventType.toLowerCase(),handler,capture);} +else{var et=eventType.toUpperCase();if(window.Event&&window.Event[et]&&obj.releaseEvents)obj.releaseEvents(Event[et]);et='on'+eventType.toLowerCase();if(obj[et]&&obj[et]==handler)obj.et=null;}},enableKeyboard:function(term){var tg=Terminal.prototype.globals;if(!tg.kbdEnabled){tg.registerEvent(document,'keypress',tg.keyHandler,true);tg.registerEvent(document,'keydown',tg.keyFix,true);tg.registerEvent(document,'keyup',tg.clearRepeatTimer,true);tg.kbdEnabled=true;} +tg.activeTerm=term;},disableKeyboard:function(term){var tg=Terminal.prototype.globals;if(tg.kbdEnabled){tg.releaseEvent(document,'keypress',tg.keyHandler,true);tg.releaseEvent(document,'keydown',tg.keyFix,true);tg.releaseEvent(document,'keyup',tg.clearRepeatTimer,true);tg.kbdEnabled=false;} +tg.activeTerm=null;},keyFix:function(e){var tg=Terminal.prototype.globals;var term=tg.activeTerm;var ch;if(tg.keylock||term.lock)return true;if(window.event){if(!e)e=window.event;ch=e.keyCode;if(e.DOM_VK_UP){for(var i in tg.termDomKeyRef){if(e[i]&&ch==e[i]){tg.keyHandler({which:tg.termDomKeyRef[i],_remapped:true,_repeat:(ch==0x1B)?true:false});if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();e.cancelBubble=true;return false;}} +e.cancelBubble=false;return true;} +else{var termKey=term.termKey;var keyHandler=tg.keyHandler;if(ch==8&&!term.isOpera){keyHandler({which:termKey.BS,_remapped:true,_repeat:true});} +else if(ch==9){keyHandler({which:termKey.TAB,_remapped:true,_repeat:(term.printTab)?false:true});} +else if(ch==27){keyHandler({which:termKey.ESC,_remapped:true,_repeat:(term.printTab)?false:true});} +else if(ch==37){keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true});} +else if(ch==39){keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true});} +else if(ch==38){keyHandler({which:termKey.UP,_remapped:true,_repeat:true});} +else if(ch==40){keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true});} +else if(ch==127||ch==46){keyHandler({which:termKey.DEL,_remapped:true,_repeat:true});} +else if(ch>=57373&&ch<=57376){if(ch==57373){keyHandler({which:termKey.UP,_remapped:true,_repeat:true});} +else if(ch==57374){keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true});} +else if(ch==57375){keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true});} +else if(ch==57376){keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true});}} +else{e.cancelBubble=false;return true;} +if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();e.cancelBubble=true;return false;}}},clearRepeatTimer:function(e){var tg=Terminal.prototype.globals;if(tg.keyRepeatTimer){clearTimeout(tg.keyRepeatTimer);tg.keyRepeatTimer=null;}},doKeyRepeat:function(ch){Terminal.prototype.globals.keyHandler({which:ch,_remapped:true,_repeated:true})},keyHandler:function(e){var tg=Terminal.prototype.globals;var term=tg.activeTerm;if(tg.keylock||term.lock||term.isMac&&e&&e.metaKey)return true;if(window.event){if(window.event.preventDefault)window.event.preventDefault();if(window.event.stopPropagation)window.event.stopPropagation();} +else if(e){if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();} +var ch;var ctrl=false;var shft=false;var remapped=false;var termKey=term.termKey;var keyRepeat=0;if(e){ch=e.which;ctrl=((e.ctrlKey&&!e.altKey)||e.modifiers==2);shft=(e.shiftKey||e.modifiers==4);if(e._remapped){remapped=true;if(window.event){ctrl=(ctrl||(window.event.ctrlKey&&!window.event.altKey));shft=(shft||window.event.shiftKey);}} +if(e._repeated){keyRepeat=2;} +else if(e._repeat){keyRepeat=1;}} +else if(window.event){ch=window.event.keyCode;ctrl=(window.event.ctrlKey&&!window.event.altKey);shft=(window.event.shiftKey);if(window.event._repeated){keyRepeat=2;} +else if(window.event._repeat){keyRepeat=1;}} +else{return true;} +if(ch==''&&remapped==false){if(e==null)e=window.event;if(e.charCode==0&&e.keyCode){if(e.DOM_VK_UP){var dkr=tg.termDomKeyRef;for(var i in dkr){if(e[i]&&e.keyCode==e[i]){ch=dkr[i];break;}}} +else{if(e.keyCode==28){ch=termKey.LEFT;} +else if(e.keyCode==29){ch=termKey.RIGHT;} +else if(e.keyCode==30){ch=termKey.UP;} +else if(e.keyCode==31){ch=termKey.DOWN;} +else if(e.keyCode==37){ch=termKey.LEFT;} +else if(e.keyCode==39){ch=termKey.RIGHT;} +else if(e.keyCode==38){ch=termKey.UP;} +else if(e.keyCode==40){ch=termKey.DOWN;} +else if(e.keyCode==9){ch=termKey.TAB;}}}} +if((ch>=0xE000)&&(ch<=0xF8FF))return;if(keyRepeat){tg.clearRepeatTimer();tg.keyRepeatTimer=window.setTimeout('Terminal.prototype.globals.doKeyRepeat('+ch+')',(keyRepeat==1)?tg.keyRepeatDelay1:tg.keyRepeatDelay2);} +if(term.charMode){term.insert=false;term.inputChar=ch;term.lineBuffer='';term.handler();if(ch<=32&&window.event)window.event.cancelBubble=true;return false;} +if(!ctrl){if(ch==termKey.CR){term.lock=true;term.cursorOff();term.insert=false;if(term.rawMode){term.lineBuffer=term.lastLine;} +else if(term.fieldMode){term.lineBuffer=term.lastLine;term.exitFieldMode();} +else{term.lineBuffer=term._getLine(true);if(term.lineBuffer!=''&&(!term.historyUnique||term.history.length==0||term.lineBuffer!=term.history[term.history.length-1])){term.history[term.history.length]=term.lineBuffer;} +term.histPtr=term.history.length;} +term.lastLine='';term.inputChar=0;term.handler();if(window.event)window.event.cancelBubble=true;return false;} +else if(term.fieldMode){if(ch==termKey.ESC){term.lineBuffer=term.lastLine='';term.exitFieldMode();term.lastLine='';term.inputChar=0;term.handler();if(window.event)window.event.cancelBubble=true;return false;} +else if(ch==termKey.LEFT){if(term.fieldC>0)term.fieldC--;} +else if(ch==termKey.RIGHT){if(term.fieldC0){term.lastLine=term.lastLine.substring(0,term.fieldC-1)+term.lastLine.substring(term.fieldC);term.fieldC--;}} +else if(ch==termKey.DEL){if(term.fieldC=32){term.lastLine=term.lastLine.substring(0,term.fieldC)+String.fromCharCode(ch)+term.lastLine.substring(term.fieldC);term.fieldC++;} +term.drawField();return false;} +else if(ch==termKey.ESC&&term.conf.closeOnESC){term.close();if(window.event)window.event.cancelBubble=true;return false;} +if(ch<32&&term.rawMode){if(window.event)window.event.cancelBubble=true;return false;} +else{if(ch==termKey.LEFT){term.cursorLeft();if(window.event)window.event.cancelBubble=true;return false;} +else if(ch==termKey.RIGHT){term.cursorRight();if(window.event)window.event.cancelBubble=true;return false;} +else if(ch==termKey.UP){term.cursorOff();if(term.histPtr==term.history.length)term.lastLine=term._getLine();term._clearLine();if(term.history.length&&term.histPtr>=0){if(term.histPtr>0)term.histPtr--;term.type(term.history[term.histPtr]);} +else if(term.lastLine){term.type(term.lastLine);} +term.cursorOn();if(window.event)window.event.cancelBubble=true;return false;} +else if(ch==termKey.DOWN){term.cursorOff();if(term.histPtr==term.history.length)term.lastLine=term._getLine();term._clearLine();if(term.history.length&&term.histPtr<=term.history.length){if(term.histPtr=65&&ch<=96)||ch==63){if(ch==63){ch=31;} +else{ch-=64;}} +term.inputChar=ch;term.ctrlHandler();if(window.event)window.event.cancelBubble=true;return false;} +else if(ctrl||!term.isPrintable(ch,true)){if(window.event)window.event.cancelBubble=true;return false;} +else if(term.isPrintable(ch,true)){if(term.blinkTimer)clearTimeout(term.blinkTimer);if(term.insert){term.cursorOff();term._scrollRight(term.r,term.c);} +term._charOut(ch);term.cursorOn();if(ch==32&&window.event){window.event.cancelBubble=true;} +else if(window.opera&&window.event){window.event.cancelBubble=true;} +return false;}} +return true;},hasSubDivs:false,termStringStart:'',termStringEnd:'',termSpecials:{0:' ',1:' ',9:' ',32:' ',34:'"',38:'&',60:'<',62:'>',127:'◊',0x20AC:'€'},termStyles:[1,2,4,8,16],termStyleMarkup:{'r':1,'u':2,'i':4,'s':8,'b':16},termStyleOpen:{1:'',2:'',4:'',8:'',16:''},termStyleClose:{1:'<\/span>',2:'<\/u>',4:'<\/i>',8:'<\/strike>',16:''},assignStyle:function(styleCode,markup,htmlOpen,htmlClose){var tg=Terminal.prototype.globals;if(!styleCode||isNaN(styleCode)){if(styleCode>=256){alert('termlib.js:\nCould not assign style.\n'+s+' is not a valid power of 2 between 0 and 256.');return;}} +var s=styleCode&0xff;var matched=false;for(var i=0;i<8;i++){if((s>>>i)&1){if(matched){alert('termlib.js:\nCould not assign style code.\n'+s+' is not a power of 2!');return;} +matched=true;}} +if(!matched){alert('termlib.js:\nCould not assign style code.\n'+s+' is not a valid power of 2 between 0 and 256.');return;} +markup=String(markup).toLowerCase();if(markup=='c'||markup=='p'){alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is a reserved code.');return;} +if(markup.length>1){alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is not a single letter code.');return;} +var exists=false;for(var i=0;i=32){var cs=unescape("%"+high+low);termString_keyref[cc]=cs;termString_keycoderef[cs]=cc;}}}},_extendMissingStringMethods:function(){if(!String.fromCharCode||!String.prototype.charCodeAt){Terminal.prototype.globals._termString_makeKeyref();} +if(!String.fromCharCode){String.fromCharCode=function(cc){return(cc!=null)?Terminal.prototype.globals.termString_keyref[cc]:'';};} +if(!String.prototype.charCodeAt){String.prototype.charCodeAt=function(n){cs=this.charAt(n);return(Terminal.prototype.globals.termString_keycoderef[cs])?Terminal.prototype.globals.termString_keycoderef[cs]:0;};}}}} +Terminal.prototype.globals._initGlobals();var TerminalDefaults=Terminal.prototype.Defaults;var termDefaultHandler=Terminal.prototype.defaultHandler;var TermGlobals=Terminal.prototype.globals;var termKey=Terminal.prototype.globals.termKey;var termDomKeyRef=Terminal.prototype.globals.termDomKeyRef;Terminal.prototype._HttpSocket=function(){var req=null;if(window.XMLHttpRequest){try{req=new XMLHttpRequest();} +catch(e){}} +else if(window.ActiveXObject){var prtcls=this._msXMLHttpObjects;for(var i=0;i1)this.prototype._msXMLHttpObjects=[prtcls[i]];break;}} +catch(e){}}} +this.request=req;this.url;this.data=null;this.query='';this.timeoutTimer=null;this.localMode=Boolean(window.location.href.search(/^file:/i)==0);this.error=0;} +Terminal.prototype._HttpSocket.prototype={version:'1.02',useXMLEncoding:false,defaulTimeout:10000,defaultMethod:'GET',forceNewline:true,errno:{OK:0,NOTIMPLEMENTED:1,FATALERROR:2,TIMEOUT:3,NETWORKERROR:4,LOCALFILEERROR:5},errstring:['','XMLHttpRequest not implemented.','Could not open XMLHttpRequest.','The connection timed out.','Network error.','The requested local document was not found.'],_msXMLHttpObjects:['Msxml2.XMLHTTP','Microsoft.XMLHTTP','Msxml2.XMLHTTP.5.0','Msxml2.XMLHTTP.4.0','Msxml2.XMLHTTP.3.0'],serializeData:function(){this.query=this.serialize(this.data);},serialize:function(data){var v='';if(data!=null){switch(typeof data){case'object':var d=[];if(data instanceof Array){for(var i=0;i=200&&r.status<300){success=true;} +else if(r.status>=12000){failed=true;this.error=this.errno.NETWORKERROR;}}}} +catch(e){} +if(!failed){response.status=r.status;response.statusText=(r.status==404)?'Not Found':r.statusText;response.responseText=r.responseText;response.responseXML=r.responseXML;if(this.getHeaders){if(this.getHeaders instanceof Array){for(var i=0;i FB_COMPTARGET_JS ) then ln += "-Wno-unused-but-set-variable " else - ln += "-Wno-warn-absolute-paths -s LEGACY_GL_EMULATION=1 " + ln += "-Wno-warn-absolute-paths -s ASYNCIFY=1 -s RETAIN_COMPILER_SETTINGS=1 " end if '' Don't warn about non-standard main() signature diff --git a/src/rtlib/con_lineinp.c b/src/rtlib/con_lineinp.c index d802094825..491328a232 100644 --- a/src/rtlib/con_lineinp.c +++ b/src/rtlib/con_lineinp.c @@ -101,7 +101,7 @@ int fb_ConsoleLineInput { /* create temporary string */ - FBSTRING str_result = { 0 }; + FBSTRING str_result = { .data = NULL, .len = 0, .size = 0 }; res = fb_DevFileReadLineDumb( stdin, &str_result, hWrapper ); diff --git a/src/rtlib/js/fb_private_console.h b/src/rtlib/js/fb_private_console.h index 8d2b0a27fb..22c702b893 100644 --- a/src/rtlib/js/fb_private_console.h +++ b/src/rtlib/js/fb_private_console.h @@ -3,6 +3,23 @@ #define KEY_BUFFER_LEN 256 +#define FB_COLOR_BLACK (0) +#define FB_COLOR_BLUE (1) +#define FB_COLOR_GREEN (2) +#define FB_COLOR_CYAN (3) +#define FB_COLOR_RED (4) +#define FB_COLOR_MAGENTA (5) +#define FB_COLOR_BROWN (6) +#define FB_COLOR_WHITE (7) +#define FB_COLOR_GREY (8) +#define FB_COLOR_LBLUE (9) +#define FB_COLOR_LGREEN (10) +#define FB_COLOR_LCYAN (11) +#define FB_COLOR_LRED (12) +#define FB_COLOR_LMAGENTA (13) +#define FB_COLOR_YELLOW (14) +#define FB_COLOR_BWHITE (15) + typedef struct _FB_CONSOLE_MOUSE { int x; int y; @@ -20,6 +37,7 @@ typedef struct _FB_CONSOLE_CTX { int key_tail; unsigned char multikey[128]; FB_CONSOLE_MOUSE mouse; + const char *color_remap; } FB_CONSOLE_CTX; extern FB_CONSOLE_CTX __fb_con; diff --git a/src/rtlib/js/hinit.c b/src/rtlib/js/hinit.c index 43575a38a4..5070bdc396 100644 --- a/src/rtlib/js/hinit.c +++ b/src/rtlib/js/hinit.c @@ -16,10 +16,32 @@ FBCALL void fb_GraphicsLock ( void ) { return; } FBCALL void fb_GraphicsUnlock( void ) { return; } #endif -void fb_hInit( void ) +static const char color_remap[16] = +{ + [FB_COLOR_BLACK] = '1', + [FB_COLOR_BLUE] = 'D', + [FB_COLOR_GREEN] = 'B', + [FB_COLOR_CYAN] = 'F', + [FB_COLOR_RED] = 'A', + [FB_COLOR_MAGENTA] = 'E', + [FB_COLOR_BROWN] = 'C', + [FB_COLOR_WHITE] = '8', + [FB_COLOR_GREY] = '9', + [FB_COLOR_LBLUE] = '5', + [FB_COLOR_LGREEN] = '3', + [FB_COLOR_LCYAN] = '7', + [FB_COLOR_LRED] = '2', + [FB_COLOR_LMAGENTA] = '6', + [FB_COLOR_YELLOW] = '4', + [FB_COLOR_BWHITE] = '8', +}; + +static void fb_fs_init_console(void) { memset( &__fb_con, 0, sizeof(__fb_con) ); + __fb_con.color_remap = color_remap; + // keyboard emscripten_set_keypress_callback( 0, NULL, 1, fb_hKeyEventHandler ); emscripten_set_keydown_callback( 0, NULL, 1, fb_hKeyEventHandler ); @@ -33,6 +55,12 @@ void fb_hInit( void ) //emscripten_set_wheel_callback( 0, NULL, 1, fb_hMouseWheelEventHandler ); } +void fb_hInit( void ) +{ + fb_fs_init_console(); +} + void fb_hEnd( int unused ) { } + diff --git a/src/rtlib/js/io_color.c b/src/rtlib/js/io_color.c index 24f6ae14a1..b79a56fe7e 100644 --- a/src/rtlib/js/io_color.c +++ b/src/rtlib/js/io_color.c @@ -1,13 +1,31 @@ /* console COLOR statement */ #include "../fb.h" +#include "fb_private_console.h" + +static int last_bc = FB_COLOR_BLACK, last_fc = FB_COLOR_WHITE; int fb_ConsoleColor( int fc, int bc, int flags ) { - return 0; + int cur = last_fc | (last_bc << 16); + + if( !( flags & FB_COLOR_FG_DEFAULT ) ) + last_fc = fc & 15; + + if( !( flags & FB_COLOR_BG_DEFAULT ) ) + last_bc = bc & 15; + + char fc_c = __fb_con.color_remap[last_fc]; + char bc_c = __fb_con.color_remap[last_bc]; + + EM_ASM_ARGS({ + fbrt_term.color_set('$0', '$1'); + }, fc_c, bc_c); + + return cur; } int fb_ConsoleGetColorAtt( void ) { - return 0; + return last_fc | (last_bc << 4); } diff --git a/src/rtlib/js/io_getxy.c b/src/rtlib/js/io_getxy.c index a80e2a5f40..05da926585 100644 --- a/src/rtlib/js/io_getxy.c +++ b/src/rtlib/js/io_getxy.c @@ -2,4 +2,9 @@ FBCALL void fb_ConsoleGetXY( int *col, int *row ) { + if( col != NULL ) + *col = 0; + + if( row != NULL ) + *row = 0; } diff --git a/src/rtlib/js/io_locate.c b/src/rtlib/js/io_locate.c index 6b889743de..095722fc72 100644 --- a/src/rtlib/js/io_locate.c +++ b/src/rtlib/js/io_locate.c @@ -1,8 +1,13 @@ /* console LOCATE statement */ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleLocate( int row, int col, int cursor ) { - return 0; + EM_ASM_ARGS({ + fbrt_term.position_set($0, $1); + }, row-1, col-1); + + return (col & 0xFF) | ((row & 0xFF) << 8); } diff --git a/src/rtlib/js/io_pageset.c b/src/rtlib/js/io_pageset.c index 796de72101..2888620c9e 100644 --- a/src/rtlib/js/io_pageset.c +++ b/src/rtlib/js/io_pageset.c @@ -4,5 +4,5 @@ int fb_ConsolePageSet( int active, int visible ) { - return -1; + return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } diff --git a/src/rtlib/js/io_printbuff_wstr.c b/src/rtlib/js/io_printbuff_wstr.c index cb69f21a5c..c276362304 100644 --- a/src/rtlib/js/io_printbuff_wstr.c +++ b/src/rtlib/js/io_printbuff_wstr.c @@ -9,7 +9,8 @@ void fb_ConsolePrintBufferWstrEx int mask ) { - /* !!!WRITEME!!! */ + /* !!!FIXME!!! should print only buffer[0 .. chars-1] */ + wprintf( L"%ls", buffer ); } void fb_ConsolePrintBufferWstr diff --git a/src/rtlib/js/io_readxy.c b/src/rtlib/js/io_readxy.c index f552a6a803..8ce2aea1d1 100644 --- a/src/rtlib/js/io_readxy.c +++ b/src/rtlib/js/io_readxy.c @@ -4,5 +4,6 @@ FBCALL unsigned int fb_ConsoleReadXY( int col, int row, int colorflag ) { + /* !!!WRITEME!!! */ return 0; } diff --git a/src/rtlib/js/io_scroll.c b/src/rtlib/js/io_scroll.c index 2050d82dad..c7cc14df66 100644 --- a/src/rtlib/js/io_scroll.c +++ b/src/rtlib/js/io_scroll.c @@ -4,4 +4,5 @@ void fb_ConsoleScroll( int nrows ) { + /* !!!WRITEME!!! */ } diff --git a/src/rtlib/js/io_width.c b/src/rtlib/js/io_width.c index 5add1b321d..30d2492dbe 100644 --- a/src/rtlib/js/io_width.c +++ b/src/rtlib/js/io_width.c @@ -4,5 +4,5 @@ int fb_ConsoleWidth( int cols, int rows ) { - return 0; + return (25 << 16) | 80; } diff --git a/src/rtlib/js/sys_getcwd.c b/src/rtlib/js/sys_getcwd.c index 09782b4be3..82991fe5bc 100644 --- a/src/rtlib/js/sys_getcwd.c +++ b/src/rtlib/js/sys_getcwd.c @@ -4,7 +4,6 @@ ssize_t fb_hGetCurrentDir( char *dst, ssize_t maxlen ) { - /* !!!WRITEME!!! */ *dst = '\0'; return 0; } diff --git a/src/rtlib/js/sys_getexename.c b/src/rtlib/js/sys_getexename.c index ed15d23906..6eac1f2dcb 100644 --- a/src/rtlib/js/sys_getexename.c +++ b/src/rtlib/js/sys_getexename.c @@ -4,7 +4,6 @@ char *fb_hGetExeName( char *dst, ssize_t maxlen ) { - /* !!!WRITEME!!! */ dst[0] = '\0'; return dst; } diff --git a/src/rtlib/js/sys_getexepath.c b/src/rtlib/js/sys_getexepath.c index 238f875b57..61aa4be96a 100644 --- a/src/rtlib/js/sys_getexepath.c +++ b/src/rtlib/js/sys_getexepath.c @@ -4,7 +4,6 @@ char *fb_hGetExePath( char *dst, ssize_t maxlen ) { - /* !!!WRITEME!!! */ dst[0] = '\0'; return dst; } diff --git a/src/rtlib/js/sys_getshortpath.c b/src/rtlib/js/sys_getshortpath.c index 838d90fe04..1f59347c67 100644 --- a/src/rtlib/js/sys_getshortpath.c +++ b/src/rtlib/js/sys_getshortpath.c @@ -2,7 +2,6 @@ char *fb_hGetShortPath( char *src, char *dst, ssize_t maxlen ) { - /* !!!WRITEME!!! */ strncpy(dst, src, maxlen); return dst; } diff --git a/src/rtlib/js/time_setdate.c b/src/rtlib/js/time_setdate.c index cd0599c15e..a436240dfc 100644 --- a/src/rtlib/js/time_setdate.c +++ b/src/rtlib/js/time_setdate.c @@ -4,6 +4,5 @@ int fb_hSetDate( int y, int m, int d ) { - /* TODO: use NtSetSystemTime */ return 0; } diff --git a/src/rtlib/js/time_settime.c b/src/rtlib/js/time_settime.c index 33e167d9dc..7d3dc297fe 100644 --- a/src/rtlib/js/time_settime.c +++ b/src/rtlib/js/time_settime.c @@ -2,6 +2,5 @@ int fb_hSetTime( int h, int m, int s ) { - /* TODO: use NtSetSystemTime */ return 0; } From 11e76f5c2aa0a4db3409ef7f15c47912c693c2e5 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Fri, 16 Oct 2015 23:29:19 -0300 Subject: [PATCH 7/8] changed: terminal is now emulated using termlib.js --- lib/fb_rtlib.js | 178 ++ lib/fb_shell.html | 187 +++ lib/termlib_min.js | 3083 +++++++++++++++++++++++++++++++---- makefile | 8 + src/compiler/fbc.bas | 5 +- src/rtlib/js/hinit.c | 34 +- src/rtlib/js/io_cls.c | 4 + src/rtlib/js/io_color.c | 2 +- src/rtlib/js/io_getsize.c | 9 +- src/rtlib/js/io_getx.c | 7 +- src/rtlib/js/io_getxy.c | 9 +- src/rtlib/js/io_gety.c | 7 +- src/rtlib/js/io_locate.c | 2 +- src/rtlib/js/io_maxrow.c | 3 +- src/rtlib/js/io_printbuff.c | 5 +- src/rtlib/js/io_readxy.c | 15 +- src/rtlib/js/io_width.c | 13 +- 17 files changed, 3194 insertions(+), 377 deletions(-) create mode 100644 lib/fb_rtlib.js create mode 100644 lib/fb_shell.html diff --git a/lib/fb_rtlib.js b/lib/fb_rtlib.js new file mode 100644 index 0000000000..0cc87b0ba7 --- /dev/null +++ b/lib/fb_rtlib.js @@ -0,0 +1,178 @@ +var __fb_rtlib = +{ + console: + { + term: null, + divId: 'termDiv', + fg_color: '8', + bg_color: '1', + cols: 80, + rows: 25, + + open: function(cols, rows) + { + if( this.term === null ) + { + if( typeof Terminal !== 'undefined' ) + { + this.cols = !cols? cols: 80; + this.rows = !rows? rows: 25; + + this.term = new Terminal( + { + 'x': 0, + 'y': 0, + 'cols': this.cols, + 'rows': this.rows, + termDiv: this.divId, + bgColor: '#000000', + catchCtrlH: false, + closeOnESC: false, + greeting: '', + crsrBlockMode: false, + initHandler: this.termInitHandler, + handler: this.termHandler + //exitHandler: this.termExitHandler + }); + + this.term.open(); + this.term.resizeTo(cols, rows); + } + } + }, + + close: function() + { + if( this.term !== null ) + { + } + }, + + write: function(text) + { + if( this.term === null ) + { + console.log(text); + return; + } + + this.term.write('%c(' + this.fg_color + ',' + this.bg_color + ')' + text.replace('%(', '%%(')); + }, + + writeSubs: function(text, len) + { + this.write(text.substr(0, len)); + }, + + color_set: function(fg, bg) + { + if( fg >= 0 && fg <= 15 ) + this.fg_color = fg; + + if( bg >= 0 && bg <= 15 ) + this.bg_color = bg; + }, + + color_get: function() + { + return (this.bg_color << 8) | this.fg_color; + }, + + clear: function() + { + if( this.term !== null ) + this.term.clear(); + }, + + pos_set: function(row, col) + { + if( this.term !== null ) + this.term.cursorSet(row, col); + }, + + pos_get: function() + { + if( this.term !== null ) + return (this.term.r << 8) | this.term.c; + else + return 0; + }, + + size_get: function() + { + if( this.term !== null ) + return (this.rows << 8) | this.cols; + else + return 0; + }, + + size_set: function(cols, rows) + { + if( this.term !== null ) + { + if( this.term.resizeTo(cols, rows) ) + { + this.rows = rows; + this.cols = cols; + return true; + } + return false; + } + else + return false; + }, + + charAt: function(col, row) + { + if( this.term === null || + col < 0 || col >= this.cols || + row < 0 || row >= this.rows ) + return 0; + + return this.term.charBuf[row][col]; + }, + + colorAt: function(col, row) + { + if( this.term === null || + col < 0 || col >= this.cols || + row < 0 || row >= this.rows ) + return 0; + + return this.term.styleBuf[row][col]; + }, + + requestFullScreen: function() + { + if( this.term === null ) + return false; + + var target = document.getElementById(this.divId); + + if (target.requestFullscreen) + target.requestFullscreen(); + else if (target.msRequestFullscreen) + target.msRequestFullscreen(); + else if (target.mozRequestFullScreen) + target.mozRequestFullScreen(); + else if (target.mozRequestFullscreen) + target.mozRequestFullscreen(); + else if (target.webkitRequestFullscreen) + target.webkitRequestFullscreen(); + else + return false; + + return true; + }, + + termInitHandler: function() + { + this.lock = false + }, + + termHandler: function() + { + this.lock = false + } + } +}; diff --git a/lib/fb_shell.html b/lib/fb_shell.html new file mode 100644 index 0000000000..32581ddc7e --- /dev/null +++ b/lib/fb_shell.html @@ -0,0 +1,187 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+
+ +
+ +
+ +
+ + +
+ + +
+
Console
+
[x]
+
[^]
+
+
+ +
+ + {{{ SCRIPT }}} + + diff --git a/lib/termlib_min.js b/lib/termlib_min.js index 0d979adbf7..1a19d60601 100644 --- a/lib/termlib_min.js +++ b/lib/termlib_min.js @@ -1,5 +1,5 @@ /* - termlib.js - JS-WebTerminal Object v1.66 (source compacted using jsmin.php) + termlib.js - JS-WebTerminal Object v1.66 (c) Norbert Landsteiner 2003-2015 mass:werk - media environments @@ -7,13 +7,6 @@ Creates [multiple] Terminal instances. - Synopsis: - - myTerminal = new Terminal(); - myTerminal.open(); - - See file "readme.txt" for documentation and usage. - License: This JavaScript-library is free. Include a visible backlink to in the @@ -23,6 +16,10 @@ Any changes should be commented and must be reflected in `Terminal.version' in the format: "Version.Subversion (compatibility)". + + Donations: + Donations are welcome: You may support and/or honor the development of + "termlib.js" via PayPal at: Disclaimer: This software is distributed AS IS and in the hope that it will be useful, @@ -31,340 +28,2736 @@ the quality and performance of the product is borne by the user. No use of the product is authorized hereunder except under this disclaimer. */ -var Terminal=function(conf){if(typeof conf!='object')conf=new Object();for(var i in this.Defaults){if(typeof conf[i]=='undefined')conf[i]=this.Defaults[i];} -if(typeof conf.handler!='function')conf.handler=Terminal.prototype.defaultHandler;this.conf=conf;this.setInitValues();} -Terminal.prototype={version:'1.66 (original)',Defaults:{cols:80,rows:24,x:100,y:100,termDiv:'termDiv',bgColor:'#181818',frameColor:'#555555',frameWidth:1,rowHeight:15,blinkDelay:500,fontClass:'term',crsrBlinkMode:false,crsrBlockMode:true,DELisBS:false,printTab:true,printEuro:true,catchCtrlH:true,closeOnESC:true,historyUnique:false,id:0,ps:'>',greeting:'%+r Terminal ready. %-r',handler:null,ctrlHandler:null,initHandler:null,exitHandler:null,wrapping:false,mapANSI:false,ANSItrueBlack:false,textBlur:0,textColor:''},setInitValues:function(){this.isSafari=(navigator.userAgent.indexOf('Safari')>=0||navigator.userAgent.indexOf('WebKit')>=0)?true:false;this.isOpera=(window.opera&&navigator.userAgent.indexOf('Opera')>=0)?true:false;this.isChrome=(navigator.userAgent.indexOf('Chrome/')>=0&&navigator.userAgent.indexOf('WebKit')>=0)?true:false;this.domAPI=(document&&document.createElement)?true:false;this.isMac=(navigator.userAgent.indexOf('Mac')>=0)?true:false;this.id=this.conf.id;this.maxLines=this.conf.rows;this.maxCols=this.conf.cols;this.termDiv=this.conf.termDiv;this.crsrBlinkMode=this.conf.crsrBlinkMode;this.crsrBlockMode=this.conf.crsrBlockMode;this.blinkDelay=this.conf.blinkDelay;this.DELisBS=this.conf.DELisBS;this.printTab=this.conf.printTab;this.printEuro=this.conf.printEuro;this.catchCtrlH=this.conf.catchCtrlH;this.closeOnESC=this.conf.closeOnESC;this.historyUnique=this.conf.historyUnique;this.ps=this.conf.ps;this.closed=false;this.r;this.c;this.charBuf=new Array();this.styleBuf=new Array();this.scrollBuf=null;this.blinkBuffer=0;this.blinkTimer;this.cursoractive=false;this.lock=true;this.insert=false;this.charMode=false;this.rawMode=false;this.lineBuffer='';this.inputChar=0;this.lastLine='';this.guiCounter=0;this.history=new Array();this.histPtr=0;this.env=new Object();this.buckupBuffer=null;this.handler=this.conf.handler;this.wrapping=this.conf.wrapping;this.mapANSI=this.conf.mapANSI;this.ANSItrueBlack=this.conf.ANSItrueBlack;this.ctrlHandler=this.conf.ctrlHandler;this.initHandler=this.conf.initHandler;this.exitHandler=this.conf.exitHandler;this.fieldMode=false;this.fieldStart=this.fieldEnd=this.fieldC=0;if(typeof this.conf.textBlur==='object'&&this.conf.textBlur.length){var a=[];for(var i=0;i0)a.push(b);} -this.textBlur=(a.length)?a:0;} -else{this.textBlur=Number(this.conf.textBlur);if(isNaN(this.textBlur)||this.textBlur<0||this.textBlur>40)this.textBlur=0;} -this.textColor=this.conf.textColor||'';},defaultHandler:function(){this.newLine();if(this.lineBuffer!=''){this.type('You typed: '+this.lineBuffer);this.newLine();} -this.prompt();},open:function(){if(this.termDivReady()){if(!this.closed)this._makeTerm();this.init();return true;} -else{return false;}},close:function(){this.lock=true;this.cursorOff();if(this.exitHandler)this.exitHandler();this.globals.setVisible(this.termDiv,0);this.closed=true;},init:function(){if(this.guiReady()){this.guiCounter=0;if(this.closed){this.setInitValues();} -this.clear();this.globals.setVisible(this.termDiv,1);this.globals.enableKeyboard(this);if(this.initHandler){this.initHandler();} -else{this.write(this.conf.greeting);this.newLine();this.prompt();}} -else{this.guiCounter++;if(this.guiCounter>18000){if(confirm('Terminal:\nYour browser hasn\'t responded for more than 2 minutes.\nRetry?')){this.guiCounter=0;} -else{return;}};this.globals.termToInitialze=this;window.setTimeout('Terminal.prototype.globals.termToInitialze.init()',200);}},getRowArray:function(l,v){var a=new Array();for(var i=0;i0)a.push(b);} -this.textBlur=(a.length)?a:0;rerender=true;} -else{v=Number(v);if(isNaN(v)||v<0||v>40)v=0;if(v!=this.textBlur){this.textBlur=v;rerender=true;}} -if(rerender){for(var r=0,l=this.conf.rows;r=0){var ta=text.split('\n');text=ta.join('%n');}} -else{if(text.join){text=text.join('%n');} -else{text=''+text;} -if(text.indexOf('\n')>=0){var ta=text.split('\n');text=ta.join('%n');}} -if(this.mapANSI)text=this.globals.ANSI_map(text,this.ANSItrueBlack);this._sbInit(usemore);var chunks=text.split('%');var esc=(text.charAt(0)!='%');var style=0;var styleMarkUp=this.globals.termStyleMarkup;for(var i=0;i0){this._sbType(chunks[i],style);} -else if(i>0){this._sbType('%',style);} -esc=false;} -else{var func=chunks[i].charAt(0);if(chunks[i].length==0&&i>0){this._sbType("%",style);esc=true;} -else if(func=='n'){this._sbNewLine(true);if(chunks[i].length>1)this._sbType(chunks[i].substring(1),style);} -else if(func=='+'){var opt=chunks[i].charAt(1);opt=opt.toLowerCase();if(opt=='p'){style=0;} -else if(styleMarkUp[opt]){style|=styleMarkUp[opt];} -if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} -else if(func=='-'){var opt=chunks[i].charAt(1);opt=opt.toLowerCase();if(opt=='p'){style=0;} -else if(styleMarkUp[opt]){style&=~styleMarkUp[opt];} -if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} -else if(chunks[i].length>1&&func=='c'){var cinfo=this._parseColor(chunks[i].substring(1));style=(style&(~0xfffff0))|cinfo.style;if(cinfo.rest)this._sbType(cinfo.rest,style);} -else if(chunks[i].length>1&&chunks[i].charAt(0)=='C'&&chunks[i].charAt(1)=='S'){this.clear();this._sbInit();if(chunks[i].length>2)this._sbType(chunks[i].substring(2),style);} -else{if(chunks[i].length>0)this._sbType(chunks[i],style);}}} -this._sbOut();},_parseColor:function(chunk){var rest='';var style=0;if(chunk.length){if(chunk.charAt(0)=='('){var clabel='';for(var i=1;ii)rest=chunk.substring(i+1);break;} -clabel+=c;} -if(clabel){if(clabel.charAt(0)=='@'){var sc=this.globals.nsColors[clabel.substring(1).toLowerCase()];if(sc)style=(16+sc)*0x100;} -else if(clabel.charAt(0)=='#'){var cl=clabel.substring(1).toLowerCase();var sc=this.globals.webColors[cl];if(sc){style=sc*0x10000;} -else{cl=this.globals.webifyColor(cl);if(cl)style=this.globals.webColors[cl]*0x10000;}} -else if(clabel.length&&clabel.length<=2){var isHex=false;for(var i=0;i=this.maxCols)this._sbNewLine();}},_sbNewLine:function(forced){var sb=this.scrollBuf;if(this.wrapping&&forced){sb.lines[sb.r][sb.c]=10;sb.lines[sb.r].length=sb.c+1;} -sb.r++;sb.c=0;sb.lines[sb.r]=this.getRowArray(this.conf.cols,0);sb.styles[sb.r]=this.getRowArray(this.conf.cols,0);},_sbWrap:function(){var wb=new Object();wb.lines=new Array();wb.styles=new Array();wb.lines[0]=this.getRowArray(this.conf.cols,0);wb.styles[0]=this.getRowArray(this.conf.cols,0);wb.r=0;wb.c=0;var sb=this.scrollBuf;var sbl=sb.lines;var sbs=sb.styles;var ch,st,wrap,lc,ls;var l=this.c;var lastR=0;var lastC=0;wb.cBreak=false;for(var r=0;r=this.maxCols)this._wbIncLine(wb);} -if(wrap==3){lastR=r;lastC=c;l=1;} -else{l=0;lastR=r;lastC=c+1;if(lastC==lc.length){lastR++;lastC=0;} -if(wrap==4)wb.cBreak=true;}} -else{l++;}} -else{continue;}}} -if(l){if(wb.cBreak&&wb.c!=0)wb.c--;this._wbOut(wb,lastR,lastC,l);} -sb.lines=wb.lines;sb.styles=wb.styles;sb.r=wb.r;sb.c=wb.c;},_wbOut:function(wb,br,bc,l){var sb=this.scrollBuf;var sbl=sb.lines;var sbs=sb.styles;var ofs=0;var lc,ls;if(l+wb.c>this.maxCols){if(l=ml-1)this.clear();}} -if(this.r+buflen-sb.line<=ml){for(var i=sb.line;i=ml){var ofs=buflen-ml;for(var i=0;i0){r=this.conf.rows-offset;} -else{r=this.conf.rows-1;} -for(var i=0;i=0&&r=this.maxCols){this.c=0;this._incRow();}},_incRow:function(){this.r++;if(this.r>=this.maxLines){this._scrollLines(0,this.maxLines);this.r=this.maxLines-1;}},_scrollLines:function(start,end){window.status='Scrolling lines ...';start++;for(var ri=start;ri=start;r--)this.redraw(r-1);window.status='';},clear:function(){window.status='Clearing display ...';this.cursorOff();this.insert=false;for(var ri=0;ri0)this.newLine();this.type(this.ps);this._charOut(1);this.lock=false;this.cursorOn();},isPrintable:function(ch,unicodePage1only){if(this.wrapping&&this.globals.wrapChars[ch]==4)return true;if(unicodePage1only&&ch>255){return(ch==this.termKey.EURO&&this.printEuro)?true:false;} -return((ch>=32&&ch!=this.termKey.DEL)||(this.printTab&&ch==this.termKey.TAB));},cursorSet:function(r,c){var crsron=this.cursoractive;if(crsron)this.cursorOff();this.r=r%this.maxLines;this.c=c%this.maxCols;this._cursorReset(crsron);},cursorOn:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);this.blinkBuffer=this.styleBuf[this.r][this.c];this._cursorBlink();this.cursoractive=true;},cursorOff:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);if(this.cursoractive){this.styleBuf[this.r][this.c]=this.blinkBuffer;this.redraw(this.r);this.cursoractive=false;}},cursorLeft:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();var r=this.r;var c=this.c;if(c>0){c--;} -else if(r>0){c=this.maxCols-1;r--;} -if(this.isPrintable(this.charBuf[r][c])){this.r=r;this.c=c;} -this.insert=true;this._cursorReset(crsron);},cursorRight:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();var r=this.r;var c=this.c;if(c0)c-- -else if(r>0){c=this.maxCols-1;r--;};if(this.isPrintable(this.charBuf[r][c])){this._scrollLeft(r,c);this.r=r;this.c=c;};this._cursorReset(crsron);},fwdDelete:function(){var crsron=this.cursoractive;if(crsron)this.cursorOff();if(this.isPrintable(this.charBuf[this.r][this.c])){this._scrollLeft(this.r,this.c);if(!this.isPrintable(this.charBuf[this.r][this.c]))this.insert=false;} -this._cursorReset(crsron);},_cursorReset:function(crsron){if(crsron){this.cursorOn();} -else{this.blinkBuffer=this.styleBuf[this.r][this.c];}},_cursorBlink:function(){if(this.blinkTimer)clearTimeout(this.blinkTimer);if(this==this.globals.activeTerm){if(this.crsrBlockMode){this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&1)?this.styleBuf[this.r][this.c]&0xfffffe:this.styleBuf[this.r][this.c]|1;} -else{this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&2)?this.styleBuf[this.r][this.c]&0xffffd:this.styleBuf[this.r][this.c]|2;} -this.redraw(this.r);} -if(this.crsrBlinkMode)this.blinkTimer=setTimeout('Terminal.prototype.globals.activeTerm._cursorBlink()',this.blinkDelay);},_scrollLeft:function(r,c){var rows=new Array();rows[0]=r;while(this.isPrintable(this.charBuf[r][c])){var ri=r;var ci=c+1;if(ci==this.maxCols){if(ri0){r--;c=this.maxCols-1;} -else{c=0;}}} -if(this.isPrintable(this.charBuf[r][c])){while(true){var ri=r;var ci=c+1;if(ci==this.maxCols){if(ri=this.maxCols)this.c=this.maxCols-1;} -var line=new Array();while(this.isPrintable(this.charBuf[r][c])){line[line.length]=String.fromCharCode(this.charBuf[r][c]);if(c>0){c--;} -else if(r>0){c=this.maxCols-1;r--;} -else{break;}} -line.reverse();return line.join('');},_clearLine:function(){var end=this._getLineEnd(this.r,this.c);var r=end[0];var c=end[1];var line='';while(this.isPrintable(this.charBuf[r][c])){this.charBuf[r][c]=0;if(c>0){c--;} -else if(r>0){this.redraw(r);c=this.maxCols-1;r--;} -else{break;}} -if(r!=end[0])this.redraw(r);c++;this.cursorSet(r,c);this.insert=false;},backupScreen:function(){var backup=this.backupBuffer=new Object();var rl=this.conf.rows;var cl=this.conf.cols;backup.cbuf=new Array(rl);backup.sbuf=new Array(rl);backup.maxCols=this.maxCols;backup.maxLines=this.maxLines;backup.r=this.r;backup.c=this.c;backup.charMode=this.charMode;backup.rawMode=this.rawMode;backup.handler=this.handler;backup.ctrlHandler=this.ctrlHandler;backup.cursoractive=this.cursoractive;backup.crsrBlinkMode=this.crsrBlinkMode;backup.crsrBlockMode=this.crsrBlockMode;backup.blinkDelay=this.blinkDelay;backup.DELisBS=this.DELisBS;backup.printTab=this.printTab;backup.printEuro=this.printEuro;backup.catchCtrlH=this.catchCtrlH;backup.closeOnESC=this.closeOnESC;backup.historyUnique=this.historyUnique;backup.ps=this.ps;backup.lineBuffer=this.lineBuffer;backup.inputChar=this.inputChar;backup.lastLine=this.lastLine;backup.historyLength=this.history.length;backup.histPtr=this.histPtr;backup.wrapping=this.wrapping;backup.mapANSI=this.mapANSI;backup.ANSItrueBlack=this.ANSItrueBlack;if(this.cursoractive)this.cursorOff();for(var r=0;rbackup.historyLength){this.history.length=backup.historyLength;this.histPtr=backup.histPtr;} -this.wrapping=backup.wrapping;this.mapANSI=backup.mapANSI;this.ANSItrueBlack=backup.ANSItrueBlack;if(this.cursoractive)this.cursorOn();this.backupBuffer=null;},swapBackup:function(){var backup=this.backupBuffer;this.backupScreen;if(backup){var backup2=this.backupBuffer;this.backupBuffer=backup;this.restoreScreen();this.backupBuffer=backup2;}},escapeMarkup:function(t){return t.replace(/%/g,'%%');},enterFieldMode:function(start,end,style){this.cursorOff();if(start===undefined||start<0)start=this.c;if(end===undefined||endthis.maxCols)end=this.maxCols;if(!style)style=0;this.fieldStart=start;this.fieldEnd=end;this.fieldStyle=style;this.fieldC=0;this.lastLine='';this.fieldMode=true;this.rawMode=this.charMode=false;if(style&1){this._crsrWasBlockMode=this.crsrBlockMode;this._crsrWasBlinkMode=this.crsrBlinkMode;this.crsrBlockMode=false;this.crsrBlinkMode=true;} -this.drawField();this.lock=false;},exitFieldMode:function(){this.drawField(true);this.fieldMode=false;this.c=this.fieldEnd;if(this.c==this.maxLine)this.newLine();this.lock=true;},drawField:function(isfinal){this.cursorOff();if(isfinal)this.fieldC=0;var fl=this.fieldEnd-this.fieldStart;if(this.fieldC==this.lastLine.length)fl--;var ofs=this.fieldC-fl;if(ofs<0)ofs=0;var line=(ofs)?this.lastLine.substring(ofs):this.lastLine;var sb=this.styleBuf[this.r];var cb=this.charBuf[this.r];var max=line.length;for(var i=this.fieldStart,k=0;i\n';s+='
\n';var rstr='';for(var c=0;c'+rstr+'<\/td><\/tr>\n';} -s+='<\/table><\/td><\/tr>\n';s+='<\/table><\/td><\/tr>\n';s+='<\/table>\n';var termOffset=2+this.conf.frameWidth;if(this.globals.hasSubDivs){for(var r=0;r<\/div>\n';} -this.globals.termStringStart='
';this.globals.termStringEnd='<\/td><\/tr><\/table>';} -this.globals.writeElement(this.termDiv,s);} -if(!rebuild){this.globals.setElementXY(this.termDiv,this.conf.x,this.conf.y);this.globals.setVisible(this.termDiv,1);} -window.status='';},rebuild:function(){var rl=this.conf.rows;var cl=this.conf.cols;for(var r=0;r=rl){r=rl-1;resetcrsr=true;} -if(this.c>=cl){c=cl-1;resetcrsr=true;} -if(resetcrsr&&this.cursoractive)this.cursorOn();this._makeTerm(true);for(var r=0;r';for(var k=tstls.length-1;k>=0;k--){var st=tstls[k];if(curStyle&st)s+=tscls[st];}} -curStyle=cs;for(var k=0;k>>8;clr=(cc<16)?tclrs[cc]:'#'+tnclrs[cc-16];} -else if(curStyle&0xff0000){clr='#'+twclrs[(curStyle&0xff0000)>>>16];} -if(clr){if(curStyle&1){s+='';} -else if(typeof blur==='object'){s+='';} -else if(blur){s+='';} -else{s+='';}}} -s+=(tspcl[c])?tspcl[c]:String.fromCharCode(c);} -if(curStyle>0){if(curStyle&0xffff00)s+='';for(var k=tstls.length-1;k>=0;k--){var st=tstls[k];if(curStyle&st)s+=tscls[st];}} -s+=this.globals.termStringEnd;this.globals.writeElement(this.termDiv+'_r'+r,s);},guiReady:function(){var ready=true;if(this.globals.guiElementsReady(this.termDiv)){for(var r=0;r='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F'))?true:false;},isHexOnlyChar:function(c){return((c>='a'&&c<='f')||(c>='A'&&c<='F'))?true:false;},hexToNum:{'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'a':10,'b':11,'c':12,'d':13,'e':14,'f':15,'A':10,'B':11,'C':12,'D':13,'E':14,'F':15},webColors:[],webColorCodes:[''],colors:{black:1,red:2,green:3,yellow:4,blue:5,magenta:6,cyan:7,white:8,grey:9,red2:10,green2:11,yellow2:12,blue2:13,magenta2:14,cyan2:15,red1:2,green1:3,yellow1:4,blue1:5,magenta1:6,cyan1:7,gray:9,darkred:10,darkgreen:11,darkyellow:12,darkblue:13,darkmagenta:14,darkcyan:15,'default':0,clear:0},colorCodes:['','#000000','#ff0000','#00ff00','#ffff00','#0066ff','#ff00ff','#00ffff','#ffffff','#808080','#990000','#009900','#999900','#003399','#990099','#009999'],nsColors:{'aliceblue':1,'antiquewhite':2,'aqua':3,'aquamarine':4,'azure':5,'beige':6,'black':7,'blue':8,'blueviolet':9,'brown':10,'burlywood':11,'cadetblue':12,'chartreuse':13,'chocolate':14,'coral':15,'cornflowerblue':16,'cornsilk':17,'crimson':18,'darkblue':19,'darkcyan':20,'darkgoldenrod':21,'darkgray':22,'darkgreen':23,'darkkhaki':24,'darkmagenta':25,'darkolivegreen':26,'darkorange':27,'darkorchid':28,'darkred':29,'darksalmon':30,'darkseagreen':31,'darkslateblue':32,'darkslategray':33,'darkturquoise':34,'darkviolet':35,'deeppink':36,'deepskyblue':37,'dimgray':38,'dodgerblue':39,'firebrick':40,'floralwhite':41,'forestgreen':42,'fuchsia':43,'gainsboro':44,'ghostwhite':45,'gold':46,'goldenrod':47,'gray':48,'green':49,'greenyellow':50,'honeydew':51,'hotpink':52,'indianred':53,'indigo':54,'ivory':55,'khaki':56,'lavender':57,'lavenderblush':58,'lawngreen':59,'lemonchiffon':60,'lightblue':61,'lightcoral':62,'lightcyan':63,'lightgoldenrodyellow':64,'lightgreen':65,'lightgrey':66,'lightpink':67,'lightsalmon':68,'lightseagreen':69,'lightskyblue':70,'lightslategray':71,'lightsteelblue':72,'lightyellow':73,'lime':74,'limegreen':75,'linen':76,'maroon':77,'mediumaquamarine':78,'mediumblue':79,'mediumorchid':80,'mediumpurple':81,'mediumseagreen':82,'mediumslateblue':83,'mediumspringgreen':84,'mediumturquoise':85,'mediumvioletred':86,'midnightblue':87,'mintcream':88,'mistyrose':89,'moccasin':90,'navajowhite':91,'navy':92,'oldlace':93,'olive':94,'olivedrab':95,'orange':96,'orangered':97,'orchid':98,'palegoldenrod':99,'palegreen':100,'paleturquoise':101,'palevioletred':102,'papayawhip':103,'peachpuff':104,'peru':105,'pink':106,'plum':107,'powderblue':108,'purple':109,'red':110,'rosybrown':111,'royalblue':112,'saddlebrown':113,'salmon':114,'sandybrown':115,'seagreen':116,'seashell':117,'sienna':118,'silver':119,'skyblue':120,'slateblue':121,'slategray':122,'snow':123,'springgreen':124,'steelblue':125,'tan':126,'teal':127,'thistle':128,'tomato':129,'turquoise':130,'violet':131,'wheat':132,'white':133,'whitesmoke':134,'yellow':135,'yellowgreen':136},nsColorCodes:['','f0f8ff','faebd7','00ffff','7fffd4','f0ffff','f5f5dc','000000','0000ff','8a2be2','a52a2a','deb887','5f9ea0','7fff00','d2691e','ff7f50','6495ed','fff8dc','dc143c','00008b','008b8b','b8860b','a9a9a9','006400','bdb76b','8b008b','556b2f','ff8c00','9932cc','8b0000','e9967a','8fbc8f','483d8b','2f4f4f','00ced1','9400d3','ff1493','00bfff','696969','1e90ff','b22222','fffaf0','228b22','ff00ff','dcdcdc','f8f8ff','ffd700','daa520','808080','008000','adff2f','f0fff0','ff69b4','cd5c5c','4b0082','fffff0','f0e68c','e6e6fa','fff0f5','7cfc00','fffacd','add8e6','f08080','e0ffff','fafad2','90ee90','d3d3d3','ffb6c1','ffa07a','20b2aa','87cefa','778899','b0c4de','ffffe0','00ff00','32cd32','faf0e6','800000','66cdaa','0000cd','ba55d3','9370db','3cb371','7b68ee','00fa9a','48d1cc','c71585','191970','f5fffa','ffe4e1','ffe4b5','ffdead','000080','fdf5e6','808000','6b8e23','ffa500','ff4500','da70d6','eee8aa','98fb98','afeeee','db7093','ffefd5','ffdab9','cd853f','ffc0cb','dda0dd','b0e0e6','800080','ff0000','bc8f8f','4169e1','8b4513','fa8072','f4a460','2e8b57','fff5ee','a0522d','c0c0c0','87ceeb','6a5acd','708090','fffafa','00ff7f','4682b4','d2b48c','008080','d8bfd8','ff6347','40e0d0','ee82ee','f5deb3','ffffff','f5f5f5','ffff00','9acd32'],_webSwatchChars:['0','3','6','9','c','f'],_initWebColors:function(){var tg=Terminal.prototype.globals;var ws=tg._webColorSwatch;var wn=tg.webColors;var cc=tg.webColorCodes;var n=1;var a,b,c,al,bl,bs,cl;for(var i=0;i<6;i++){a=tg._webSwatchChars[i];al=a+a;for(var j=0;j<6;j++){b=tg._webSwatchChars[j];bl=al+b+b;bs=a+b;for(var k=0;k<6;k++){c=tg._webSwatchChars[k];cl=bl+c+c;wn[bs+c]=wn[cl]=n;cc[n]=cl;n++;}}}},webifyColor:function(s){var tg=Terminal.prototype.globals;if(s.length==6){var c='';for(var i=0;i<6;i+=2){var a=s.charAt(i);var b=s.charAt(i+1);if(tg.isHexChar(a)&&tg.isHexChar(b)){c+=tg._webSwatchChars[Math.round(parseInt(a+b,16)/255*5)];} -else{return'';}} -return c;} -else if(s.length==3){var c='';for(var i=0;i<3;i++){var a=s.charAt(i);if(tg.isHexChar(a)){c+=tg._webSwatchChars[Math.round(parseInt(a,16)/15*5)];} -else{return'';}} -return c;} -else{return'';}},setColor:function(label,value){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=1&&label<=15){tg.colorCodes[label]=value;} -else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){var n=tg.hexToNum[label];if(n)tg.colorCodes[n]=value;} -else if(typeof tg.colors[label]!='undefined'){var n=tg.colors[label];if(n)tg.colorCodes[n]=value;}}},getColorString:function(label){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=0&&label<=15){return tg.colorCodes[label];} -else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){return tg.colorCodes[tg.hexToNum[label]];} -else if(typeof tg.colors[label]!='undefined'){return tg.colorCodes[tg.colors[label]];}} -return'';},getColorCode:function(label){var tg=Terminal.prototype.globals;if(typeof label=='number'&&label>=0&&label<=15){return label;} -else if(typeof label=='string'){label=label.toLowerCase();if(label.length==1&&tg.isHexChar(label)){return parseInt(label,16);} -else if(typeof tg.colors[label]!='undefined'){return tg.colors[label];}} -return 0;},insertText:function(text){var tg=Terminal.prototype.globals;var termRef=tg.activeTerm;if(!termRef||termRef.closed||tg.keylock||termRef.lock||termRef.charMode||termRef.fieldMode)return false;for(var i=0;i=0){t=t.substring(0,ofs)+s2+t.substring(ofs+l1);ofs=t.indexOf(s1,ofs+l2);} -return t;},wrapChars:{9:1,10:1,12:4,13:1,32:1,40:3,45:2,61:2,91:3,94:3,123:3},setFocus:function(termref){Terminal.prototype.globals.activeTerm=termref;Terminal.prototype.globals.clearRepeatTimer();},termKey:{'NUL':0x00,'SOH':0x01,'STX':0x02,'ETX':0x03,'EOT':0x04,'ENQ':0x05,'ACK':0x06,'BEL':0x07,'BS':0x08,'BACKSPACE':0x08,'HT':0x09,'TAB':0x09,'LF':0x0A,'VT':0x0B,'FF':0x0C,'CR':0x0D,'SO':0x0E,'SI':0x0F,'DLE':0x10,'DC1':0x11,'DC2':0x12,'DC3':0x13,'DC4':0x14,'NAK':0x15,'SYN':0x16,'ETB':0x17,'CAN':0x18,'EM':0x19,'SUB':0x1A,'ESC':0x1B,'IS4':0x1C,'IS3':0x1D,'IS2':0x1E,'IS1':0x1F,'DEL':0x7F,'EURO':0x20AC,'LEFT':0x1C,'RIGHT':0x1D,'UP':0x1E,'DOWN':0x1F},termDomKeyRef:{},_domKeyMappingData:{'LEFT':'LEFT','RIGHT':'RIGHT','UP':'UP','DOWN':'DOWN','BACK_SPACE':'BS','RETURN':'CR','ENTER':'CR','ESCAPE':'ESC','DELETE':'DEL','TAB':'TAB'},_initDomKeyRef:function(){var tg=Terminal.prototype.globals;var m=tg._domKeyMappingData;var r=tg.termDomKeyRef;var k=tg.termKey;for(var i in m)r['DOM_VK_'+i]=k[m[i]];},registerEvent:function(obj,eventType,handler,capture){if(obj.addEventListener){obj.addEventListener(eventType.toLowerCase(),handler,capture);} -else{var et=eventType.toUpperCase();if(window.Event&&window.Event[et]&&obj.captureEvents)obj.captureEvents(Event[et]);obj['on'+eventType.toLowerCase()]=handler;}},releaseEvent:function(obj,eventType,handler,capture){if(obj.removeEventListener){obj.removeEventListener(eventType.toLowerCase(),handler,capture);} -else{var et=eventType.toUpperCase();if(window.Event&&window.Event[et]&&obj.releaseEvents)obj.releaseEvents(Event[et]);et='on'+eventType.toLowerCase();if(obj[et]&&obj[et]==handler)obj.et=null;}},enableKeyboard:function(term){var tg=Terminal.prototype.globals;if(!tg.kbdEnabled){tg.registerEvent(document,'keypress',tg.keyHandler,true);tg.registerEvent(document,'keydown',tg.keyFix,true);tg.registerEvent(document,'keyup',tg.clearRepeatTimer,true);tg.kbdEnabled=true;} -tg.activeTerm=term;},disableKeyboard:function(term){var tg=Terminal.prototype.globals;if(tg.kbdEnabled){tg.releaseEvent(document,'keypress',tg.keyHandler,true);tg.releaseEvent(document,'keydown',tg.keyFix,true);tg.releaseEvent(document,'keyup',tg.clearRepeatTimer,true);tg.kbdEnabled=false;} -tg.activeTerm=null;},keyFix:function(e){var tg=Terminal.prototype.globals;var term=tg.activeTerm;var ch;if(tg.keylock||term.lock)return true;if(window.event){if(!e)e=window.event;ch=e.keyCode;if(e.DOM_VK_UP){for(var i in tg.termDomKeyRef){if(e[i]&&ch==e[i]){tg.keyHandler({which:tg.termDomKeyRef[i],_remapped:true,_repeat:(ch==0x1B)?true:false});if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();e.cancelBubble=true;return false;}} -e.cancelBubble=false;return true;} -else{var termKey=term.termKey;var keyHandler=tg.keyHandler;if(ch==8&&!term.isOpera){keyHandler({which:termKey.BS,_remapped:true,_repeat:true});} -else if(ch==9){keyHandler({which:termKey.TAB,_remapped:true,_repeat:(term.printTab)?false:true});} -else if(ch==27){keyHandler({which:termKey.ESC,_remapped:true,_repeat:(term.printTab)?false:true});} -else if(ch==37){keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true});} -else if(ch==39){keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true});} -else if(ch==38){keyHandler({which:termKey.UP,_remapped:true,_repeat:true});} -else if(ch==40){keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true});} -else if(ch==127||ch==46){keyHandler({which:termKey.DEL,_remapped:true,_repeat:true});} -else if(ch>=57373&&ch<=57376){if(ch==57373){keyHandler({which:termKey.UP,_remapped:true,_repeat:true});} -else if(ch==57374){keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true});} -else if(ch==57375){keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true});} -else if(ch==57376){keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true});}} -else{e.cancelBubble=false;return true;} -if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();e.cancelBubble=true;return false;}}},clearRepeatTimer:function(e){var tg=Terminal.prototype.globals;if(tg.keyRepeatTimer){clearTimeout(tg.keyRepeatTimer);tg.keyRepeatTimer=null;}},doKeyRepeat:function(ch){Terminal.prototype.globals.keyHandler({which:ch,_remapped:true,_repeated:true})},keyHandler:function(e){var tg=Terminal.prototype.globals;var term=tg.activeTerm;if(tg.keylock||term.lock||term.isMac&&e&&e.metaKey)return true;if(window.event){if(window.event.preventDefault)window.event.preventDefault();if(window.event.stopPropagation)window.event.stopPropagation();} -else if(e){if(e.preventDefault)e.preventDefault();if(e.stopPropagation)e.stopPropagation();} -var ch;var ctrl=false;var shft=false;var remapped=false;var termKey=term.termKey;var keyRepeat=0;if(e){ch=e.which;ctrl=((e.ctrlKey&&!e.altKey)||e.modifiers==2);shft=(e.shiftKey||e.modifiers==4);if(e._remapped){remapped=true;if(window.event){ctrl=(ctrl||(window.event.ctrlKey&&!window.event.altKey));shft=(shft||window.event.shiftKey);}} -if(e._repeated){keyRepeat=2;} -else if(e._repeat){keyRepeat=1;}} -else if(window.event){ch=window.event.keyCode;ctrl=(window.event.ctrlKey&&!window.event.altKey);shft=(window.event.shiftKey);if(window.event._repeated){keyRepeat=2;} -else if(window.event._repeat){keyRepeat=1;}} -else{return true;} -if(ch==''&&remapped==false){if(e==null)e=window.event;if(e.charCode==0&&e.keyCode){if(e.DOM_VK_UP){var dkr=tg.termDomKeyRef;for(var i in dkr){if(e[i]&&e.keyCode==e[i]){ch=dkr[i];break;}}} -else{if(e.keyCode==28){ch=termKey.LEFT;} -else if(e.keyCode==29){ch=termKey.RIGHT;} -else if(e.keyCode==30){ch=termKey.UP;} -else if(e.keyCode==31){ch=termKey.DOWN;} -else if(e.keyCode==37){ch=termKey.LEFT;} -else if(e.keyCode==39){ch=termKey.RIGHT;} -else if(e.keyCode==38){ch=termKey.UP;} -else if(e.keyCode==40){ch=termKey.DOWN;} -else if(e.keyCode==9){ch=termKey.TAB;}}}} -if((ch>=0xE000)&&(ch<=0xF8FF))return;if(keyRepeat){tg.clearRepeatTimer();tg.keyRepeatTimer=window.setTimeout('Terminal.prototype.globals.doKeyRepeat('+ch+')',(keyRepeat==1)?tg.keyRepeatDelay1:tg.keyRepeatDelay2);} -if(term.charMode){term.insert=false;term.inputChar=ch;term.lineBuffer='';term.handler();if(ch<=32&&window.event)window.event.cancelBubble=true;return false;} -if(!ctrl){if(ch==termKey.CR){term.lock=true;term.cursorOff();term.insert=false;if(term.rawMode){term.lineBuffer=term.lastLine;} -else if(term.fieldMode){term.lineBuffer=term.lastLine;term.exitFieldMode();} -else{term.lineBuffer=term._getLine(true);if(term.lineBuffer!=''&&(!term.historyUnique||term.history.length==0||term.lineBuffer!=term.history[term.history.length-1])){term.history[term.history.length]=term.lineBuffer;} -term.histPtr=term.history.length;} -term.lastLine='';term.inputChar=0;term.handler();if(window.event)window.event.cancelBubble=true;return false;} -else if(term.fieldMode){if(ch==termKey.ESC){term.lineBuffer=term.lastLine='';term.exitFieldMode();term.lastLine='';term.inputChar=0;term.handler();if(window.event)window.event.cancelBubble=true;return false;} -else if(ch==termKey.LEFT){if(term.fieldC>0)term.fieldC--;} -else if(ch==termKey.RIGHT){if(term.fieldC0){term.lastLine=term.lastLine.substring(0,term.fieldC-1)+term.lastLine.substring(term.fieldC);term.fieldC--;}} -else if(ch==termKey.DEL){if(term.fieldC=32){term.lastLine=term.lastLine.substring(0,term.fieldC)+String.fromCharCode(ch)+term.lastLine.substring(term.fieldC);term.fieldC++;} -term.drawField();return false;} -else if(ch==termKey.ESC&&term.conf.closeOnESC){term.close();if(window.event)window.event.cancelBubble=true;return false;} -if(ch<32&&term.rawMode){if(window.event)window.event.cancelBubble=true;return false;} -else{if(ch==termKey.LEFT){term.cursorLeft();if(window.event)window.event.cancelBubble=true;return false;} -else if(ch==termKey.RIGHT){term.cursorRight();if(window.event)window.event.cancelBubble=true;return false;} -else if(ch==termKey.UP){term.cursorOff();if(term.histPtr==term.history.length)term.lastLine=term._getLine();term._clearLine();if(term.history.length&&term.histPtr>=0){if(term.histPtr>0)term.histPtr--;term.type(term.history[term.histPtr]);} -else if(term.lastLine){term.type(term.lastLine);} -term.cursorOn();if(window.event)window.event.cancelBubble=true;return false;} -else if(ch==termKey.DOWN){term.cursorOff();if(term.histPtr==term.history.length)term.lastLine=term._getLine();term._clearLine();if(term.history.length&&term.histPtr<=term.history.length){if(term.histPtr=65&&ch<=96)||ch==63){if(ch==63){ch=31;} -else{ch-=64;}} -term.inputChar=ch;term.ctrlHandler();if(window.event)window.event.cancelBubble=true;return false;} -else if(ctrl||!term.isPrintable(ch,true)){if(window.event)window.event.cancelBubble=true;return false;} -else if(term.isPrintable(ch,true)){if(term.blinkTimer)clearTimeout(term.blinkTimer);if(term.insert){term.cursorOff();term._scrollRight(term.r,term.c);} -term._charOut(ch);term.cursorOn();if(ch==32&&window.event){window.event.cancelBubble=true;} -else if(window.opera&&window.event){window.event.cancelBubble=true;} -return false;}} -return true;},hasSubDivs:false,termStringStart:'',termStringEnd:'',termSpecials:{0:' ',1:' ',9:' ',32:' ',34:'"',38:'&',60:'<',62:'>',127:'◊',0x20AC:'€'},termStyles:[1,2,4,8,16],termStyleMarkup:{'r':1,'u':2,'i':4,'s':8,'b':16},termStyleOpen:{1:'',2:'',4:'',8:'',16:''},termStyleClose:{1:'<\/span>',2:'<\/u>',4:'<\/i>',8:'<\/strike>',16:''},assignStyle:function(styleCode,markup,htmlOpen,htmlClose){var tg=Terminal.prototype.globals;if(!styleCode||isNaN(styleCode)){if(styleCode>=256){alert('termlib.js:\nCould not assign style.\n'+s+' is not a valid power of 2 between 0 and 256.');return;}} -var s=styleCode&0xff;var matched=false;for(var i=0;i<8;i++){if((s>>>i)&1){if(matched){alert('termlib.js:\nCould not assign style code.\n'+s+' is not a power of 2!');return;} -matched=true;}} -if(!matched){alert('termlib.js:\nCould not assign style code.\n'+s+' is not a valid power of 2 between 0 and 256.');return;} -markup=String(markup).toLowerCase();if(markup=='c'||markup=='p'){alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is a reserved code.');return;} -if(markup.length>1){alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is not a single letter code.');return;} -var exists=false;for(var i=0;i=32){var cs=unescape("%"+high+low);termString_keyref[cc]=cs;termString_keycoderef[cs]=cc;}}}},_extendMissingStringMethods:function(){if(!String.fromCharCode||!String.prototype.charCodeAt){Terminal.prototype.globals._termString_makeKeyref();} -if(!String.fromCharCode){String.fromCharCode=function(cc){return(cc!=null)?Terminal.prototype.globals.termString_keyref[cc]:'';};} -if(!String.prototype.charCodeAt){String.prototype.charCodeAt=function(n){cs=this.charAt(n);return(Terminal.prototype.globals.termString_keycoderef[cs])?Terminal.prototype.globals.termString_keycoderef[cs]:0;};}}}} -Terminal.prototype.globals._initGlobals();var TerminalDefaults=Terminal.prototype.Defaults;var termDefaultHandler=Terminal.prototype.defaultHandler;var TermGlobals=Terminal.prototype.globals;var termKey=Terminal.prototype.globals.termKey;var termDomKeyRef=Terminal.prototype.globals.termDomKeyRef;Terminal.prototype._HttpSocket=function(){var req=null;if(window.XMLHttpRequest){try{req=new XMLHttpRequest();} -catch(e){}} -else if(window.ActiveXObject){var prtcls=this._msXMLHttpObjects;for(var i=0;i1)this.prototype._msXMLHttpObjects=[prtcls[i]];break;}} -catch(e){}}} -this.request=req;this.url;this.data=null;this.query='';this.timeoutTimer=null;this.localMode=Boolean(window.location.href.search(/^file:/i)==0);this.error=0;} -Terminal.prototype._HttpSocket.prototype={version:'1.02',useXMLEncoding:false,defaulTimeout:10000,defaultMethod:'GET',forceNewline:true,errno:{OK:0,NOTIMPLEMENTED:1,FATALERROR:2,TIMEOUT:3,NETWORKERROR:4,LOCALFILEERROR:5},errstring:['','XMLHttpRequest not implemented.','Could not open XMLHttpRequest.','The connection timed out.','Network error.','The requested local document was not found.'],_msXMLHttpObjects:['Msxml2.XMLHTTP','Microsoft.XMLHTTP','Msxml2.XMLHTTP.5.0','Msxml2.XMLHTTP.4.0','Msxml2.XMLHTTP.3.0'],serializeData:function(){this.query=this.serialize(this.data);},serialize:function(data){var v='';if(data!=null){switch(typeof data){case'object':var d=[];if(data instanceof Array){for(var i=0;i=200&&r.status<300){success=true;} -else if(r.status>=12000){failed=true;this.error=this.errno.NETWORKERROR;}}}} -catch(e){} -if(!failed){response.status=r.status;response.statusText=(r.status==404)?'Not Found':r.statusText;response.responseText=r.responseText;response.responseXML=r.responseXML;if(this.getHeaders){if(this.getHeaders instanceof Array){for(var i=0;i', + greeting:'%+r Terminal ready. %-r', + // handlers + handler:null, + ctrlHandler:null, + initHandler:null, + exitHandler:null, + wrapping:false, + mapANSI:false, + ANSItrueBlack:false, + textBlur: 0, + textColor: '' +}, + +setInitValues: function() { + this.isSafari= (navigator.userAgent.indexOf('Safari')>=0 || navigator.userAgent.indexOf('WebKit')>=0)? true:false; + this.isOpera= (window.opera && navigator.userAgent.indexOf('Opera')>=0)? true:false; + this.isChrome= (navigator.userAgent.indexOf('Chrome/')>=0 && navigator.userAgent.indexOf('WebKit')>=0)? true:false; + this.domAPI= (document && document.createElement)? true:false; + this.isMac= (navigator.userAgent.indexOf('Mac')>=0)? true:false; + this.id=this.conf.id; + this.maxLines=this.conf.rows; + this.maxCols=this.conf.cols; + this.termDiv=this.conf.termDiv; + this.crsrBlinkMode=this.conf.crsrBlinkMode; + this.crsrBlockMode=this.conf.crsrBlockMode; + this.blinkDelay=this.conf.blinkDelay; + this.DELisBS=this.conf.DELisBS; + this.printTab=this.conf.printTab; + this.printEuro=this.conf.printEuro; + this.catchCtrlH=this.conf.catchCtrlH; + this.closeOnESC=this.conf.closeOnESC; + this.historyUnique=this.conf.historyUnique; + this.ps=this.conf.ps; + this.closed=false; + this.r; + this.c; + this.charBuf=new Array(); + this.styleBuf=new Array(); + this.scrollBuf=null; + this.blinkBuffer=0; + this.blinkTimer; + this.cursoractive=false; + this.lock=true; + this.insert=false; + this.charMode=false; + this.rawMode=false; + this.lineBuffer=''; + this.inputChar=0; + this.lastLine=''; + this.guiCounter=0; + this.history=new Array(); + this.histPtr=0; + this.env=new Object(); + this.buckupBuffer=null; + this.handler=this.conf.handler; + this.wrapping=this.conf.wrapping; + this.mapANSI=this.conf.mapANSI; + this.ANSItrueBlack=this.conf.ANSItrueBlack; + this.ctrlHandler=this.conf.ctrlHandler; + this.initHandler=this.conf.initHandler; + this.exitHandler=this.conf.exitHandler; + this.fieldMode=false; + this.fieldStart=this.fieldEnd=this.fieldC=0; + if (typeof this.conf.textBlur === 'object' && this.conf.textBlur.length) { + var a=[]; + for (var i=0; i0) a.push(b); + } + this.textBlur=(a.length)? a:0; + } + else { + this.textBlur=Number(this.conf.textBlur); + if (isNaN(this.textBlur) || this.textBlur<0 || this.textBlur>40) this.textBlur=0; + } + this.textColor=this.conf.textColor || ''; +}, + +defaultHandler: function() { + this.newLine(); + if (this.lineBuffer != '') { + this.type('You typed: '+this.lineBuffer); + this.newLine(); + } + this.prompt(); +}, + +open: function() { + if (this.termDivReady()) { + if (!this.closed) this._makeTerm(); + this.init(); + return true; + } + else { + return false; + } +}, + +close: function() { + this.lock=true; + this.cursorOff(); + if (this.exitHandler) this.exitHandler(); + this.globals.setVisible(this.termDiv,0); + this.closed=true; +}, + +init: function() { + // wait for gui + if (this.guiReady()) { + this.guiCounter=0; + // clean up at re-entry + if (this.closed) { + this.setInitValues(); + } + this.clear(); + this.globals.setVisible(this.termDiv,1); + this.globals.enableKeyboard(this); + if (this.initHandler) { + this.initHandler(); + } + else { + this.write(this.conf.greeting); + this.newLine(); + this.prompt(); + } + } + else { + this.guiCounter++; + if (this.guiCounter>18000) { + if (confirm('Terminal:\nYour browser hasn\'t responded for more than 2 minutes.\nRetry?')) { + this.guiCounter=0; + } + else { + return; + } + }; + this.globals.termToInitialze=this; + window.setTimeout('Terminal.prototype.globals.termToInitialze.init()',200); + } +}, + +getRowArray: function(l,v) { + // returns a fresh array of l length initialized with value v + var a=new Array(); + for (var i=0; i0) a.push(b); + } + this.textBlur=(a.length)? a:0; + rerender=true; + } + else { + v=Number(v); + if (isNaN(v) || v<0 || v>40) v=0; + if (v!=this.textBlur) { + this.textBlur=v; + rerender=true; + } + } + if (rerender) { + for (var r=0, l=this.conf.rows; r=0) { + var ta=text.split('\n'); + text=ta.join('%n'); + } + } + else { + if (text.join) { + text=text.join('%n'); + } + else { + text=''+text; + } + if (text.indexOf('\n')>=0) { + var ta=text.split('\n'); + text=ta.join('%n'); + } + } + if (this.mapANSI) text=this.globals.ANSI_map(text, this.ANSItrueBlack); + this._sbInit(usemore); + var chunks=text.split('%'); + var esc=(text.charAt(0)!='%'); + var style=0; + var styleMarkUp=this.globals.termStyleMarkup; + for (var i=0; i0) { + this._sbType(chunks[i],style); + } + else if (i>0) { + this._sbType('%', style); + } + esc=false; + } + else { + var func=chunks[i].charAt(0); + if (chunks[i].length==0 && i>0) { + this._sbType("%",style); + esc=true; + } + else if (func=='n') { + this._sbNewLine(true); + if (chunks[i].length>1) this._sbType(chunks[i].substring(1),style); + } + else if (func=='+') { + var opt=chunks[i].charAt(1); + opt=opt.toLowerCase(); + if (opt=='p') { + style=0; + } + else if (styleMarkUp[opt]) { + style|=styleMarkUp[opt]; + } + if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style); + } + else if (func=='-') { + var opt=chunks[i].charAt(1); + opt=opt.toLowerCase(); + if (opt=='p') { + style=0; + } + else if (styleMarkUp[opt]) { + style&=~styleMarkUp[opt]; + } + if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style); + } + else if (chunks[i].length>1 && func=='c') { + var cinfo=this._parseColor(chunks[i].substring(1)); + style=(style&(~0xfffff0))|cinfo.style; + if (cinfo.rest) this._sbType(cinfo.rest,style); + } + else if (chunks[i].length>1 && chunks[i].charAt(0)=='C' && chunks[i].charAt(1)=='S') { + this.clear(); + this._sbInit(); + if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style); + } + else { + if (chunks[i].length>0) this._sbType(chunks[i],style); + } + } + } + this._sbOut(); +}, + +_lookupColor: function(clabel) +{ + if (clabel.length && clabel.length<=2) { + var isHex=false; + for (var i=0; ii) rest=chunk.substring(i+1); + break; + } + else if (c==',') { + isforeground = false; + continue; + } + if( isforeground ) + clabel+=c; + else + bclabel+=c; + } + if (clabel) { + style = this._lookupColor(clabel, false) << 8; + } + + if (bclabel) { + style = (style & 0xff00) | (this._lookupColor(bclabel, true) << 16); + } + + } + else { + var c=chunk.charAt(0); + if (this.globals.isHexChar(c)) { + style=this.globals.hexToNum[c] << 8; + rest=chunk.substring(1); + } + else { + rest=chunk; + } + } + } + return { rest: rest, style: style }; +}, + +// internal scroll buffer output methods + +_sbInit: function(usemore) { + var sb=this.scrollBuf=new Object(); + var sbl=sb.lines=new Array(); + var sbs=sb.styles=new Array(); + sb.more=usemore; + sb.line=0; + sb.status=0; + sb.r=0; + sb.c=this.c; + sbl[0]=this.getRowArray(this.conf.cols,0); + sbs[0]=this.getRowArray(this.conf.cols,0); + for (var i=0; i=this.maxCols) this._sbNewLine(); + } +}, + +_sbNewLine: function(forced) { + var sb=this.scrollBuf; + if (this.wrapping && forced) { + sb.lines[sb.r][sb.c]=10; + sb.lines[sb.r].length=sb.c+1; + } + sb.r++; + sb.c=0; + sb.lines[sb.r]=this.getRowArray(this.conf.cols,0); + sb.styles[sb.r]=this.getRowArray(this.conf.cols,0); +}, + +_sbWrap: function() { + // create a temp wrap buffer wb and scan for words/wrap-chars + // then re-asign lines & styles to scrollBuf + var wb=new Object(); + wb.lines=new Array(); + wb.styles=new Array(); + wb.lines[0]=this.getRowArray(this.conf.cols,0); + wb.styles[0]=this.getRowArray(this.conf.cols,0); + wb.r=0; + wb.c=0; + var sb=this.scrollBuf; + var sbl=sb.lines; + var sbs=sb.styles; + var ch, st, wrap, lc, ls; + var l=this.c; + var lastR=0; + var lastC=0; + wb.cBreak=false; + for (var r=0; r=this.maxCols) this._wbIncLine(wb); + } + if (wrap==3) { + lastR=r; + lastC=c; + l=1; + } + else { + l=0; + lastR=r; + lastC=c+1; + if (lastC==lc.length) { + lastR++; + lastC=0; + } + if (wrap==4) wb.cBreak=true; + } + } + else { + l++; + } + } + else { + continue; + } + } + } + if (l) { + if (wb.cBreak && wb.c!=0) wb.c--; + this._wbOut(wb, lastR, lastC, l); + } + sb.lines=wb.lines; + sb.styles=wb.styles; + sb.r=wb.r; + sb.c=wb.c; +}, + +_wbOut: function(wb, br, bc, l) { + // copy a word (of l length from br/bc) to wrap buffer wb + var sb=this.scrollBuf; + var sbl=sb.lines; + var sbs=sb.styles; + var ofs=0; + var lc, ls; + if (l+wb.c>this.maxCols) { + if (l=ml-1) this.clear(); + } + } + if (this.r+buflen-sb.line<=ml) { + for (var i=sb.line; i=ml) { + var ofs=buflen-ml; + for (var i=0; i0) { + r=this.conf.rows-offset; + } + else { + r=this.conf.rows-1; + } + for (var i=0; i=0 && r=this.maxCols) { + this.c=0; + this._incRow(); + } +}, + +_incRow: function() { + this.r++; + if (this.r>=this.maxLines) { + this._scrollLines(0,this.maxLines); + this.r=this.maxLines-1; + } +}, + +_scrollLines: function(start, end) { + window.status='Scrolling lines ...'; + start++; + for (var ri=start; ri=start; r--) this.redraw(r-1); + window.status=''; +}, + +// control methods + +clear: function() { + window.status='Clearing display ...'; + this.cursorOff(); + this.insert=false; + for (var ri=0; ri0) this.newLine(); + this.type(this.ps); + this._charOut(1); + this.lock=false; + this.cursorOn(); +}, + +isPrintable: function(ch, unicodePage1only) { + if (this.wrapping && this.globals.wrapChars[ch]==4) return true; + if (unicodePage1only && ch>255) { + return (ch==this.termKey.EURO && this.printEuro)? true:false; + } + return ( + (ch>=32 && ch!=this.termKey.DEL) || + (this.printTab && ch==this.termKey.TAB) + ); +}, + +// cursor methods + +cursorSet: function(r,c) { + var crsron=this.cursoractive; + if (crsron) this.cursorOff(); + this.r=r%this.maxLines; + this.c=c%this.maxCols; + this._cursorReset(crsron); +}, + +cursorOn: function() { + if (this.blinkTimer) clearTimeout(this.blinkTimer); + this.blinkBuffer=this.styleBuf[this.r][this.c]; + this._cursorBlink(); + this.cursoractive=true; +}, + +cursorOff: function() { + if (this.blinkTimer) clearTimeout(this.blinkTimer); + if (this.cursoractive) { + this.styleBuf[this.r][this.c]=this.blinkBuffer; + this.redraw(this.r); + this.cursoractive=false; + } +}, + +cursorLeft: function() { + var crsron=this.cursoractive; + if (crsron) this.cursorOff(); + var r=this.r; + var c=this.c; + if (c>0) { + c--; + } + else if (r>0) { + c=this.maxCols-1; + r--; + } + if (this.isPrintable(this.charBuf[r][c])) { + this.r=r; + this.c=c; + } + this.insert=true; + this._cursorReset(crsron); +}, + +cursorRight: function() { + var crsron=this.cursoractive; + if (crsron) this.cursorOff(); + var r=this.r; + var c=this.c; + if (c0) c-- + else if (r>0) { + c=this.maxCols-1; + r--; + }; + if (this.isPrintable(this.charBuf[r][c])) { + this._scrollLeft(r, c); + this.r=r; + this.c=c; + }; + this._cursorReset(crsron); +}, + +fwdDelete: function() { + var crsron=this.cursoractive; + if (crsron) this.cursorOff(); + if (this.isPrintable(this.charBuf[this.r][this.c])) { + this._scrollLeft(this.r,this.c); + if (!this.isPrintable(this.charBuf[this.r][this.c])) this.insert=false; + } + this._cursorReset(crsron); +}, + +_cursorReset: function(crsron) { + if (crsron) { + this.cursorOn(); + } + else { + this.blinkBuffer=this.styleBuf[this.r][this.c]; + } +}, + +_cursorBlink: function() { + if (this.blinkTimer) clearTimeout(this.blinkTimer); + if (this == this.globals.activeTerm) { + if (this.crsrBlockMode) { + this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&1)? + this.styleBuf[this.r][this.c]&0xfffffe:this.styleBuf[this.r][this.c]|1; + } + else { + this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&2)? + this.styleBuf[this.r][this.c]&0xffffd:this.styleBuf[this.r][this.c]|2; + } + this.redraw(this.r); + } + if (this.crsrBlinkMode) this.blinkTimer=setTimeout('Terminal.prototype.globals.activeTerm._cursorBlink()', this.blinkDelay); +}, + +_scrollLeft: function(r,c) { + var rows=new Array(); + rows[0]=r; + while (this.isPrintable(this.charBuf[r][c])) { + var ri=r; + var ci=c+1; + if (ci==this.maxCols) { + if (ri0) { + r--; + c=this.maxCols-1; + } + else { + c=0; + } + } + } + if (this.isPrintable(this.charBuf[r][c])) { + while (true) { + var ri=r; + var ci=c+1; + if (ci==this.maxCols) { + if (ri=this.maxCols) this.c=this.maxCols-1; + } + var line=new Array(); + while (this.isPrintable(this.charBuf[r][c])) { + line[line.length]=String.fromCharCode(this.charBuf[r][c]); + if (c>0) { + c--; + } + else if (r>0) { + c=this.maxCols-1; + r--; + } + else { + break; + } + } + line.reverse(); + return line.join(''); +}, + +_clearLine: function() { + var end=this._getLineEnd(this.r,this.c); + var r=end[0]; + var c=end[1]; + var line=''; + while (this.isPrintable(this.charBuf[r][c])) { + this.charBuf[r][c]=0; + if (c>0) { + c--; + } + else if (r>0) { + this.redraw(r); + c=this.maxCols-1; + r--; + } + else { + break; + } + } + if (r!=end[0]) this.redraw(r); + c++; + this.cursorSet(r,c); + this.insert=false; +}, + +// backup/restore screen & state + +backupScreen: function() { + var backup=this.backupBuffer=new Object(); + var rl=this.conf.rows; + var cl=this.conf.cols; + backup.cbuf=new Array(rl); + backup.sbuf=new Array(rl); + backup.maxCols=this.maxCols; + backup.maxLines=this.maxLines; + backup.r=this.r; + backup.c=this.c; + backup.charMode=this.charMode; + backup.rawMode=this.rawMode; + backup.handler=this.handler; + backup.ctrlHandler=this.ctrlHandler; + backup.cursoractive=this.cursoractive; + + backup.crsrBlinkMode=this.crsrBlinkMode; + backup.crsrBlockMode=this.crsrBlockMode; + backup.blinkDelay=this.blinkDelay; + backup.DELisBS=this.DELisBS; + backup.printTab=this.printTab; + backup.printEuro=this.printEuro; + backup.catchCtrlH=this.catchCtrlH; + backup.closeOnESC=this.closeOnESC; + backup.historyUnique=this.historyUnique; + backup.ps=this.ps; + backup.lineBuffer=this.lineBuffer; + backup.inputChar=this.inputChar; + backup.lastLine=this.lastLine; + backup.historyLength=this.history.length; + backup.histPtr=this.histPtr; + backup.wrapping=this.wrapping; + backup.mapANSI=this.mapANSI; + backup.ANSItrueBlack=this.ANSItrueBlack; + if (this.cursoractive) this.cursorOff(); + for (var r=0; rbackup.historyLength) { + this.history.length=backup.historyLength; + this.histPtr=backup.histPtr; + } + this.wrapping=backup.wrapping; + this.mapANSI=backup.mapANSI; + this.ANSItrueBlack=backup.ANSItrueBlack; + if (this.cursoractive) this.cursorOn(); + this.backupBuffer=null; +}, + +swapBackup: function() { + // swap current state and backup buffer (e.g.: toggle do/undo) + var backup=this.backupBuffer; + this.backupScreen; + if (backup) { + var backup2=this.backupBuffer; + this.backupBuffer=backup; + this.restoreScreen(); + this.backupBuffer=backup2; + } +}, + +// simple markup escaping + +escapeMarkup: function(t) { + return t.replace(/%/g, '%%'); +}, + +// field mode + +enterFieldMode: function(start, end, style) { + this.cursorOff(); + if (start===undefined || start<0) start=this.c; + if (end=== undefined || endthis.maxCols) end=this.maxCols; + if (!style) style=0; + this.fieldStart=start; + this.fieldEnd=end; + this.fieldStyle=style; + this.fieldC=0; + this.lastLine=''; + this.fieldMode=true; + this.rawMode=this.charMode=false; + if (style&1) { + this._crsrWasBlockMode=this.crsrBlockMode; + this._crsrWasBlinkMode=this.crsrBlinkMode; + this.crsrBlockMode=false; + this.crsrBlinkMode=true; + } + this.drawField(); + this.lock=false; +}, + +exitFieldMode: function() { + this.drawField(true); + this.fieldMode=false; + this.c=this.fieldEnd; + if (this.c==this.maxLine) this.newLine(); + this.lock=true; +}, + +drawField: function(isfinal) { + this.cursorOff(); + if (isfinal) this.fieldC=0; + var fl=this.fieldEnd-this.fieldStart; + if (this.fieldC==this.lastLine.length) fl--; + var ofs=this.fieldC-fl; + if (ofs<0) ofs=0; + var line = (ofs)? this.lastLine.substring(ofs):this.lastLine; + var sb=this.styleBuf[this.r]; + var cb=this.charBuf[this.r]; + var max=line.length; + for (var i=this.fieldStart, k=0; i\n'; + s+='
\n'; + var rstr=''; + for (var c=0; c'+rstr+'<\/td><\/tr>\n'; + } + s+='<\/table><\/td><\/tr>\n'; + s+='<\/table><\/td><\/tr>\n'; + s+='<\/table>\n'; + var termOffset=2+this.conf.frameWidth; + if (this.globals.hasSubDivs) { + for (var r=0; r<\/div>\n'; + } + this.globals.termStringStart='
'; + this.globals.termStringEnd='<\/td><\/tr><\/table>'; + } + this.globals.writeElement(this.termDiv,s); + } + if (!rebuild) { + this.globals.setElementXY(this.termDiv,this.conf.x,this.conf.y); + this.globals.setVisible(this.termDiv,1); + } + window.status=''; +}, + +rebuild: function() { + // check for bounds and array lengths + var rl=this.conf.rows; + var cl=this.conf.cols; + for (var r=0; r=rl) { + r=rl-1; + resetcrsr=true; + } + if (this.c>=cl) { + c=cl-1; + resetcrsr=true; + } + if (resetcrsr && this.cursoractive) this.cursorOn(); + // and actually rebuild + this._makeTerm(true); + for (var r=0; r=0; k--) { + var st=tstls[k]; + if (curStyle & st) s+=tscls[st]; + } + } + curStyle=cs; + for (var k=0; k>>8) & 0xff; + clr= (cc<16)? tclrs[cc] : 0; + } + if (curStyle & 0xff0000) { + var bc=((curStyle & 0xff0000)>>>16) & 0xff; + bgclr= (bc<16)? tclrs[bc] : 0; + } + if (clr) { + if (curStyle&1) { + s+=''; + } + else if (typeof blur === 'object') { + s+=''; + } + else if (blur) { + s+=''; + } + else { + s+=''; + } + } + } + s+= (tspcl[c])? tspcl[c] : String.fromCharCode(c); + } + if (curStyle>0) { + if (curStyle & 0xffff00) s+=''; + for (var k=tstls.length-1; k>=0; k--) { + var st=tstls[k]; + if (curStyle&st) s+=tscls[st]; + } + } + s+=this.globals.termStringEnd; + this.globals.writeElement(this.termDiv+'_r'+r,s); +}, + +guiReady: function() { + var ready=true; + if (this.globals.guiElementsReady(this.termDiv)) { + for (var r=0; r='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))? true:false; + }, + + isHexOnlyChar: function(c) { + return ((c>='a' && c<='f') || (c>='A' && c<='F'))? true:false; + }, + + hexToNum: { + '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, + '8': 8, '9': 9, 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15, + 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15 + }, + + // data for color support + + webColors: [], + webColorCodes: [''], + + colors: { + // ANSI bright (bold) color set + black: 1, + red: 2, + green: 3, + yellow: 4, + blue: 5, + magenta: 6, + cyan: 7, + white: 8, + // dark color set + grey: 9, + red2: 10, + green2: 11, + yellow2: 12, + blue2: 13, + magenta2: 14, + cyan2: 15, + // synonyms + red1: 2, + green1: 3, + yellow1: 4, + blue1: 5, + magenta1: 6, + cyan1: 7, + gray: 9, + darkred: 10, + darkgreen: 11, + darkyellow: 12, + darkblue: 13, + darkmagenta: 14, + darkcyan: 15, + // default color + 'default': 0, + clear: 0 + }, + + colorCodes: [ + '', '#000000', '#ff0000', '#00ff00', '#ffff00', '#0066ff', '#ff00ff', '#00ffff', '#ffffff', + '#808080', '#990000', '#009900', '#999900', '#003399', '#990099', '#009999' + ], + + _webSwatchChars: ['0','3','6','9','c','f'], + _initWebColors: function() { + // generate long and short web color ref + var tg=Terminal.prototype.globals; + var ws=tg._webColorSwatch; + var wn=tg.webColors; + var cc=tg.webColorCodes; + var n=1; + var a, b, c, al, bl, bs, cl; + for (var i=0; i<6; i++) { + a=tg._webSwatchChars[i]; + al=a+a; + for (var j=0; j<6; j++) { + b=tg._webSwatchChars[j]; + bl=al+b+b; + bs=a+b; + for (var k=0; k<6; k++) { + c=tg._webSwatchChars[k]; + cl=bl+c+c; + wn[bs+c]=wn[cl]=n; + cc[n]=cl; + n++; + } + } + } + }, + + webifyColor: function(s) { + // return nearest web color in 3 digit format + // (do without RegExp for compatibility) + var tg=Terminal.prototype.globals; + if (s.length==6) { + var c=''; + for (var i=0; i<6; i+=2) { + var a=s.charAt(i); + var b=s.charAt(i+1); + if (tg.isHexChar(a) && tg.isHexChar(b)) { + c+=tg._webSwatchChars[Math.round(parseInt(a+b,16)/255*5)]; + } + else { + return ''; + } + } + return c; + } + else if (s.length==3) { + var c=''; + for (var i=0; i<3; i++) { + var a=s.charAt(i); + if (tg.isHexChar(a)) { + c+=tg._webSwatchChars[Math.round(parseInt(a,16)/15*5)]; + } + else { + return ''; + } + } + return c; + } + else { + return ''; + } + }, + + // public methods for color support + + setColor: function(label, value) { + var tg=Terminal.prototype.globals; + if (typeof label == 'number' && label>=1 && label<=15) { + tg.colorCodes[label]=value; + } + else if (typeof label == 'string') { + label=label.toLowerCase(); + if (label.length==1 && tg.isHexChar(label)) { + var n=tg.hexToNum[label]; + if (n) tg.colorCodes[n]=value; + } + else if (typeof tg.colors[label] != 'undefined') { + var n=tg.colors[label]; + if (n) tg.colorCodes[n]=value; + } + } + }, + + getColorString: function(label) { + var tg=Terminal.prototype.globals; + if (typeof label == 'number' && label>=0 && label<=15) { + return tg.colorCodes[label]; + } + else if (typeof label == 'string') { + label=label.toLowerCase(); + if (label.length==1 && tg.isHexChar(label)) { + return tg.colorCodes[tg.hexToNum[label]]; + } + else if (typeof tg.colors[label] != 'undefined') { + return tg.colorCodes[tg.colors[label]]; + } + } + return ''; + }, + + getColorCode: function(label) { + var tg=Terminal.prototype.globals; + if (typeof label == 'number' && label>=0 && label<=15) { + return label; + } + else if (typeof label == 'string') { + label=label.toLowerCase(); + if (label.length==1 && tg.isHexChar(label)) { + return parseInt(label,16); + } + else if (typeof tg.colors[label] != 'undefined') { + return tg.colors[label]; + } + } + return 0; + }, + + // import/paste methods (methods return success) + + insertText: function(text) { + // auto-types a given string to the active terminal + // returns success (false indicates a lock or no active terminal) + var tg=Terminal.prototype.globals; + var termRef = tg.activeTerm; + if (!termRef || termRef.closed || tg.keylock || termRef.lock || termRef.charMode || termRef.fieldMode) return false; + // terminal open and unlocked, so type the text + for (var i=0; i; + // (no history entry for this) + termRef.lineBuffer = text; + termRef.lastLine = ''; + termRef.inputChar = 0; + termRef.handler(); + return true; + }, + + // text related service functions + + normalize: function(n,m) { + var s=''+n; + while (s.length=0) { + t=t.substring(0,ofs)+s2+t.substring(ofs+l1); + ofs=t.indexOf(s1,ofs+l2); + } + return t; + }, + + + // config data for text wrap + + wrapChars: { + // keys: charCode + // values: 1 = white space, 2 = wrap after, 3 = wrap before, 4 = conditional word break + 9: 1, // tab + 10: 1, // new line - don't change this (used internally)!!! + 12: 4, // form feed (use this for conditional word breaks) + 13: 1, // cr + 32: 1, // blank + 40: 3, // ( + 45: 2, // dash/hyphen + 61: 2, // = + 91: 3, // [ + 94: 3, // caret (non-printing chars) + 123: 3 // { + }, + + + // keyboard methods & controls + + setFocus: function(termref) { + Terminal.prototype.globals.activeTerm=termref; + Terminal.prototype.globals.clearRepeatTimer(); + }, + + termKey: { + // codes of special keys + 'NUL': 0x00, + 'SOH': 0x01, + 'STX': 0x02, + 'ETX': 0x03, + 'EOT': 0x04, + 'ENQ': 0x05, + 'ACK': 0x06, + 'BEL': 0x07, + 'BS': 0x08, + 'BACKSPACE': 0x08, + 'HT': 0x09, + 'TAB': 0x09, + 'LF': 0x0A, + 'VT': 0x0B, + 'FF': 0x0C, + 'CR': 0x0D, + 'SO': 0x0E, + 'SI': 0x0F, + 'DLE': 0x10, + 'DC1': 0x11, + 'DC2': 0x12, + 'DC3': 0x13, + 'DC4': 0x14, + 'NAK': 0x15, + 'SYN': 0x16, + 'ETB': 0x17, + 'CAN': 0x18, + 'EM': 0x19, + 'SUB': 0x1A, + 'ESC': 0x1B, + 'IS4': 0x1C, + 'IS3': 0x1D, + 'IS2': 0x1E, + 'IS1': 0x1F, + 'DEL': 0x7F, + // other specials + 'EURO': 0x20AC, + // cursor mapping + 'LEFT': 0x1C, + 'RIGHT': 0x1D, + 'UP': 0x1E, + 'DOWN': 0x1F + }, + + // map some DOM_VK_* properties to values defined in termKey + termDomKeyRef: {}, + _domKeyMappingData: { + 'LEFT': 'LEFT', + 'RIGHT': 'RIGHT', + 'UP': 'UP', + 'DOWN': 'DOWN', + 'BACK_SPACE': 'BS', + 'RETURN': 'CR', + 'ENTER': 'CR', + 'ESCAPE': 'ESC', + 'DELETE': 'DEL', + 'TAB': 'TAB' + }, + _initDomKeyRef: function() { + var tg=Terminal.prototype.globals; + var m=tg._domKeyMappingData; + var r=tg.termDomKeyRef; + var k=tg.termKey; + for (var i in m) r['DOM_VK_'+i]=k[m[i]]; + }, + + registerEvent: function(obj, eventType, handler, capture) { + if (obj.addEventListener) { + obj.addEventListener(eventType.toLowerCase(), handler, capture); + } + /* + else if (obj.attachEvent) { + obj.attachEvent('on'+eventType.toLowerCase(), handler); + } + */ + else { + var et=eventType.toUpperCase(); + if (window.Event && window.Event[et] && obj.captureEvents) obj.captureEvents(Event[et]); + obj['on'+eventType.toLowerCase()]=handler; + } + }, + releaseEvent: function(obj, eventType, handler, capture) { + if (obj.removeEventListener) { + obj.removeEventListener(eventType.toLowerCase(), handler, capture); + } + /* + else if (obj.detachEvent) { + obj.detachEvent('on'+eventType.toLowerCase(), handler); + } + */ + else { + var et=eventType.toUpperCase(); + if (window.Event && window.Event[et] && obj.releaseEvents) obj.releaseEvents(Event[et]); + et='on'+eventType.toLowerCase(); + if (obj[et] && obj[et]==handler) obj.et=null; + } + }, + + enableKeyboard: function(term) { + var tg=Terminal.prototype.globals; + if (!tg.kbdEnabled) { + tg.registerEvent(document, 'keypress', tg.keyHandler, true); + tg.registerEvent(document, 'keydown', tg.keyFix, true); + tg.registerEvent(document, 'keyup', tg.clearRepeatTimer, true); + tg.kbdEnabled=true; + } + tg.activeTerm=term; + }, + + disableKeyboard: function(term) { + var tg=Terminal.prototype.globals; + if (tg.kbdEnabled) { + tg.releaseEvent(document, 'keypress', tg.keyHandler, true); + tg.releaseEvent(document, 'keydown', tg.keyFix, true); + tg.releaseEvent(document, 'keyup', tg.clearRepeatTimer, true); + tg.kbdEnabled=false; + } + tg.activeTerm=null; + }, + + // remap some special key mappings on keydown + + keyFix: function(e) { + var tg=Terminal.prototype.globals; + var term=tg.activeTerm; + var ch; + if (tg.keylock || term.lock) return true; + if (window.event) { + if (!e) e=window.event; + ch=e.keyCode; + if (e.DOM_VK_UP) { + for (var i in tg.termDomKeyRef) { + if (e[i] && ch == e[i]) { + tg.keyHandler({which:tg.termDomKeyRef[i],_remapped:true,_repeat:(ch==0x1B)? true:false}); + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + e.cancelBubble=true; + return false; + } + } + e.cancelBubble=false; + return true; + } + else { + // no DOM support + var termKey=term.termKey; + var keyHandler=tg.keyHandler; + if (ch==8 && !term.isOpera) { keyHandler({which:termKey.BS,_remapped:true,_repeat:true}); } + else if (ch==9) { keyHandler({which:termKey.TAB,_remapped:true,_repeat: (term.printTab)? false:true}); } + else if (ch==27) { keyHandler({which:termKey.ESC,_remapped:true,_repeat: (term.printTab)? false:true}); } + else if (ch==37) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); } + else if (ch==39) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); } + else if (ch==38) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); } + else if (ch==40) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); } + else if (ch==127 || ch==46) { keyHandler({which:termKey.DEL,_remapped:true,_repeat:true}); } + else if (ch>=57373 && ch<=57376) { + if (ch==57373) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); } + else if (ch==57374) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); } + else if (ch==57375) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); } + else if (ch==57376) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); } + } + else { + e.cancelBubble=false; + return true; + } + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + e.cancelBubble=true; + return false; + } + } + }, + + clearRepeatTimer: function(e) { + var tg=Terminal.prototype.globals; + if (tg.keyRepeatTimer) { + clearTimeout(tg.keyRepeatTimer); + tg.keyRepeatTimer=null; + } + }, + + doKeyRepeat: function(ch) { + Terminal.prototype.globals.keyHandler({which:ch,_remapped:true,_repeated:true}) + }, + + keyHandler: function(e) { + var tg=Terminal.prototype.globals; + var term=tg.activeTerm; + if (tg.keylock || term.lock || term.isMac && e && e.metaKey) return true; + if (window.event) { + if (window.event.preventDefault) window.event.preventDefault(); + if (window.event.stopPropagation) window.event.stopPropagation(); + } + else if (e) { + if (e.preventDefault) e.preventDefault(); + if (e.stopPropagation) e.stopPropagation(); + } + var ch; + var ctrl=false; + var shft=false; + var remapped=false; + var termKey=term.termKey; + var keyRepeat=0; + if (e) { + ch=e.which; + ctrl=((e.ctrlKey && !e.altKey) || e.modifiers==2); + shft=(e.shiftKey || e.modifiers==4); + if (e._remapped) { + remapped=true; + if (window.event) { + //ctrl=(ctrl || window.event.ctrlKey); + ctrl=(ctrl || (window.event.ctrlKey && !window.event.altKey)); + shft=(shft || window.event.shiftKey); + } + } + if (e._repeated) { + keyRepeat=2; + } + else if (e._repeat) { + keyRepeat=1; + } + } + else if (window.event) { + ch=window.event.keyCode; + //ctrl=(window.event.ctrlKey); + ctrl=(window.event.ctrlKey && !window.event.altKey); // allow alt gr == ctrl alt + shft=(window.event.shiftKey); + if (window.event._repeated) { + keyRepeat=2; + } + else if (window.event._repeat) { + keyRepeat=1; + } + } + else { + return true; + } + if (ch=='' && remapped==false) { + // map specials + if (e==null) e=window.event; + if (e.charCode==0 && e.keyCode) { + if (e.DOM_VK_UP) { + var dkr=tg.termDomKeyRef; + for (var i in dkr) { + if (e[i] && e.keyCode == e[i]) { + ch=dkr[i]; + break; + } + } + } + else { + // NS4 + if (e.keyCode==28) { ch=termKey.LEFT; } + else if (e.keyCode==29) { ch=termKey.RIGHT; } + else if (e.keyCode==30) { ch=termKey.UP; } + else if (e.keyCode==31) { ch=termKey.DOWN; } + // Mozilla alike but no DOM support + else if (e.keyCode==37) { ch=termKey.LEFT; } + else if (e.keyCode==39) { ch=termKey.RIGHT; } + else if (e.keyCode==38) { ch=termKey.UP; } + else if (e.keyCode==40) { ch=termKey.DOWN; } + // just to have the TAB mapping here too + else if (e.keyCode==9) { ch=termKey.TAB; } + } + } + } + // leave on unicode private use area (might be function key etc) + if ((ch>=0xE000) && (ch<= 0xF8FF)) return; + if (keyRepeat) { + tg.clearRepeatTimer(); + tg.keyRepeatTimer = window.setTimeout( + 'Terminal.prototype.globals.doKeyRepeat('+ch+')', + (keyRepeat==1)? tg.keyRepeatDelay1:tg.keyRepeatDelay2 + ); + } + // key actions + if (term.charMode) { + term.insert=false; + term.inputChar=ch; + term.lineBuffer=''; + term.handler(); + if (ch<=32 && window.event) window.event.cancelBubble=true; + return false; + } + if (!ctrl) { + // special keys + if (ch==termKey.CR) { + term.lock=true; + term.cursorOff(); + term.insert=false; + if (term.rawMode) { + term.lineBuffer=term.lastLine; + } + else if (term.fieldMode) { + term.lineBuffer=term.lastLine; + term.exitFieldMode(); + } + else { + term.lineBuffer=term._getLine(true); + if ( + term.lineBuffer!='' && + (!term.historyUnique || term.history.length==0 || + term.lineBuffer!=term.history[term.history.length-1]) + ) { + term.history[term.history.length]=term.lineBuffer; + } + term.histPtr=term.history.length; + } + term.lastLine=''; + term.inputChar=0; + term.handler(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (term.fieldMode) { + if (ch==termKey.ESC) { + term.lineBuffer=term.lastLine=''; + term.exitFieldMode(); + term.lastLine=''; + term.inputChar=0; + term.handler(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (ch==termKey.LEFT) { + if (term.fieldC>0) term.fieldC--; + } + else if (ch==termKey.RIGHT) { + if (term.fieldC0) { + term.lastLine=term.lastLine.substring(0,term.fieldC-1)+term.lastLine.substring(term.fieldC); + term.fieldC--; + } + } + else if (ch==termKey.DEL) { + if (term.fieldC=32) { + term.lastLine=term.lastLine.substring(0,term.fieldC)+String.fromCharCode(ch)+term.lastLine.substring(term.fieldC); + term.fieldC++; + } + term.drawField(); + return false; + } + else if (ch==termKey.ESC && term.conf.closeOnESC) { + term.close(); + if (window.event) window.event.cancelBubble=true; + return false; + } + if (ch<32 && term.rawMode) { + if (window.event) window.event.cancelBubble=true; + return false; + } + else { + if (ch==termKey.LEFT) { + term.cursorLeft(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (ch==termKey.RIGHT) { + term.cursorRight(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (ch==termKey.UP) { + term.cursorOff(); + if (term.histPtr==term.history.length) term.lastLine=term._getLine(); + term._clearLine(); + if (term.history.length && term.histPtr>=0) { + if (term.histPtr>0) term.histPtr--; + term.type(term.history[term.histPtr]); + } + else if (term.lastLine) { + term.type(term.lastLine); + } + term.cursorOn(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (ch==termKey.DOWN) { + term.cursorOff(); + if (term.histPtr==term.history.length) term.lastLine=term._getLine(); + term._clearLine(); + if (term.history.length && term.histPtr<=term.history.length) { + if (term.histPtr=65 && ch<=96) || ch==63) { + // remap canonical + if (ch==63) { + ch=31; + } + else { + ch-=64; + } + } + term.inputChar=ch; + term.ctrlHandler(); + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (ctrl || !term.isPrintable(ch,true)) { + if (window.event) window.event.cancelBubble=true; + return false; + } + else if (term.isPrintable(ch,true)) { + if (term.blinkTimer) clearTimeout(term.blinkTimer); + if (term.insert) { + term.cursorOff(); + term._scrollRight(term.r,term.c); + } + term._charOut(ch); + term.cursorOn(); + if (ch==32 && window.event) { + window.event.cancelBubble=true; + } + else if (window.opera && window.event) { + window.event.cancelBubble=true; + } + return false; + } + } + return true; + }, + + + // gui mappings + + hasSubDivs: false, + termStringStart: '', + termStringEnd: '', + + termSpecials: { + // special HTML escapes + 0: ' ', + 1: ' ', + 9: ' ', + 32: ' ', + 34: '"', + 38: '&', + 60: '<', + 62: '>', + 127: '◊', + 0x20AC: '€' + }, + + // extensive list of max 8 styles (2^n, n<16) + termStyles: [1,2,4,8, 16], + // style markup: one letter keys, reserved keys: "p" (plain), "c" (color) + termStyleMarkup: { + 'r': 1, + 'u': 2, + 'i': 4, + 's': 8, + 'b': 16 // map "b" to 16 (italics) for ANSI mapping + }, + // mappings for styles (heading HTML) + termStyleOpen: { + 1: '', + 2: '', + 4: '', + 8: '', + 16: '' + }, + // mapping for styles (trailing HTML) + termStyleClose: { + 1: '<\/span>', + 2: '<\/u>', + 4: '<\/i>', + 8: '<\/strike>', + 16: '' + }, + + // method to install custom styles + assignStyle: function(styleCode, markup, htmlOpen, htmlClose) { + var tg=Terminal.prototype.globals; + // check params + if (!styleCode || isNaN(styleCode)) { + if (styleCode>=256) { + alert('termlib.js:\nCould not assign style.\n'+s+' is not a valid power of 2 between 0 and 256.'); + return; + } + } + var s=styleCode&0xff; + var matched=false; + for (var i=0; i<8; i++) { + if ((s>>>i)&1) { + if (matched) { + alert('termlib.js:\nCould not assign style code.\n'+s+' is not a power of 2!'); + return; + } + matched=true; + } + } + if (!matched) { + alert('termlib.js:\nCould not assign style code.\n'+s+' is not a valid power of 2 between 0 and 256.'); + return; + } + markup=String(markup).toLowerCase(); + if (markup=='c' || markup=='p') { + alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is a reserved code.'); + return; + } + if (markup.length>1) { + alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is not a single letter code.'); + return; + } + var exists=false; + for (var i=0; i=32) { + var cs=unescape("%"+high+low); + termString_keyref[cc]=cs; + termString_keycoderef[cs]=cc; + } + } + } + }, + + _extendMissingStringMethods: function() { + if (!String.fromCharCode || !String.prototype.charCodeAt) { + Terminal.prototype.globals._termString_makeKeyref(); + } + if (!String.fromCharCode) { + String.fromCharCode=function(cc) { + return (cc!=null)? Terminal.prototype.globals.termString_keyref[cc] : ''; + }; + } + if (!String.prototype.charCodeAt) { + String.prototype.charCodeAt=function(n) { + cs=this.charAt(n); + return (Terminal.prototype.globals.termString_keycoderef[cs])? + Terminal.prototype.globals.termString_keycoderef[cs] : 0; + }; + } + } + + // end of Terminal.prototype.globals +} + +// end of Terminal.prototype +} + +// initialize global data +Terminal.prototype.globals._initGlobals(); + +// global entities for backward compatibility with termlib 1.x applications +var TerminalDefaults = Terminal.prototype.Defaults; +var termDefaultHandler = Terminal.prototype.defaultHandler; +var TermGlobals = Terminal.prototype.globals; +var termKey = Terminal.prototype.globals.termKey; +var termDomKeyRef = Terminal.prototype.globals.termDomKeyRef; + +// eof \ No newline at end of file diff --git a/makefile b/makefile index e2e846818f..27d7643687 100644 --- a/makefile +++ b/makefile @@ -524,6 +524,8 @@ ifeq ($(TARGET_OS),dos) endif ifeq ($(TARGET_OS),js) RTL_LIBS += $(libdir)/termlib_min.js + RTL_LIBS += $(libdir)/fb_rtlib.js + RTL_LIBS += $(libdir)/fb_shell.html endif # @@ -594,6 +596,12 @@ $(libdir)/fbrt0pic.o: $(srcdir)/rtlib/static/fbrt0.c $(LIBFB_H) $(libdir)/termlib_min.js: $(rootdir)lib/termlib_min.js cp $< $@ + +$(libdir)/fb_rtlib.js: $(rootdir)lib/fb_rtlib.js + cp $< $@ + +$(libdir)/fb_shell.html: $(rootdir)lib/fb_shell.html + cp $< $@ $(libdir)/libfb.a: $(LIBFB_C) $(LIBFB_S) ifeq ($(TARGET_OS),dos) diff --git a/src/compiler/fbc.bas b/src/compiler/fbc.bas index 91ee934d76..af7a878007 100644 --- a/src/compiler/fbc.bas +++ b/src/compiler/fbc.bas @@ -695,7 +695,10 @@ private function hLinkFiles( ) as integer next ldcline += " --shell-file" + hFindLib("fb_shell.html") - ldcline += " --post-js" + hFindLib("termlib_min.js") + ldcline += " --post-js" + hFindLib("fb_rtlib.js") + if( len(fbc.subsystem) = 0 ) then + ldcline += " --post-js" + hFindLib("termlib_min.js") + end if end select diff --git a/src/rtlib/js/hinit.c b/src/rtlib/js/hinit.c index 5070bdc396..cb8b8794b4 100644 --- a/src/rtlib/js/hinit.c +++ b/src/rtlib/js/hinit.c @@ -2,8 +2,6 @@ #include "../fb.h" #include "fb_private_console.h" -#include -#include FB_CONSOLE_CTX __fb_con; @@ -18,22 +16,22 @@ FBCALL void fb_GraphicsUnlock( void ) { return; } static const char color_remap[16] = { - [FB_COLOR_BLACK] = '1', - [FB_COLOR_BLUE] = 'D', - [FB_COLOR_GREEN] = 'B', - [FB_COLOR_CYAN] = 'F', - [FB_COLOR_RED] = 'A', - [FB_COLOR_MAGENTA] = 'E', - [FB_COLOR_BROWN] = 'C', - [FB_COLOR_WHITE] = '8', - [FB_COLOR_GREY] = '9', - [FB_COLOR_LBLUE] = '5', - [FB_COLOR_LGREEN] = '3', - [FB_COLOR_LCYAN] = '7', - [FB_COLOR_LRED] = '2', - [FB_COLOR_LMAGENTA] = '6', - [FB_COLOR_YELLOW] = '4', - [FB_COLOR_BWHITE] = '8', + [FB_COLOR_BLACK] = 0x1, + [FB_COLOR_BLUE] = 0xD, + [FB_COLOR_GREEN] = 0xB, + [FB_COLOR_CYAN] = 0xF, + [FB_COLOR_RED] = 0xA, + [FB_COLOR_MAGENTA] = 0xE, + [FB_COLOR_BROWN] = 0xC, + [FB_COLOR_WHITE] = 0x8, + [FB_COLOR_GREY] = 0x9, + [FB_COLOR_LBLUE] = 0x5, + [FB_COLOR_LGREEN] = 0x3, + [FB_COLOR_LCYAN] = 0x7, + [FB_COLOR_LRED] = 0x2, + [FB_COLOR_LMAGENTA] = 0x6, + [FB_COLOR_YELLOW] = 0x4, + [FB_COLOR_BWHITE] = 0x8, }; static void fb_fs_init_console(void) diff --git a/src/rtlib/js/io_cls.c b/src/rtlib/js/io_cls.c index 24efcc10be..55a1b27d0b 100644 --- a/src/rtlib/js/io_cls.c +++ b/src/rtlib/js/io_cls.c @@ -1,7 +1,11 @@ /* console CLS statement */ #include "../fb.h" +#include "fb_private_console.h" void fb_ConsoleClear( int mode ) { + EM_ASM({ + __fb_rtlib.console.clear(); + }); } diff --git a/src/rtlib/js/io_color.c b/src/rtlib/js/io_color.c index b79a56fe7e..70f7f4dd17 100644 --- a/src/rtlib/js/io_color.c +++ b/src/rtlib/js/io_color.c @@ -19,7 +19,7 @@ int fb_ConsoleColor( int fc, int bc, int flags ) char bc_c = __fb_con.color_remap[last_bc]; EM_ASM_ARGS({ - fbrt_term.color_set('$0', '$1'); + __fb_rtlib.console.color_set($0, $1); }, fc_c, bc_c); return cur; diff --git a/src/rtlib/js/io_getsize.c b/src/rtlib/js/io_getsize.c index 2d9eb1415f..258ee7cab2 100644 --- a/src/rtlib/js/io_getsize.c +++ b/src/rtlib/js/io_getsize.c @@ -1,7 +1,12 @@ #include "../fb.h" +#include "fb_private_console.h" FBCALL void fb_ConsoleGetSize( int *cols, int *rows ) { - *cols = 80; - *rows = 25; + int res = EM_ASM_INT({ + return __fb_rtlib.console.size_get(); + }, NULL); + + *cols = res & 0xFF; + *rows = (res >> 8) & 0xFF; } diff --git a/src/rtlib/js/io_getx.c b/src/rtlib/js/io_getx.c index 49604ae5fa..93aaea3e72 100644 --- a/src/rtlib/js/io_getx.c +++ b/src/rtlib/js/io_getx.c @@ -1,6 +1,11 @@ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleGetX( void ) { - return 0; + int res = EM_ASM_INT({ + return __fb_rtlib.console.pos_get(); + },NULL); + + return 1+(res & 0xFF); } diff --git a/src/rtlib/js/io_getxy.c b/src/rtlib/js/io_getxy.c index 05da926585..813e7a04d6 100644 --- a/src/rtlib/js/io_getxy.c +++ b/src/rtlib/js/io_getxy.c @@ -1,10 +1,15 @@ #include "../fb.h" +#include "fb_private_console.h" FBCALL void fb_ConsoleGetXY( int *col, int *row ) { + int res = EM_ASM_INT({ + return __fb_rtlib.console.pos_get(); + },NULL); + if( col != NULL ) - *col = 0; + *col = 1+(res & 0xFF); if( row != NULL ) - *row = 0; + *row = 1+((res >> 8) & 0xFF); } diff --git a/src/rtlib/js/io_gety.c b/src/rtlib/js/io_gety.c index 8809660948..1e8957a260 100644 --- a/src/rtlib/js/io_gety.c +++ b/src/rtlib/js/io_gety.c @@ -1,6 +1,11 @@ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleGetY( void ) { - return 0; + int res = EM_ASM_INT( + return __fb_rtlib.console.pos_get(); + ,NULL); + + return 1+((res >> 8) & 0xFF); } diff --git a/src/rtlib/js/io_locate.c b/src/rtlib/js/io_locate.c index 095722fc72..b6851ffcfb 100644 --- a/src/rtlib/js/io_locate.c +++ b/src/rtlib/js/io_locate.c @@ -6,7 +6,7 @@ int fb_ConsoleLocate( int row, int col, int cursor ) { EM_ASM_ARGS({ - fbrt_term.position_set($0, $1); + __fb_rtlib.console.pos_set($0, $1); }, row-1, col-1); return (col & 0xFF) | ((row & 0xFF) << 8); diff --git a/src/rtlib/js/io_maxrow.c b/src/rtlib/js/io_maxrow.c index 090adce923..d4598c7373 100644 --- a/src/rtlib/js/io_maxrow.c +++ b/src/rtlib/js/io_maxrow.c @@ -1,6 +1,7 @@ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleGetMaxRow( void ) { - return 25; + return 100; } diff --git a/src/rtlib/js/io_printbuff.c b/src/rtlib/js/io_printbuff.c index 88794cf36e..f9422b8396 100644 --- a/src/rtlib/js/io_printbuff.c +++ b/src/rtlib/js/io_printbuff.c @@ -1,10 +1,13 @@ /* low-level print to console function stub */ #include "../fb.h" +#include "fb_private_console.h" void fb_ConsolePrintBufferEx( const void *buffer, size_t len, int mask ) { - fwrite(buffer, 1, len, stdout); + EM_ASM_ARGS({ + __fb_rtlib.console.writeSubs(UTF8ToString($0), $1); + }, buffer, len ); } void fb_ConsolePrintBuffer( const char *buffer, int mask ) diff --git a/src/rtlib/js/io_readxy.c b/src/rtlib/js/io_readxy.c index 8ce2aea1d1..3f75152c5d 100644 --- a/src/rtlib/js/io_readxy.c +++ b/src/rtlib/js/io_readxy.c @@ -1,9 +1,20 @@ /* console SCREEN() function (character/color query) */ #include "../fb.h" +#include "fb_private_console.h" FBCALL unsigned int fb_ConsoleReadXY( int col, int row, int colorflag ) { - /* !!!WRITEME!!! */ - return 0; + unsigned int res = 0; + + if( colorflag ) + res = EM_ASM_INT({ + __fb_rtlib.console.charAt($0, $1) + }, col-1, row-1); + else + res = EM_ASM_INT({ + __fb_rtlib.console.colorAt($0, $1) + }, col-1, row-1); + + return res; } diff --git a/src/rtlib/js/io_width.c b/src/rtlib/js/io_width.c index 30d2492dbe..70b2127825 100644 --- a/src/rtlib/js/io_width.c +++ b/src/rtlib/js/io_width.c @@ -1,8 +1,19 @@ /* console width() function */ #include "../fb.h" +#include "fb_private_console.h" int fb_ConsoleWidth( int cols, int rows ) { - return (25 << 16) | 80; + if( cols < 40 ) + cols = 40; + + if( rows < 10 ) + rows = 10; + + EM_ASM_ARGS({ + __fb_rtlib.console.size_set($0, $1); + },cols, rows); + + return (rows << 16) | cols; } From e79f80d74b319e9cb6140be3fa17080f6b3ded13 Mon Sep 17 00:00:00 2001 From: v1ctor Date: Sun, 18 Oct 2015 12:29:40 -0200 Subject: [PATCH 8/8] fixed: cursor on/off --- src/rtlib/js/io_locate.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/rtlib/js/io_locate.c b/src/rtlib/js/io_locate.c index b6851ffcfb..68dda79360 100644 --- a/src/rtlib/js/io_locate.c +++ b/src/rtlib/js/io_locate.c @@ -5,9 +5,28 @@ int fb_ConsoleLocate( int row, int col, int cursor ) { - EM_ASM_ARGS({ - __fb_rtlib.console.pos_set($0, $1); - }, row-1, col-1); + if( row > 0 || col > 0 ) + { + EM_ASM_ARGS({ + __fb_rtlib.console.pos_set($0, $1); + }, row-1, col-1); + } + + if( cursor != -1 ) + { + if( cursor == 0 ) + { + EM_ASM({ + __fb_rtlib.console.cursor_hide(); + }); + } + else + { + EM_ASM({ + __fb_rtlib.console.cursor_show(); + }); + } + } return (col & 0xFF) | ((row & 0xFF) << 8); }