import util.table; import JSON; namespace console; enabled = true; if( _WINE ){ import console.wine; return; } getWindow = ::Kernel32.api( "GetConsoleWindow", "int()"); getOutputHandle = function(){ return topointer( ::Kernel32.GetStdHandle(-11/*_STD_OUTPUT_HANDLE*/) ); } getInputHandle = function(){ return topointer( ::Kernel32.GetStdHandle(-10/*_STD_INPUT_HANDLE*/) ); } getErrorHandle = function(){ return topointer( ::Kernel32.GetStdHandle(-12/*_STD_ERROR_HANDLE*/) ); } modifyMode = function(h,remove=0,add=0 ){ if(h===null) h = getOutputHandle(); var mode ={INT value} var _,mode = ::Kernel32.GetConsoleMode(h,mode); mode.value = ( mode.value & ~remove ) | add ; if( ::Kernel32.SetConsoleMode(h,mode.value) ) return mode; } class INPUT_RECORD{ WORD eventType; union event = { struct keyEvent = { int bKeyDown; WORD wRepeatCount; WORD wVirtualKeyCode; WORD wVirtualScanCode; union uChar = { WORD unicodeChar; BYTE asciiChar; } ; INT dwControlKeyState; isShiftPressed = function(){ return owner.dwControlKeyState & 0x10 }; isScrLkOn = function(){ return owner.dwControlKeyState & 0x40 }; isRightCtrlPressed = function(){ return owner.dwControlKeyState & 0x4 }; isRightAltPressed = function(){ return owner.dwControlKeyState & 0x1 }; isLeftCtrlPressed = function(){ return owner.dwControlKeyState & 0x8 }; isLeftAltPressed = function(){ return owner.dwControlKeyState & 0x2 }; isNumLkOn = function(){ return owner.dwControlKeyState & 0x20 }; isCapsLkOn = function(){ return owner.dwControlKeyState & 0x80 }; isEnhanced = function(){ return owner.dwControlKeyState & 0x100 }; } struct mouseEvent = { struct dwMousePosition = {word x;word y} INT dwButtonState; INT dwControlKeyState; INT dwEventFlags; } struct windowBufferSizeEvent={ struct dwSize = {word x;word y} } struct menuEvent={ INT dwCommandId; } struct focusEvent={ bool bSetFocus; } } } GetNumberOfConsoleInputEvents = ::Kernel32.api( "GetNumberOfConsoleInputEvents", "bool(pointer hIn,INT & numEvt)"); kbHit = function(){ var ret,nums = GetNumberOfConsoleInputEvents(getInputHandle(),0) return ret ? nums : 0; } peek = function(){ if(kbHit() ) return kbRead(false); } kbRead = function(wait){ var input,ke; if(!wait){ input = readInput(1,0x1/*_KEY_EVENT*/); if(#input){ return input[1].keyEvent; } } else { while( getInputHandle() ){ sleep(100); if( kbHit() ){ input = readInput(1,0x1/*_KEY_EVENT*/); if(!#input) continue; ke = input[1].keyEvent; if( ke.bKeyDown) return ke; }; } } } getKey = function(){ return kbRead(true)[["wVirtualKeyCode"]]; } ::Msvcrt := ..raw.loadDll("Msvcrt.dll",,"cdecl") getch = ::Msvcrt._getwch; getche = function(){ var c = ::Msvcrt._getwche(); c = ..string.fromUtf16(..raw.str( {WORD bytes = c },true)); return c; } getPassword = function(mask="*"){ openForWrite(); var s = {}; while( var c; c = ..string.pack( getch() ); c != '\r' ) { ..table.push(s,c); writeText(mask:c); } writeText('\n'); return ..string.join(s) } clearInputBuffer = function(){ ::Kernel32.FlushConsoleInputBuffer(getInputHandle()); } var moreLines = 1; more = function(count,cls){ count = count : 1; moreLines = moreLines % count; if(!moreLines){ pause(,langMore,"---------- More -----------"); if(cls) clearScreen(); } moreLines++; }; ::Imm32 := ..raw.loadDll("Imm32.dll") var closeInputMethod = function(){ openForWrite(); var hwnd = getWindow(); var hIme = ::Imm32.ImmGetDefaultIMEWnd(hwnd); if(hIme){ ::User32.SendMessage(hIme,0x283/*_WM_IME_CONTROL*/,6/*_IMC_SETOPENSTATUS*/,0) } } askYesNo = function(title){ closeInputMethod(); log( "[Y/N] " + (title : langYesNo) ) while( getInputHandle() && sleep(10) ){ if( kbHit() ){ var kb = kbRead(); if(!kb) continue; if(kb.bKeyDown) continue; var vk = kb.wVirtualKeyCode; if( vk == 'Y'#){ return true; } elseif( vk == 'N'#){ return false; } } } } pause = function(close,msg,erase,...){ openForWrite(); var x,y = getPos(); if(x) { writeText( '\n' ); } clearInputBuffer(); msg := langPause; writeText( msg ); var chr = kbRead(true)[["wVirtualKeyCode"]]; clearInputBuffer(); clearScreen(x,y); if(erase) { writeText(erase,...); writeText('\n'); } if(close)..io.close(); pausedOnce = true; return chr; } mapEventType2FieldName = { [0x10/*_FOCUS_EVENT*/] = "focusEvent"; [0x1/*_KEY_EVENT*/] = "keyEvent"; [0x2/*_MOUSE_EVENT*/] = "mouseEvent"; [0x8/*_MENU_EVENT*/] = "menuEvent"; [0x4/*_WINDOW_BUFFER_SIZE_EVENT*/] = "windowBufferSizeEvent"; } ReadConsoleInput = Kernel32.api( "ReadConsoleInput", "bool(pointer hIn,struct& brf,INT len,INT &Reads)"); readInput = function(len=1,eventType){ if( len < 1)return; var buf = ..raw.toarray( len,"struct","array" ); buf.array = { INPUT_RECORD() } var ok,buf,len = ReadConsoleInput( getInputHandle(),buf,len,len); if( ok && len){ var ret = {} for(k,input in buf.array){ if(input.eventType){ if( eventType && eventType!= input.eventType ) continue; var name = mapEventType2FieldName[input.eventType] if(name){ ..table.push(ret,{[name] = input.event[name];eventType=input.eventType;eventName = name } ) } } } return ret; } } _ctrlHandlerThreads = {} setCtrlHandlerThread = function(handle,add,thrdOwner){ open(); if( add || (add === null) ){ var pfunc = _ctrlHandlerThreads[handle] : ..thread.tostdcall(handle,"bool(int ctrlType)",thrdOwner); ::Kernel32.SetConsoleCtrlHandler(pfunc,true ); _ctrlHandlerThreads[handle] = pfunc; } else{ var pfunc = _ctrlHandlerThreads[handle]; if(pfunc){ ::Kernel32.SetConsoleCtrlHandler(pfunc,false ); _ctrlHandlerThreads[handle] = null; } } } ..subscribe("beforeUnload",function(){ for(k,v in _ctrlHandlerThreads){ k();} } ); isOpened = function(){ var hwnd = getWindow(); return (hwnd ? ::User32.IsWindowVisible(hwnd)); } var init; open = function(utf8){ if( utf8!== null ) self.utf8 = true; if(self.utf8!==null) ..io.utf8 = self.utf8; return ..thread.lock("std.console.open",function(){ var hwnd = getWindow(); if( ( !hwnd ) || ( !::User32.IsWindowVisible(hwnd) ) ){ ..io.open(); if(crtReopen) crtReopen(); hwnd = getWindow(); } elseif(!init){ if( ..io.utf8 && ::Kernel32.SetCurrentConsoleFontEx ){ if( ::Kernel32.GetConsoleOutputCP()!=65001 ){ ..io.open(); if(crtReopen) crtReopen(); hwnd = getWindow(); } } } if( !init ){ modifyMode( getInputHandle(),0x10/*_ENABLE_MOUSE_INPUT*/,); var ansion; if( _WIN10_LATER ){ ansion = null !== modifyMode( getOutputHandle(),,4/*ENABLE_VIRTUAL_TERMINAL_PROCESSING*/) } init = true; if( ..win[["title"]] ){ setTitle(..win[["title"]]); } } return hwnd; }) } crtReopen = function(){ var stdin = ::Msvcrt.__iob_func(0); ::Msvcrt.freopen("CONIN$", "r+t", stdin); ::Msvcrt.freopen("CONOUT$", "w+t", stdin + 32); ::Msvcrt.freopen("CONOUT$", "w+t", stdin + 64); ..publish("afterConsoleOpen"); } openForWrite = function(utf8){ if( utf8!== null ) self.utf8 = utf8; if(self.utf8!==null) ..io.utf8 = self.utf8; showLoading(false); var hwnd = open(utf8); ..console.setCursorVisible(true); return hwnd; } import thread.event; var eventLoadingStop,eventLoadingStopped; var loadingMessage,loadingDotColor,loadingDotChanged,loadingDots; var initLoading = function(){ if(eventLoadingStop) return; var PID = ::Kernel32.GetCurrentProcessId() eventLoadingStop = thread.event("(console.std.eventLoadingStop)"+PID,true); eventLoadingStopped = thread.event("(console.std.eventLoadingStopped)"+PID,true,true); loadingMessage = thread.var("(console.std.loadingMessage)"); loadingDotColor = thread.var("(console.std.loadingDotColor)"); loadingDotChanged = thread.var("(console.std.loadingDotChanged)"); loadingDots = thread.var("(console.std.loadingDots)"); if(!loadingDots.get()){ loadingDots.set({"▏";"▎";"▍";"▌";"▋";"▊";"▆";"▅";"▄";"▃";"▁";"▃";"▄";"▅";"▆";"▇";"▉";"▊";"▋";"▌";"▍";"▎"}) } } setLoadingDots = function(dots,endDots,interval){ initLoading(); if( endDots !== null ) dots.endDots = true; if( interval !== null ) dots.interval = true; loadingDots.set(dots); loadingDotChanged.set(true); } showLoading = function(msg,dotColor){ initLoading(); if(!msg) { eventLoadingStop.set() eventLoadingStopped.waitOne(1000); return; } loadingDotColor.set(type(dotColor)!=type.number ? 0xF : dotColor); loadingMessage.set(type(msg)==type.string ? msg : ""); if(!eventLoadingStopped.waitOne(100)){ return; } open(); eventLoadingStop.reset(); eventLoadingStopped.reset(); thread.invoke( function(utf8,eventLoadingStop,eventLoadingStopped,loadingMessage,loadingDots,loadingDotChanged,loadingDotColor){ ..io.utf8 = utf8; import JSON; import console; console.$isLoadingThread____ = true; var cursorVisible = console.isCursorVisible(); console.setCursorVisible(false); var outHandle = console.getOutputHandle(); var written = {INT size}; var dots = loadingDots.get(); var interval = loadingDots.interval : 120; var endDots = dots.endDots; while(!eventLoadingStop.wait(interval)){ for(i=1;#dots;1){ console.writeText('\r') if(endDots){ console.writeText(loadingMessage.get()) console.writeColorText(dots[i],loadingDotColor.get()) } else { console.writeColorText(dots[i],loadingDotColor.get()) console.writeText(loadingMessage.get()) } console.eraseToEndOfLine(); if( eventLoadingStop.wait(interval) ) break; if( loadingDotChanged.get() ){ dots = loadingDots.get(); interval = loadingDots.interval : 120; endDots = dots.endDots; loadingDotChanged.set(false); break; } } } console.eraseLine(); console.setCursorVisible(cursorVisible); eventLoadingStopped.set(); },..io.utf8,eventLoadingStop,eventLoadingStopped,loadingMessage,loadingDots,loadingDotChanged,loadingDotColor ) } fullscreen = function(){ var hwnd = open(); var s = ::User32.MapVirtualKey(0xD/*_VK_ENTER*/, 0) << 16 | 1 | 0x20000000; ::User32.PostMessage(hwnd,0x104, 0xD/*_VK_ENTER*/ ,s ); ::User32.PostMessage(hwnd,0x105 ,0xD/*_VK_ENTER*/ ,s| 0xC0000000); } getText = function(s,len){ openForWrite(); if( s ) writeText( s ); return ..io.getText(len) ; } read = getText; writeText = function(s,...){ pausedOnce = null if(! $isLoadingThread____ ){ showLoading(false); } var written = {INT size}; s = s!==null? tostring(s) : ""; if( (!..string.isUtf8(s)) && (!..string.isUtf16(s)) ){ ..string.setUtf(s,1); } s = ..string.toUtf16(s); if( ::Kernel32.WriteConsoleB( ::Kernel32.GetStdHandle(-11/*_STD_OUTPUT_HANDLE*/), s,#s/2,written,null) ) { if(!#{...}) return written.size; return writeText(...); } else { var e,c = ..lasterr(); if( c == 0x8/*_ERROR_NOT_ENOUGH_MEMORY*/){ return ..io.print(s,...)); } } } write = function(...){ if(!enabled) return; openForWrite(); return writeText(...); } print = function(...){ if(!enabled) return; openForWrite(); var args = {...}; var output = {}; for(i,v in ..table.eachArgs(args) ){ if(i>1)writeText('\t'); writeText(..table.isArray(v)?..table.tostring(v):tostring(v)); } writeText('\n'); } log = print; logPause = function(...){ if(!enabled) return; log(...); pause(); } printf = function(s,...){ if(!enabled) return; if( ...!== null ) s = ..string.format(s,... ) log( s ) } hex = function(s){ print( ..string.hex(s," ") ) } writeBack = function( s,... ){ if( ... !== null ) s = ..string.format(s,... ); writeText( ..string.repeat(#(..string.fromto(s,,::Kernel32.GetConsoleOutputCP())),'\b') ); writeText( s ); } self.error = function(x,...){ if(x===null && ... === null) return; if( _STUDIO_INVOKED ) openForWrite(); if( isOpened() ) setTextAttribute( color.red ); if( _STUDIO_INVOKED ) { global.import("debug"); stderr.write( ..debug.traceback(,"console.error",2),'\n\t-----------------------------------------------'); } var args = {x,...} for(i,v in args){ args[i] = type(v)=="table"?..table.tostring(v):tostring(v); } var r = stderr.write('\n',..string.join(args,'\t'),'\n\n'); if( isOpened() ) setTextAttribute(); } errorPause = function(...){ if(...){ openForWrite(); self.error(...); pause(); } } self.assert = function(exp,msg,...){ if(!exp) { self.error(msg,...); pause(); error(null); } return exp; } class CONSOLE_SCREEN_BUFFER_INFO { struct size = {word x;word y}; struct cursorPosition = {word x;word y}; WORD attributes; struct srWindow = {word left;word top;word right;word bottom}; struct maximumWindowSize = {word x;word y}; } clearScreen = function(x,y){ showLoading(false); x = x:0; y = y:0; var offset = x*y; var coord = ::MAKELONG(x,y); var csbi = CONSOLE_SCREEN_BUFFER_INFO(); var hConsole = getOutputHandle(); ::Kernel32.GetConsoleScreenBufferInfo(hConsole,csbi) var size = csbi.size.x * csbi.size.y; var cCharsWritten = { INT cChars = 0} ::Kernel32.FillConsoleOutputCharacter(hConsole,' '#, size-offset,coord, cCharsWritten ); ::Kernel32.GetConsoleScreenBufferInfo(hConsole,csbi); ::Kernel32.FillConsoleOutputAttribute(hConsole, csbi.wAttributes,size-offset,coord, cCharsWritten); ::Kernel32.SetConsoleCursorPosition(hConsole, coord); ::Kernel32.SetConsoleTextAttribute(getOutputHandle(),15); } cls = clearScreen; eraseToEndOfLine = function(){ var x,y = getPos(); var width = getSize(); if(!width) return; var line = ..string.toUtf16(..string.repeat(width-y," ") ); ::Kernel32.WriteConsoleW(getOutputHandle(),line,#line/2,{INT size},null); setPos(x,y); } eraseLine = function(...){ var x,y = getPos(); setPos(0,y); eraseToEndOfLine(...); if(#{...}) writeText(...); } getScreenBufferInfo = function(x,y){ var csbi = CONSOLE_SCREEN_BUFFER_INFO(); if( ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi) ) return csbi; } getCursorInfo = function(){ var hConsole = getOutputHandle(); var info = {INT size; bool visible}; ::Kernel32.GetConsoleCursorInfo(hConsole,info); return info; } setCursorInfo = function(newInfo){ var hConsole = getOutputHandle(); var info = {INT size; bool visible}; ::Kernel32.GetConsoleCursorInfo(hConsole,info); ..table.assign(info,newInfo); ::Kernel32.SetConsoleCursorInfo(hConsole,info); } isCursorVisible = function(visible){ return getCursorInfo()[["visible"]]; } setCursorVisible = function(visible){ setCursorInfo(visible=visible); } getSize = function(){ var csbi = CONSOLE_SCREEN_BUFFER_INFO(); if( ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi) ) return csbi.size.x,csbi.size.y; } getPos = function(){ open(); var csbi = CONSOLE_SCREEN_BUFFER_INFO(); if( ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi) ) return csbi.cursorPosition.x,csbi.cursorPosition.y; } setPos = function(x,y){ open(); var x2,y2 = getPos(); if( x === null ) x = x2; if( y === null ) y = y2; return !!::Kernel32.SetConsoleCursorPosition( getOutputHandle(),::MAKELONG(x,y) ) } getTextAttribute = function(){ var csbi = CONSOLE_SCREEN_BUFFER_INFO(); if( ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi) ) return csbi.attributes; } setTextAttribute = function(fore,back){ open(); if(fore)fore = color[[fore]] || fore; if(back)back = color[[back]] || back; if(fore===null) fore = 0xF; if( type(fore) != type.number ) error("参数必须是数值",2) if( type(back) == type.number ) fore = back * 0x10 + fore; return ::Kernel32.SetConsoleTextAttribute(getOutputHandle(),fore); } setTextColor = setTextAttribute; //设整整个窗口颜色,设置局部颜色用 setTextAttribute 或 writeColorText setColor = function(fore,back){ if(fore)fore = color[[fore]] || fore; if(back)back = color[[back]] || back; execute("color " + ..string.format("%x%x",back:0, fore:0xF)) } writeColorText = function(txt,fore,back){ var a = getTextAttribute(); setTextAttribute(fore,back); writeText(txt); setTextAttribute(a); } box = function(x,y,x2,y2,clr,title){ openForWrite(); var csbi = CONSOLE_SCREEN_BUFFER_INFO(); ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi); if(!x) { x = ..math.floor( ( csbi.srWindow.right - csbi.srWindow.left - x2 ) / 2 ); x2 = x + x2; } if(!y) { y = ..math.floor( ( csbi.srWindow.bottom - csbi.srWindow.top - y2 ) / 2 ); y2 = y + y2; } x2 = x2 + ( 2 -( ( x2 - x ) % 2 ) ) if(clr===null) return x,y,x2,y2; setTextAttribute(clr); for(y=y;y2;1){ for(x=x;x2-1){ setPos(x,y);writeText(" "); } } if( title ){ title = title; setPos(x,y);writeText("┌") setPos(x2-2,y);writeText("┐") setPos(x,y2);writeText("└") setPos(x2-2,y2);writeText("┘") for (i=x+2;x2-4;2){ setPos(i,y);writeText("─"); setPos(i,y2);writeText("─"); } for (i=y+1;y2-1){ setPos(x,i);writeText("│"); setPos(x2-2,i);writeText("│"); } setPos(x+4,y);writeText(title); setPos(x+4,y+2); } else { setPos(x+2,y+1); } return x,y,x2,y2; } readOutputCharacter = function(size){ if(size===null){ var csbi = CONSOLE_SCREEN_BUFFER_INFO(); ::Kernel32.GetConsoleScreenBufferInfo(getOutputHandle(),csbi) size = csbi.size.x * csbi.size.y; } var buffer = ..raw.toarray(size:1000,"WORD","value"); buffer.value = null; var ok = ::Kernel32.ReadConsoleOutputCharacterW( getOutputHandle(),buffer,size:1000,0,{INT charsRead}) return ..string.trim(buffer.value); } dump = function(v,...){ if(!enabled) return; openForWrite(); if( type(v) == "table" ) { if(v[["$jvmInstancePtr"]]){ writeText("java.object("+ tostring(v.getClass()) +'):\n',tostring(v)) writeText('\n'); if(...)log(...); return; } elseif(v[["$jvmClassPtr"]]){ writeText('java.',tostring(v),'\n') if(...)log(...); return; } if(..com ){ if(v[["_dotNetObject"]]){ writeText("dotNet.object:",..com.DumpTypeInfo(v[["_dotNetObject"]])) var u = v[["_dotNetObject"]].Value; if((u!==null) && (!u@) || ..table.isArray(u)){ log(u); } } elseif( ..com.IsObject(v)){ if(...){ var t = ..com.GetTypeInfo(v); var tl = t ? t.GetTypeLib(); var e = tl ? tl.ExportEnumerations(); if(e && e[...]){ dumpTable(e[...]); } return; } writeText( ..com.DumpTypeInfo(v) ) } else { writeText( ..table.tostring(v)) } } else { writeText( ..table.tostring(v)) } } if(type(v)==="number" || ..math.isSize64(v)){ writeText( (..math.stringify(v) ) ) } else { writeText( (tostring(v) ) ) } var a,b,c = ...; if(a===null && b===null && c===null){ writeText('\n'); return; } writeText('\t') return dump(...); } dumpTable = function(t){ if(!enabled) return; openForWrite(); if(type.isString(t)){ var s = t; t = {}; if(..string.isUtf16(s)){ for(i=1;#s/2;1){ t[i] = s[i] } } else { for(i=1;#s;1){ t[i] = s[i] } } } elseif(type(t)!=="table"){ self.error("参数不是一个 table 对象"); return; } writeText( ..util.table.stringify(t," ") ,'\n') } dumpFile = function(path){ if(!enabled) return; log( ..string.load(path) ); } setTitle = function(title){ open(); return !!::Kernel32.SetConsoleTitleW(title); } GetConsoleTitle = ::Kernel32.api( "GetConsoleTitleW", "INT(ustring& buf,INT size)"); getTitle = function(){ var len,title = GetConsoleTitle(2000,1000); return title; } getNumber = function( s,min,max ){ closeInputMethod(); var n; while( var _; n = tonumber( getText(s,30),10 ); ( (n === null) || (min!==null && n < min ) || (max!==null && n > max ) ) ) { s = langInvalidNumber; } return n; } getCodePage = function(){ return ::Kernel32.GetConsoleCP(),::Kernel32.GetConsoleOutputCP() } setCodePage = function(icp,ocp){ return ::Kernel32.SetConsoleCP(icp) && ( ocp === null || ::Kernel32.SetConsoleOutputCP(ocp) ); } dumpJson = function(v){ if(!enabled) return; log( ..JSON.stringify(v,true,false) ); } close = function(){ showLoading(false); ..io.close(); } stdout = ..io.stdout; stderr = ..io.stderr; stdin = ..io.stdin; varDump = function(...){ if(!enabled) return; openForWrite(); var args = {...}; var b,e = ..table.range(args); for(i=b;e){ var arg = args[i]; var t = type(arg); print("参数位置:" ++ i); print("数据类型:" ++ t); if( t != type.table ){ print("变量值:" ++ tostring(arg),'\n'); } else { print("变量值: {" ); var logged = { _struct = 1 }; for k,v in ..table.eachName(arg){ logged[k] = true; writeText(' ', k,' = ',tostring(v) ,'\n'); } for(i=1;#arg;1){ logged[i] = true; writeText(' [', i,'] = ',tostring(arg[i]) ,'\n'); } for(k,v in arg){ if( !logged[k] ){ writeText(' [', tostring(k),'] = ',tostring(v) ,'\n'); } } print('}'); if(#arg){ print("序列数组长度:",#arg); } if(arg[["_struct"]]){ try{ print("结构体大小:",..raw.sizeof(arg) ); } catch(e){ print("结构体大小:未知(包含动态数组)"); } } print('\n'); } } } color = { /*intellisense(console.color)*/ black = 0; //黑色 darkBlue = 1; //暗蓝色 darkGreen = 2; //暗绿色 darkCyan = 3; //暗青色 darkRed = 4; //暗红色 darkMagenta = 5; //暗紫色 darkYellow = 6; //暗黄色 gray = 7; //灰色 darkGray = 8; //深灰色 blue = 9; //蓝色 green = 0xA; //绿色 cyan = 0xB; //青色 red = 0xC; //红色 magenta = 0xD; //紫色 yellow = 0xE; //黄色 white = 0xF //白色 /*end intellisense*/ } colors = color; choice2 = function(items,color){ if(type(items)!="table" || !#items) error("参数必须是非空数组!"); if(!color) color = 0xA; var sel,oldSel = 1; var col,row = getPos(); var count = #items; while(getInputHandle() && sleep(10)){ if(oldSel!=sel){ clearScreen(col,row) for(i=1;count){ if(i == sel){ writeColorText("["+i+"] " + items[i],0xA); } else { writeText("["+i+"] " + items[i]+" "); } writeText('\n'); } oldSel = sel; } var key = getKey(); if(key == 0x26/*UP*/ || key == 0x25/*_VK_LEFT*/){ sel = sel > 1 ? sel - 1 : count; } elseif(key == 0x28/*DOWN*/ || key == 0x27/*_VK_RIGHT*/){ sel = sel < count ? sel + 1 : 1; } elseif(key == 0xD/*ENTER*/){ return sel,items[sel]; } elseif(key==0x1B/*_VK_ESC*/){ clearScreen(col,row) return; } } } choice = function(items,title){ if(type(items)!="table" || !#items) error("参数必须是非空数组!"); var col,row = getPos(); for(i=1;#items){ writeText("["+i+"] " + items[i]+" "); writeText('\n'); } var n = getNumber(title || langChoice,1,#items) clearScreen(col,row) if(n) return n,items[n]; } repeat = function(r,s){ if( type(r) === "string" ) s,r = r,s; log( ..string.repeat(r,s) ); } begin var lcid = ::Kernel32.GetUserDefaultLangID(); if( lcid==0x404/*zh-TW*/ || lcid == 0x0C04/*zh-HK*/ || lcid == 0x1404/*zh-MO*/ ){ langMore = "--- 請按任意鍵顯示更多 ---"; langPause = "請按任意鍵繼續 ... "; langYesNo = "按 Y 鍵繼續,按 N 鍵取消"; langInvalidNumber = "請重新輸入有效的數值: "; langChoice = "請輸入選項對應的數字: " } elseif( lcid==0x804/*zh-CN*/ || lcid!==0x1004/*zh-SG*/ ){ langMore = "--- 请按任意键显示更多 ---"; langPause = "请按任意键继续 ... "; langYesNo = "按 Y 键继续,按 N 键取消"; langInvalidNumber = "请重新输入有效的数值: "; langChoice = "请输入选项对应的数字: " } elseif( lcid==0x411/*ja-JP*/ ){ langMore = "--- 続きを読むには任意のキーを押してください ---"; langPause = "続行するには任意のキーを押してください... "; langYesNo = "続行しますか?"; langInvalidNumber = "有効な数値を入力してください。"; langChoice = "選択肢の番号を入力してください: "; } elseif( lcid==0x412/*ko-KR*/ ){ langMore = "--- 계속 읽으려면 아무 키나 누르세요 ---"; langPause = "계속하려면 아무 키나 누르세요... "; langYesNo = "계속하시겠습니까?"; langInvalidNumber = "유효한 숫자를 입력하세요."; langChoice = "선택 번호를 입력하세요: "; } elseif( lcid==0x419/*ru-RU*/ ){ langMore = "--- Нажмите любую клавишу, чтобы прочитать дальше ---"; langPause = "Нажмите любую клавишу, чтобы продолжить... "; langYesNo = "Продолжить?"; langInvalidNumber = "Пожалуйста, введите действительное число."; langChoice = "Введите номер выбора: "; } elseif( lcid==0x101E/*th-TH*/ ){ langMore = "--- กดปุ่มใดๆ เพื่ออ่านต่อ ---"; langPause = "กดปุ่มใดๆ เพื่อดำเนินการต่อ... "; langYesNo = "ต้องการดำเนินการต่อหรือไม่?"; langInvalidNumber = "กรุณาป้อนตัวเลขที่ถูกต้อง."; langChoice = "ป้อนหมายเลขทางเลือกของคุณ: "; } else { langMore = "--- Press any key to read more ---"; langPause = "Press any key to continue . . ."; langYesNo = "Do you want to continue?"; langInvalidNumber = "Please enter a valid number."; langChoice = "Enter your choice:"; } end; //@Deprecated debug = self.error; /**intellisense(console) enabled = 是否在当前线程禁用 console 库以下输出函数:\nlog,print,dump,dumpJson,dumpTable,varDump \n\n不会禁用 console.writeText,console.writeColorText 等基础输出函数。\n不会禁用 io.print, io.stdout.write,io.stderr.write 等基础输出函数。\n不会禁用 console.error, console.assert 等输出错误信息的函数。\n不会禁用 console.open, console.pause, console.getText 等交互类函数。 isOpened() = 是否已显示控制台窗口。 open() = 打开控制台窗口,\n如果控制台窗口已打开,该函数不进行任何操作,\n如果参数为 true 则将 console.utf8 设为true,\n请参考 console.utf8 的说明\n\n此函数重定向 msvcrt.dll 定义的 stdin,stdout,stderr 到控制台 utf8 = 控制台是否启用UTF-8编码,\n所有线程设置必须相同,否则会导致重新打开控制台,\n如果操作系统为英文环境,控制台启用 UTF-8 可正常显示中文,\n此值为 null(默认值) 时由 aardio 自动选择编码( Win10 1709 以及之后的系统默认开启 UTF-8),\n启用这个选项在 WIN10 以下系统可能出现显示不正常的问题。 setLoadingDots(.(动画字符数组,是否显示在尾部,动画间隔毫秒数) = 指定showLoading函数使用的默认动画字符数组\n除参数@1必须指定之外,其他参数可选 showLoading( = 显示进度动画 showLoading(.(状态提示文本,动画颜色) = 所有参数都可以省略,状态文本参数为 false 关闭动画,\n调用 console 库的其他函数基本都会自动停止动画。\n参数 @2 只能使用 console.color 的成员值。 getNumber( "请输入数值:__" ) = 读取用户输入的数值,\n如果用户输入错误的数值则显示错误提示并重新读取输入直到成功。\n可选用参数@2限定最小有效数值。\n可选用参数 @3 限定最大有效数值。 getText( "请输入文本:__" ) = 此函数内部调用 io.getText 自控制台读取用户输入,\n可选在参数 @2 中指定指定接收文本的缓冲区大小。\n此函数不调用 io.stdin.read 等标准输入函数,而是直接自控制台读取文本。 read(.(title,length) = 此函数为 console.getText 函数的别名。\n可选用参数 title 指定输入提示,可选用参数 @length 指定接收文本的缓冲区大小。 writeText(__) = 直接写入控制台,\n参数支持 UTF8 / UTF16 / ANSI 编码的字符串,\n支持 1 个或多个参数,但遇到null参数会停止输出后面的参数,\n注意这个函数不会自动打开控制台,\n此函数不调用io.stdout.write,io.print等标准输出函数\n并且可以支持更多的Unicode字符 writeColorText( = 调用 console.writeText 输出指定颜色文本,\n此函数不会自动打开控制台窗口 writeColorText(.(文本,文本颜色,背景色) = 颜色颜色参数可指定 console.color 命名空间的颜色数值或颜色名称(字符串值)。\n示例:`console.writeColorText("文本","red","darkBlue")` \n背景色可以省略 write(__) = 调用 console.writeText 在控制台输出信息,支持多参数。\n与 console.writeText 不同, console.write 可自动打开控制台而无需先调用 console.open 。\n与 console.writeText 不同, console.write 不会在参数间添加制表符,也不会在尾部添加换行。 log(__) = 调用 console.writeText 在控制台输出信息,支持多参数。\n参数为纯数组则序列化并输出值,其他参数调用 tostring 转为字符串输出。\n多个参数间输出时用制表符分隔,并且在最后输入一个换行。\n此函数必须先导入 console 库才能使用。\n\n参数支持 UTF8/UTF16/ANSI 字符串,\n二进制或非 UTF8 或系统 ANSI 编码的字符串请改用 console.hex 函数。\n\n该函数可自动打开控制台窗口,而无需事先调用 console.open 。\n注意 console.log 与 console.print 指向同一函数。\n如果是输出错误信息,请改用 console.error 函数。 logPause(__) = 调用 console.log 函数输入所有参数,\n然后调用 console.pause 函数暂停 print("__") = 调用 console.writeText 在控制台输出信息,支持多参数。\n参数为纯数组则序列化并输出值,其他参数调用 tostring 转为字符串输出。\n多个参数间使用制表符分隔,并且在最后输入一个换行,\n参数支持 UTF8/UTF16/ANSI 字符串,\n该函数可自动打开控制台窗口;\n注意 console.log 与 console.print 指向同一函数\n如果是输出调试信息,建议大家使用 console.error 函数 printf("%s__", ) = 自动打开控制台,\n并调用 console.log 函数输出格式化字符串,\n格式化语法与string.format相同 hex(__) = 调用console.log以16进制输出字符串、或缓冲区的所有字节码,\n也可以使用 console.dumpTable 函数将字符串或 buffer 转换为字节码数组输出 writeBack(__) = 控制台输出字符串并覆盖最后显示的等长字符\n如果有多个参数则调用string.format格式化后输出 repeat(.(repCount,repStr) = 将字符串 repStr 重复 repCount 次后输出 fullscreen() = 控制台窗口全屏切换 modifyMode(.(输入输出句柄,移除模式,添加模式) = 设置控制台的显示模式\n参数用法参考 WINAPI SetConsoleMode\n参数@1如果省略则默认为标准输出句柄\n成功返回当前模式,失败返回null error(__/*错误信息或对象*/) = 使用标准错误输出流(io.stderr)输出,可以重定向,\n可添加任意个参数,所有参数也转换为字符串以后输出。\n如果参数是表对象,则调用 table.tostring 序列化后输出。\n如果不指定参数 @1 (null值)则直接忽略本次调用(不输出任何参数)。\n\n在开发环境中会自动打开控制台以红色字体输出参数,并输出当前调用栈信息。\n发布后的程序不会自动打开控制台,不会输出调用栈信息。 assert(.(condition,errorMessage) = 控制台断言函数。\n如果 @condition 不为真则在控制台打印错误信息 errorMessage 并暂停等待按键,\n用户按键后抛出空异常(可被捕获但默认没有报错对话框)。 errorPause(__/*错误信息或对象*/) = 自动打开控制台窗口,调用 console.error 输出错误信息(或表对象的值),\n之后暂停等待按键。\n\n支持任意个参数,参数用法请参考 console.error 。 more( = 等待并在按任意键以后继续,用于在控制台分页输出时等待按键。 more(.(分页大小,是否清屏) = 略参数 @1 则参数默认为 1 。\n如果参数 @2 为true,按任意键以后清除控制台已显示的内容。 askYesNo("按 Y 键继续,按 N 键取消") = 等待用户按 Y 或 N 键 choice2(.(items,color) = 显示菜单。\n参数 @1 必须指定非空数组。\n参数 @2 可选用 console.color 命名空间的颜色值指定选中项颜色。\n按方向键选择项目,回车键确认选项,ESC 键取消。 choice2(.(items,title) = 显示菜单。。\n参数 @1 必须指定非空数组。\n参数 @2 可选用一个字符串自定义输入提示。 kbHit() = 检测键盘有没有输入 peek() = 测试键盘有没有输入\n有则读取并返回keyEvent对象,否则返回空\n!console_kbevent. clearInputBuffer() = 刷新控制台输入缓冲区\n丢弃缓冲区的所有输入 getKey() = 等待并读取控制台按键,并返回虚拟键码。\n程序退出或控制台关闭返回 null 。 kbRead() = 读取用户按键返回keyEvent对象\n!console_kbevent. kbRead(true) = 等待用户按任意键并返回keyEvent对象(不包含释放按键事件) getch() = 读取输入字节码,中文字返回两个字节码\n控制台不回显字符 getche() = 读取输入字符\n控制台回显字符 getPassword() = 读取密码\n可选使用参数一指定控制台回显掩码,默认显示星号 getWindow() = 返回控制台窗口句柄\n使用此函数可判断当前是否已打开控制台窗口; getOutputHandle() = 标准输出句柄 getInputHandle() = 标准输入句柄 getErrorHandle() = 错误输出句柄 getCodePage() = 获取输入代码页,输出代码页 setCodePage(.(输入代码页,输出代码页) = 设置代码页\n可在打开控制台后使用该函数修改输入输入代码页 readOutputCharacter() = 读取标准输出缓冲区文本。\n可选用参数 @1 指定要读取的缓冲区大小,\n如果不指定则自动获取缓冲区长度 setColor(.(文本颜色,背景色) = 设置控制台文本颜色与背景色。\n颜色颜色参数可指定 console.color 命名空间的颜色数值或颜色名称(字符串值)。\n示例:`console.setColor("red","darkBlue")`\n无参数恢复默认颜色 getTextAttribute() = 获取控制台文本颜色,\n返回颜色值为 背景色 * 0x10 + 文本颜色 setTextAttribute( = 设置文本颜色与背景色,\n设置整个窗口的背景色请使用 console.setColor; setTextAttribute(.(颜色) = 颜色值可以设为 背景色 * 0x10 + 文本颜色,\n也可直接使用 console.color 的成员值 (数值)或名称(字符串值)作为参数 setTextAttribute(.(文本颜色,背景色) = 颜色参数可指定 console.color 命名空间的颜色数值或颜色名称(字符串值)。\n无参数恢复默认颜色 setTextColor(.(文本颜色,背景色) = 设置文本颜色,此函数为 setTextAttribute 函数的别名。\n颜色参数可指定 console.color 命名空间的颜色数值或颜色名称(字符串值)。\n示例:`console.setTextColor("red","darkBlue")`\n无参数恢复默认颜色 isCursorVisible() =控制台当前是否显示光标 setCursorVisible(.(visible) = 设置控制台是否显示光标 setCursorInfo(.(info) = 修改光标信息,\n用法请参考此函数源码 getCursorInfo() = 返回光标信息,\n用法请参考此函数源码 varDump(__/*变量*/) = 此函数显示一个或多个参数的类型与值 dump( = 显示变量的值,支持多参数 dump(.(value,->->->) = 在控制台显示普通 table,string,number 等类型的值。\ntable 对象使用 table.tostring 转换为文本后输出。\ntable 的成员函数显示为 null,改用 console.varDump 可查看成员函数地址。 dump(.(comObj) = 参数 @1 指定 COM 对象,且无其他参数,\n则在控制台输出调用 com.DumpTypeInfo 函数返回的类型信息。\n调用 com.tlbDoc.dump 函数可打印 COM 对象更详细的类型库信息 dump(.(comObj,enumType) = 参数 @1 指定 COM 对象,参数 @2 指定枚举类型名,\n在控制台输出该枚举类型的所有名值对。\n\n通常枚举名值对也是 COM 常量名值对,\n可以使用列举的枚举名字(不用指定枚举类型名)\n作为 COM 对象的成员名获取枚举值 dumpJson(__/*变量*/) = 将对像转换为格式化的 JSON 文本并输出到控制台\n对象如果包含数值索引自1开始的顺序数组成员则转换为 JSON 数组\nJSON 数组会忽略其他索引不在数组范围内的成员 dumpTable(__/*表对象*/) = 如果参数 @1 传入字符串或 buffer,转换为字节码数组再输出。\n\n如果参数 @1 传入表参数,\n使用 ..util.table.stringify 函数格式化为文本然后输出到控制台。\n仅转换表包含的文本、数值、布尔值、嵌套表对象,\n小数精度最大为 6 位、并自动清除小数尾部多余的 0,\n如果表定义了 tostring 元方法、则转换为字符串\n忽略其他类型,忽略循环引用的表\n如果输出表的数组成员,则忽略非数组成员。\n\nconsole.dumpTable 输出时对表的信息进行了精简,没输出的数据不是丢了。\nconsole.dump, console.varDump 输出的信息更全,但也不是所有对象都能打印出来 dumpFile(__/*文件路径*/) = 输出参数 @1 指定文件路径的文件内容 close() = 关闭控制台 pause( = 暂停,\n按任意键继续 pause(.(按键后是否关闭控制台,提示) = 返回用户按键键码 pausedOnce = 如果执行了 console.pause 函数并且在之后没有执行过 console 库输出函数则返回 true。\n执行 console.log, console.dump, console.writeText 等输出函数会将 pausedOnce 属性设为 null 。\n\n此属性由 console 库自动维护,调用代码不应修改些属性。 setTitle("__") = 设置控制台标题,\n此函数会打开控制台窗口 getTitle() = 获取控制台标题 clearScreen( = 清屏 clearScreen(.(列号,行号) = 可选指定清屏的开始位置。\n开始位置之前的输出保持不变,\n仅清除指定位置以后的输出。\n不指定参数则清除所有输入。\n\n使用 console.getPos 函数可以获取当前位置(行号,列号)。 eraseLine() = 清除当前行\n可选指定要在当前行输出的一个或多个参数 eraseToEndOfLine() = 清除当前输入光标到行尾的所有字符\n注意用‘\r’虽然能回退光标到行首,但并不擦除已输出的字符 getScreenBufferInfo() = 返回屏幕缓冲区信息 getSize() = 返回控制台屏幕缓冲区每行可输入的字符数,\n以及可输入的字符行数 getPos() = 返回光标坐标 setPos(.(列,行)= 设置光标坐标 box(.(列,行,终止列,终止行,背景色,边框标题) = 在控制台画一个色块,边框标题可省略,\n参数@1,@2省略则自动居中\n返回列,行,终止列,终止行 stderr = 标准错误输出\n!ioFile. stdin = 标准输入\n!ioFile. stdout = 标准输出\n!ioFile. setCtrlHandlerThread(hander,add,owner) = @.setCtrlHandlerThread( function(ctrlType){\n __/*控制台程序退出前是否触发 @hander 参数指定的线程函数,\n@add 为 true 添加触发函数,为 false 移除,默认值为 true。\n可选用 @owner 指定线程函数的 owner 参数。\n\n使用前请先阅读多线程入门教程,了解线程函数基本规则。\n\nctrlType 为 null 表示控制台正常关闭,不可取消。\nctrlType 为 0 表示按下 Ctrl+ C。\nctrlType 为 1 表示按下 Ctrl + Break。\nctrlType 为 0 或 1 时返回 true 可阻止控制台退出\n\n在此函数内不应再使用任何控制台函数*/\n}); end intellisense**/ /**intellisense() console = 控制台扩展函数库\nWin10 以上系统控制台支持以下快捷键:\n Alt + Enter 切换全屏\nCtrl + Shift + 加号/减号 调整透明度 afterConsoleOpen = @ if(::Kernel32.GetConsoleWindow()){\n \n }\n ..subscribe("afterConsoleOpen",function(){\n __/*console 库打开控制台执行此回调*/\n} ); !console_kbevent.bKeyDown = 按键是否释放 !console_kbevent.wRepeatCount = 重复次数 !console_kbevent.wVirtualKeyCode = 虚拟键码 !console_kbevent.wVirtualScanCode = 扫描码 !console_kbevent.uChar.unicodeChar = Unicode字节码 !console_kbevent.uChar.asciiChar = ASCII字节码 !console_kbevent.uChar.dwControlKeyState = 控制键状态码 !console_kbevent.isShiftPressed = 是否按下SHIFT键 !console_kbevent.isScrLkOn = 是否打开ScrLk键 !console_kbevent.isRightCtrlPressed = 是否按下右CTRL键 !console_kbevent.isRightAltPressed = 是否按下右ALT键 !console_kbevent.isLeftCtrlPressed = 是否按下左CTRL键 !console_kbevent.isLeftAltPressed = 是否按下左ALT键 !console_kbevent.isNumLkOn = 是否打开NumLk键 !console_kbevent.isCapsLkOn = 是否打开大写 !console_kbevent.isEnhanced = 是否扩展键 end intellisense**/