# encoding: utf-8 # api: powershell # title: Test-BufferBox # description: A tech demo: a scrolling buffer where you can type while it’s scrolling… # version: 2.0 # type: script # author: Joel Bennett # license: CC0 # function: New-Box # x-poshcode-id: 730 # x-archived: 2016-07-15T09:50:06 # x-published: 2009-12-12T13:31:00 # # ## Test-BufferBox 2.0 #################################################################################################### ## This script is just a demonstration of some of the things you can do with the buffer ## in the default PowerShell host... it serves as a reminder of how much work remains on ## PoshConsole, and as an inspirations to anyone who is thinking about trying to create ## "interactive" PowerShell applications. ## ## Imagine it's a chat window: you can type, but the whole time, the ongoing conversation in the ## chat room you have joined is going on in the background. ## ## NOTE: because this is a "chat" demo, we treat your input as text, and to execute script in-line ## you have to enclose it inside $() braces. ## #################################################################################################### PARAM( $title = "PowerShell Interactive Buffer Demo" ) $global:fore = $Host.UI.RawUI.ForegroundColor $global:back = $Host.UI.RawUI.BackgroundColor Function New-Box ($Height, $Width, $Title="") { $box = &{ "¯¯$Title$('¯'*($Width-($Title.Length+2)))"; 1..($Height - 2) | % {(' ' * $Width)}; ('_' * $Width); 1..2 | % {(' ' * $Width)}; } $boxBuffer = $Host.UI.RawUI.NewBufferCellArray($box,'Green','Black') ,$boxBuffer } Function Scroll-Buffer ($origin,$Width,$Height,$Scroll=-1){ $re = new-object $RECT $origin.x, $origin.y, ($origin.x + $width-2), ($origin.y + $height) $origin.Y += $Scroll $Host.UI.RawUI.ScrollBufferContents($re, $origin, $re, $blank) } Function Out-Buffer { PARAM ($Message, $Foreground = 'White',$Background = 'Black',[switch]$noscroll) BEGIN { if($Message) { $Message | Out-Buffer -Fore $Foreground -Back $Background -NoScript:$NoScroll } } PROCESS { if($_){$Message = $_ if ( -not $NoScroll) { Scroll-Buffer $ContentPos ($WindowSize.Width -2) ($WindowSize.Height - 4) } # "{0},{1} {2},{3} -{4}" -f $script:pos.X, $script:pos.Y, $MessagePos.X, $MessagePos.Y, $message $host.ui.rawui.SetBufferContents( $MessagePos, $Host.UI.RawUI.NewBufferCellArray( @($message.PadRight($WindowSize.Width)), $Foreground, $Background) ) }}} Function Clear-Prompt () { $Host.UI.RawUI.SetBufferContents( $PromptPos, $prompt ) $Host.UI.RawUI.CursorPosition = $CursorPos } ################################################################################################### ##### Initialize a lot of settings ################################################################################################### $RECT = "system.management.automation.host.rectangle" $blank = new-object System.Management.Automation.Host.BufferCell(' ','Gray','Black','complete') $WindowSize = $Host.UI.RawUI.WindowSize; "`n" * $WindowSize.Height $ContentPos = $Host.UI.RawUI.WindowPosition; $Host.UI.RawUI.ForegroundColor = "Yellow" $Host.UI.RawUI.BackgroundColor = "Black" $ContentPos.Y += 1 # Keep the title in the top row $ContentPos.X += 2 # 2 cell left padding on output # The Message is written into the very last line of the ContentBox $MessagePos = $ContentPos $MessagePos.Y += ($WindowSize.Height - 4) $PromptPos = $ContentPos $PromptPos.X = 0 $PromptPos.Y += $WindowSize.Height - 2 $prompt = $Host.UI.RawUI.NewBufferCellArray( @(&{"> "+(" " * ($WindowSize.Width-3))}), "Yellow", "Black") $CursorPos = $PromptPos $CursorPos.X += 2 ################################################################################################### ##### We only need this for the purposes of the demo... ##### In a real script you would, presumably, be getting stuff from somewhere else to display $noise = Get-Content ($MyInvocation.MyCommand.Path) $index = 0; $random = New-Object "Random" ################################################################################################### ##### The loop starts by clearing the screen ... $Host.UI.RawUI.SetBufferContents($Host.UI.RawUI.WindowPosition, (New-Box ($WindowSize.Height - 1) $WindowSize.Width $title)) ##### Printing a "How to Exit" message Out-Buffer " " -Fore DarkGray -Back Cyan Out-Buffer " This is just a demo. " -Fore Black -Back Cyan Out-Buffer " We will stream in the source code of this script ... " -Fore Black -Back Cyan Out-Buffer " And you can type at the bottom while it's running. " -Fore Black -Back Cyan Out-Buffer " Imagine this as an n-way chat application like IRC, except that " -Fore Black -Back Cyan Out-Buffer " FOR THIS PERFORMANCE ONLY: " -Fore Black -Back Cyan Out-Buffer " The part of your chatting friends is played by my source code. " -Fore DarkGray -Back Cyan Out-Buffer " " -Fore DarkGray -Back Cyan Out-Buffer " Press ESC to exit, or enter 'exit' and hit Enter" -Fore Black -Back Cyan Out-Buffer " " -Fore DarkGray -Back Cyan ##### Setting the prompt Clear-Prompt ##### And initializing our two variables ... $line="" $exit = $false while(!$exit){ while(!$exit -and $Host.UI.RawUI.KeyAvailable) { $char = $Host.UI.RawUI.ReadKey("IncludeKeyUp,IncludeKeyDown,NoEcho"); # we don't want the key up events, but we do want to get rid of them if($char.KeyDown) { switch([int]$char.Character) { 13 { # Enter if($line.Trim() -eq "exit") { $exit = $true; break; } ################################################################################################### ################################################################################################### ############# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ############# ############# This executes the user input! ############# ############# Don't use this on, say, content you got from a web page or chat room ############# iex "Out-Buffer `"$line`" -Fore Red"; ############# ################################################################################################### ################################################################################################### $line = ""; Clear-Prompt } 27 { # Esc $exit = $true; break; } 8 { # Backspace if($line.Length -gt 0) { $line = $line.SubString(0,$($line.Length-1)) } # $pos = $Host.UI.RawUI.CursorPosition $Host.UI.RawUI.SetBufferContents( $PromptPos, $Host.UI.RawUI.NewBufferCellArray( @(&{ "> $($line)$(' ' * ($WindowSize.Width-3-$line.Length))"}), "Yellow", "Black") ) } 0 { # Not actually a key # Out-Buffer $($Char | Out-String) } default { $line += $char.Character $Host.UI.RawUI.SetBufferContents( $PromptPos, $Host.UI.RawUI.NewBufferCellArray( @(&{ "> $($line)$(' ' * ($WindowSize.Width-3-$line.Length))"}), "Yellow", "Black") ) } } } } # Simulate doing useful things 25% of the time if($random.NextDouble() -gt 0.75) { $noise[($index)..($index++)] | Out-Buffer if($index -ge $noise.Length){$index = 0} } sleep -milli 100 } # set the colors back ... $Host.UI.RawUI.ForegroundColor = $fore $Host.UI.RawUI.BackgroundColor = $back