private static void AddStr(int y, int x, string str) { if (x >= 0 && x < NCurses.Columns && y >= 0 && y < NCurses.Lines) { NCurses.MoveAddString(y, x, str); } }
private void Update() { NCurses.GetChar(); UpdateSnakeDirection(NCurses.GetChar()); CheckEatApple(); CheckSnakeOutOfBounds(); }
static void Main(string[] args) { short[] colorMap = new short[] { 1, 2 }; IntPtr screen = default; NCursesDisplay display = null; IChip8Device device = null; Func <bool>[] initializers = { () => InitializeNCurses(ref screen, colorMap, DefaultWidth, DefaultHeight), () => InitializeDisplayBuffer(ref display, screen, colorMap), () => BuildDevice(ref device, display.Buffer), () => LoadProgram(device, "program") }; try { if (initializers.All(p => p())) { Run(device, display); } } catch (Exception e) { Console.Error.WriteLine($"Caught an exception: {e.Message}"); } NCurses.EndWin(); }
private static bool InitializeNCurses(ref IntPtr screen, short[] colorMap, Byte width, Byte height) { screen = NCurses.InitScreen(); if (NCurses.HasColors() == false) { Console.WriteLine("Your terminal doesn't support colored output."); NCurses.EndWin(); return(false); } if ((NCurses.Columns < width - 1) || (NCurses.Lines < height - 1)) { Console.WriteLine($"Your terminal must be {width}x{height}. You have {NCurses.Columns}x{NCurses.Lines}"); NCurses.EndWin(); return(false); } NCurses.NoDelay(screen, true); NCurses.NoEcho(); NCurses.AttributeSet(CursesAttribute.NORMAL); NCurses.StartColor(); NCurses.InitPair(colorMap[0], CursesColor.BLACK, CursesColor.BLACK); NCurses.InitPair(colorMap[1], CursesColor.WHITE, CursesColor.WHITE); return(true); }
private void RenderSnake() { foreach (var coord in snake.Coordinates) { NCurses.MoveAddChar(coord.Y + 1, coord.X + 1, Snake.SYMBOL_BODY); } NCurses.MoveAddChar(snake.Coordinates.First.Value.Y + 1, snake.Coordinates.First.Value.X + 1, Snake.SYMBOL_HEAD); }
private void Move(int x, int y) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { NCurses.Move(y, x); } else { Console.SetCursorPosition(x, y); } }
private void AutoResize() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { NCurses.ResizeTerminal(Width < NCurses.Columns ? NCurses.Columns : Width, NCurses.Lines); } else { Console.SetBufferSize(Width < Console.BufferWidth ? Console.BufferWidth : Width, Console.BufferHeight); } }
internal void SetCursorPosition(Point position) { if (!usingLinux) { Win32.SetConsoleCursorPosition(stdOutputHandle, new COORD((short)position.x, (short)position.y)); } else { NCurses.move(position.y, position.x); NCurses.refresh(); } }
private void Render() { NCurses.Clear(); NCurses.NoDelay(screen, true); RenderBorders(); RenderSnake(); RenderApple(); RenderScore(); NCurses.Refresh(); }
private static void Fireworks() { NCurses.NoDelay(Screen, true); NCurses.NoEcho(); if (NCurses.HasColors()) { NCurses.StartColor(); for (short i = 1; i < 8; i++) { NCurses.InitPair(i, color_table[i], CursesColor.BLACK); } } int flag = 0; while (NCurses.GetChar() == -1) { int start, end, row, diff, direction; do { start = rng.Next(NCurses.Columns - 3); end = rng.Next(NCurses.Columns - 3); start = (start < 2) ? 2 : start; end = (end < 2) ? 2 : end; direction = (start > end) ? -1 : 1; diff = Math.Abs(start - end); } while (diff < 2 || diff >= NCurses.Lines - 2); NCurses.AttributeSet(CursesAttribute.NORMAL); for (row = 1; row < diff; ++row) { NCurses.MoveAddString(NCurses.Lines - row, row * direction + start, (direction < 0) ? "\\" : "/"); if (flag++ > 0) { MyRefresh(); NCurses.Erase(); flag = 0; } } if (flag++ > 0) { MyRefresh(); flag = 0; } Explode(NCurses.Lines - row, diff * direction + start); NCurses.Erase(); MyRefresh(); } }
public Game(Size size, int baseSnakeSize = 4) { this.size = size; random = new Random(); snake = new Snake(new Point(size.Height / 2, size.Width / 2), baseSnakeSize); GenerateNewApple(); PlayerScore = 0; isGameOver = false; screen = NCurses.InitScreen(); NCurses.NoEcho(); }
private void RenderBorders() { for (int i = 0; i < size.Width + 2; i++) { NCurses.MoveAddChar(0, i, SYMBOL_BORDER_HORIZONTAL); NCurses.MoveAddChar(size.Height + 1, i, SYMBOL_BORDER_HORIZONTAL); } for (int i = 0; i < size.Height; i++) { NCurses.MoveAddChar(i + 1, 0, SYMBOL_BORDER_VERTICAL); NCurses.MoveAddChar(i + 1, size.Width + 1, SYMBOL_BORDER_VERTICAL); } }
private static void Explode(int row, int col) { NCurses.Erase(); AddStr(row, col, "-"); MyRefresh(); col--; GetColor(); AddStr(row - 1, col, " - "); AddStr(row, col, "-+-"); AddStr(row + 1, col, " - "); MyRefresh(); col--; GetColor(); AddStr(row - 2, col, " --- "); AddStr(row - 1, col, "-+++-"); AddStr(row, col, "-+#+-"); AddStr(row + 1, col, "-+++-"); AddStr(row + 2, col, " --- "); MyRefresh(); GetColor(); AddStr(row - 2, col, " +++ "); AddStr(row - 1, col, "++#++"); AddStr(row, col, "+# #+"); AddStr(row + 1, col, "++#++"); AddStr(row + 2, col, " +++ "); MyRefresh(); GetColor(); AddStr(row - 2, col, " # "); AddStr(row - 1, col, "## ##"); AddStr(row, col, "# #"); AddStr(row + 1, col, "## ##"); AddStr(row + 2, col, " # "); MyRefresh(); GetColor(); AddStr(row - 2, col, " # # "); AddStr(row - 1, col, "# #"); AddStr(row, col, " "); AddStr(row + 1, col, "# #"); AddStr(row + 2, col, " # # "); MyRefresh(); }
/// <summary> /// Делает курсор консоли невидимым и устанавливает значение /// CursorIsVisible в false. /// </summary> internal void HideCursor() { if (!usingLinux) { CONSOLE_CURSOR_INFO consoleCursorInfo = new CONSOLE_CURSOR_INFO { Size = 5, Visible = false }; Win32.SetConsoleCursorInfo(stdOutputHandle, ref consoleCursorInfo); } else { NCurses.curs_set(CursorVisibility.Invisible); } CursorIsVisible = false; }
public void Print(Board board) { NCurses.NoDelay(Screen, true); NCurses.NoEcho(); for (int i = 0; i < board.height; i++) { StringBuilder buffer = new StringBuilder(); for (int j = 0; j < board.width; j++) { buffer.Append(board.board[i, j] ? '■' : ' '); } NCurses.MoveAddString(i, 0, buffer.ToString()); } NCurses.Refresh(); }
/// <summary> /// Writes collected data to console screen buffer, but paints specified rect only. /// </summary> public virtual void Flush(Rect affectedRect) { if (stdOutputHandle != IntPtr.Zero) { // we are in windows environment SMALL_RECT rect = new SMALL_RECT((short)affectedRect.x, (short)affectedRect.y, (short)(affectedRect.width + affectedRect.x), (short)(affectedRect.height + affectedRect.y)); if (!Win32.WriteConsoleOutputCore(stdOutputHandle, buffer, new COORD((short)size.Width, (short)size.Height), new COORD((short)affectedRect.x, (short)affectedRect.y), ref rect)) { throw new InvalidOperationException(string.Format("Cannot write to console : {0}", Win32.GetLastErrorMessage())); } } else { // we are in linux for (int i = 0; i < affectedRect.width; i++) { int x = i + affectedRect.x; for (int j = 0; j < affectedRect.height; j++) { int y = j + affectedRect.y; // todo : convert attributes and optimize rendering bool fgIntensity; short index = NCurses.winAttrsToNCursesAttrs(buffer[y, x].Attributes, out fgIntensity); if (fgIntensity) { NCurses.attrset( (int)(NCurses.COLOR_PAIR(index) | NCurses.A_BOLD)); } else { NCurses.attrset( (int)NCurses.COLOR_PAIR(index)); } char outChar = buffer[y, x].UnicodeChar != '\0' ? (buffer[y, x].UnicodeChar) : ' '; NCurses.mvaddstr(y, x, new string(outChar, 1)); } } NCurses.refresh(); } }
private void processInputEvent(INPUT_RECORD inputRecord) { if (inputRecord.EventType == EventType.WINDOW_BUFFER_SIZE_EVENT) { if (usingLinux) { // Reinitializing ncurses to deal with new dimensions // http://stackoverflow.com/questions/13707137/ncurses-resizing-glitch NCurses.endwin(); // Needs to be called after an endwin() so ncurses will initialize // itself with the new terminal dimensions. NCurses.refresh(); NCurses.clear(); } COORD dwSize = inputRecord.WindowBufferSizeEvent.dwSize; // Invoke default handler if no custom handlers attached and // userCanvasSize and userRootElementRect are not defined if (TerminalSizeChanged == null && userCanvasSize.IsEmpty && userRootElementRect.IsEmpty) { OnTerminalSizeChangedDefault(this, new TerminalSizeChangedEventArgs(dwSize.X, dwSize.Y)); } else if (TerminalSizeChanged != null) { TerminalSizeChanged.Invoke(this, new TerminalSizeChangedEventArgs(dwSize.X, dwSize.Y)); } // Refresh whole display renderer.FinallyApplyChangesToCanvas(true); return; } eventManager.ParseInputEvent(inputRecord, mainControl); }
private void runLinux(Control control) { this.mainControl = control; if (userCanvasSize.IsEmpty) { // Create physical canvas with actual terminal size winsize ws = Libc.GetTerminalSize(isDarwin); canvas = new PhysicalCanvas(ws.ws_col, ws.ws_row); } else { canvas = new PhysicalCanvas(userCanvasSize.Width, userCanvasSize.Height); } renderer.Canvas = canvas; renderer.RootElementRect = userRootElementRect.IsEmpty ? new Rect(canvas.Size) : userRootElementRect; renderer.RootElement = mainControl; // mainControl.Invalidate(); // Terminal initialization sequence // This is magic workaround to avoid messing up terminal after program finish // The bug is described at https://bugzilla.xamarin.com/show_bug.cgi?id=15118 bool ignored = Console.KeyAvailable; IntPtr stdscr = NCurses.initscr(); NCurses.cbreak(); NCurses.noecho(); NCurses.nonl(); NCurses.intrflush(stdscr, false); NCurses.keypad(stdscr, true); NCurses.start_color(); HideCursor(); try { renderer.UpdateLayout( ); renderer.FinallyApplyChangesToCanvas( ); termkeyHandle = LibTermKey.termkey_new(0, TermKeyFlag.TERMKEY_FLAG_SPACESYMBOL); // Setup the input mode Console.Write("\x1B[?1002h"); pollfd fd = new pollfd( ); fd.fd = 0; fd.events = POLL_EVENTS.POLLIN; pollfd[] fds = new pollfd[2]; fds[0] = fd; fds[1] = new pollfd( ); int pipeResult = Libc.pipe(pipeFds); if (pipeResult == -1) { throw new InvalidOperationException("Cannot create self-pipe."); } fds[1].fd = pipeFds[0]; fds[1].events = POLL_EVENTS.POLLIN; try { #if !WIN32 // Catch SIGWINCH to handle terminal resizing UnixSignal[] signals = new UnixSignal [] { new UnixSignal(Signum.SIGWINCH) }; Thread signal_thread = new Thread(delegate() { while (true) { // Wait for a signal to be delivered int index = UnixSignal.WaitAny(signals, -1); Signum signal = signals [index].Signum; Libc.writeInt64(pipeFds[1], 2); } } ); signal_thread.IsBackground = false; signal_thread.Start(); #endif TermKeyKey key = new TermKeyKey( ); // this.running = true; this.mainThreadId = Thread.CurrentThread.ManagedThreadId; // int nextwait = -1; while (true) { int pollRes = Libc.poll(fds, 2, nextwait); if (pollRes == 0) { if (nextwait == -1) { throw new InvalidOperationException("Assertion failed."); } if (TermKeyResult.TERMKEY_RES_KEY == LibTermKey.termkey_getkey_force(termkeyHandle, ref key)) { processLinuxInput(key); } } if (pollRes == -1) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode != Libc.EINTR) { throw new InvalidOperationException(string.Format("poll() returned with error code {0}", errorCode)); } } if (fds[1].revents != POLL_EVENTS.NONE) { UInt64 u; Libc.readInt64(fds[1].fd, out u); if (u == 1) { // Exit from application #if !WIN32 signal_thread.Abort(); #endif break; } if (u == 2) { // Get new term size and process appropriate INPUT_RECORD event INPUT_RECORD inputRecord = new INPUT_RECORD( ); inputRecord.EventType = EventType.WINDOW_BUFFER_SIZE_EVENT; winsize ws = Libc.GetTerminalSize(isDarwin); inputRecord.WindowBufferSizeEvent.dwSize.X = ( short )ws.ws_col; inputRecord.WindowBufferSizeEvent.dwSize.Y = ( short )ws.ws_row; processInputEvent(inputRecord); } if (u == 3) { // It is signal from async actions invocation stuff } } if ((fds[0].revents & POLL_EVENTS.POLLIN) == POLL_EVENTS.POLLIN || (fds[0].revents & POLL_EVENTS.POLLHUP) == POLL_EVENTS.POLLHUP || (fds[0].revents & POLL_EVENTS.POLLERR) == POLL_EVENTS.POLLERR) { LibTermKey.termkey_advisereadable(termkeyHandle); } TermKeyResult result = (LibTermKey.termkey_getkey(termkeyHandle, ref key)); while (result == TermKeyResult.TERMKEY_RES_KEY) { processLinuxInput(key); result = (LibTermKey.termkey_getkey(termkeyHandle, ref key)); } if (result == TermKeyResult.TERMKEY_RES_AGAIN) { nextwait = LibTermKey.termkey_get_waittime(termkeyHandle); } else { nextwait = -1; } while (true) { bool anyInvokeActions = isAnyInvokeActions( ); bool anyRoutedEvent = !EventManager.IsQueueEmpty( ); bool anyLayoutToRevalidate = renderer.AnyControlInvalidated; if (!anyInvokeActions && !anyRoutedEvent && !anyLayoutToRevalidate) { break; } EventManager.ProcessEvents(); processInvokeActions( ); renderer.UpdateLayout( ); } renderer.FinallyApplyChangesToCanvas( ); } } finally { LibTermKey.termkey_destroy(termkeyHandle); Libc.close(pipeFds[0]); Libc.close(pipeFds[1]); Console.Write("\x1B[?1002l"); } } finally { // Restore cursor visibility before exit ShowCursor( ); NCurses.endwin( ); } renderer.RootElement = null; }
private static void MyRefresh() { NCurses.Nap(FRAMERATE); NCurses.Move(NCurses.Lines - 1, NCurses.Columns - 1); NCurses.Refresh(); }
private void RenderApple() { NCurses.MoveAddChar(apple.Position.Y + 1, apple.Position.X + 1, Apple.SYMBOL); }
private void RenderScore() { NCurses.MoveAddString(size.Height + 2, 0, "Score : " + PlayerScore.ToString()); }
private static void GetColor() { uint bold = (rng.Next(2) > 0) ? CursesAttribute.BOLD : CursesAttribute.NORMAL; NCurses.AttributeSet(NCurses.ColorPair((short)rng.Next(8)) | bold); }