예제 #1
0
        /// <summary>
        /// Копирует affectedRect из буфера на экран консоли с учетом того, что буфер
        /// находится на экране консоли по смещению offset.
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="affectedRect">Измененная область относительно this.</param>
        /// <param name="offset">В какой точке экрана размещен контрол (см <see cref="Renderer.RootElementRect"/>).</param>
        public void CopyToPhysicalCanvas(PhysicalCanvas canvas, Rect affectedRect, Point offset)
        {
            Rect rectToCopy = affectedRect;
            Rect bufferRect = new Rect(new Point(0, 0), new Size(this.width, this.height));
            Rect canvasRect = new Rect(new Point(-offset.X, -offset.Y), canvas.Size);

            rectToCopy.Intersect(canvasRect);
            rectToCopy.Intersect(bufferRect);
            //
            for (int x = 0; x < rectToCopy.width; x++)
            {
                int bufferX = x + rectToCopy.x;
                int canvasX = x + rectToCopy.x + offset.x;
                for (int y = 0; y < rectToCopy.height; y++)
                {
                    int       bufferY  = y + rectToCopy.y;
                    int       canvasY  = y + rectToCopy.y + offset.y;
                    CHAR_INFO charInfo = buffer[bufferX, bufferY];
                    canvas[canvasX][canvasY].Assign(charInfo);
                }
            }
        }
예제 #2
0
 /// <summary>
 /// Копирует affectedRect из буфера на экран консоли с учетом того, что буфер
 /// находится на экране консоли по смещению offset.
 /// </summary>
 /// <param name="canvas"></param>
 /// <param name="affectedRect">Измененная область относительно this.</param>
 /// <param name="offset">В какой точке экрана размещен контрол (см <see cref="Renderer.RootElementRect"/>).</param>
 public void CopyToPhysicalCanvas(PhysicalCanvas canvas, Rect affectedRect, Point offset)
 {
     Rect rectToCopy = affectedRect;
     Rect bufferRect = new Rect(new Point(0, 0), new Size(this.width, this.height));
     Rect canvasRect = new Rect(new Point(-offset.X, -offset.Y), canvas.Size);
     rectToCopy.Intersect(canvasRect);
     rectToCopy.Intersect(bufferRect);
     //
     for (int x = 0; x < rectToCopy.width; x++) {
         int bufferX = x + rectToCopy.x;
         int canvasX = x + rectToCopy.x + offset.x;
         for (int y = 0; y < rectToCopy.height; y++) {
             int bufferY = y + rectToCopy.y;
             int canvasY = y + rectToCopy.y + offset.y;
             CHAR_INFO charInfo = buffer[bufferX, bufferY];
             canvas[canvasX][canvasY].Assign(charInfo);
         }
     }
 }
예제 #3
0
 public CHAR_INFO_ref(int x, int y, PhysicalCanvas canvas) {
     this.x = x;
     this.y = y;
     this.canvas = canvas;
 }
예제 #4
0
 public NestedIndexer(int x, PhysicalCanvas canvas) {
     this.x = x;
     this.canvas = canvas;
 }
예제 #5
0
        private void runWindows(Control control)
        {
            this.mainControl = control;
            //
            stdInputHandle = Win32.GetStdHandle(StdHandleType.STD_INPUT_HANDLE);
            stdOutputHandle = Win32.GetStdHandle(StdHandleType.STD_OUTPUT_HANDLE);
            IntPtr[] handles = new[] {
                exitWaitHandle.SafeWaitHandle.DangerousGetHandle(),
                stdInputHandle,
                invokeWaitHandle.SafeWaitHandle.DangerousGetHandle(  )
            };

            // Set console mode to enable mouse and window resizing events
            const uint ENABLE_WINDOW_INPUT = 0x0008;
            const uint ENABLE_MOUSE_INPUT = 0x0010;
            uint consoleMode;
            Win32.GetConsoleMode( stdInputHandle, out consoleMode );
            Win32.SetConsoleMode(stdInputHandle, consoleMode | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);

            // Get console screen buffer size
            CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
            Win32.GetConsoleScreenBufferInfo( stdOutputHandle, out screenBufferInfo );

            // Set Canvas size to current console window size (not to whole buffer size)
            savedWindowRect = new Rect( new Point( Console.WindowLeft, Console.WindowTop ),
                                        new Size( Console.WindowWidth, Console.WindowHeight ) );
            CanvasSize = new Size(savedWindowRect.Width, savedWindowRect.Height);

            canvas = userCanvasSize.IsEmpty
                ? new PhysicalCanvas( screenBufferInfo.dwSize.X, screenBufferInfo.dwSize.Y, stdOutputHandle )
                : new PhysicalCanvas( userCanvasSize.Width, userCanvasSize.Height, stdOutputHandle);
            renderer.Canvas = canvas;

            // Fill the canvas by default
            renderer.RootElementRect = userRootElementRect.IsEmpty
                ? new Rect( new Point(0, 0), canvas.Size ) : userRootElementRect;
            renderer.RootElement = mainControl;
            //
            mainControl.Invalidate();
            renderer.UpdateLayout();
            renderer.FinallyApplyChangesToCanvas(  );

            // Initially hide the console cursor
            HideCursor();

            this.running = true;
            this.mainThreadId = Thread.CurrentThread.ManagedThreadId;
            //
            while (true) {
                // 100 ms instead of Win32.INFINITE to check console window Zoomed and Iconic
                // state periodically (because if user presses Maximize/Restore button
                // there are no input event generated).
                uint waitResult = Win32.WaitForMultipleObjects(3, handles, false, 100);
                if (waitResult == 0) {
                    break;
                }
                if (waitResult == 1) {
                    processInput();
                }
                if ( waitResult == 2 ) {
                    // Do nothing special - because invokeActions will be invoked in loop anyway
                }

                // If we received WAIT_TIMEOUT - check window Zoomed and Iconic state
                // and correct buffer size and console window size
                if ( waitResult == 0x00000102 ) {
                    IntPtr consoleWindow = getConsoleWindowHwnd( );
                    bool isZoomed = Win32.IsZoomed(consoleWindow);
                    bool isIconic = Win32.IsIconic(consoleWindow);
                    if (maximized != isZoomed && !isIconic) {
                        if (isZoomed)
                            Maximize();
                        else
                            Restore();
                    }
                    if ( !maximized ) {
                        savedWindowRect = new Rect( new Point( Console.WindowLeft, Console.WindowTop ),
                                                    new Size( Console.WindowWidth, Console.WindowHeight ) );
                    }
                }
                // WAIT_FAILED
                if ( waitResult == 0xFFFFFFFF) {
                    throw new InvalidOperationException("Invalid wait result of WaitForMultipleObjects.");
                }

                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( );
            }

            // Restore cursor visibility before exit
            ShowCursor();

            // Restore console mode before exit
            Win32.SetConsoleMode( stdInputHandle, consoleMode );

            renderer.RootElement = null;

            // todo : restore attributes of console output
        }
예제 #6
0
        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;
        }
예제 #7
0
 public CHAR_INFO_ref(int x, int y, PhysicalCanvas canvas)
 {
     this.x      = x;
     this.y      = y;
     this.canvas = canvas;
 }
예제 #8
0
 public NestedIndexer(int x, PhysicalCanvas canvas)
 {
     this.x      = x;
     this.canvas = canvas;
 }