devdaily home | apple | java | perl | unix | directory | blog

What this is

This file is included in the DevDaily.com "Ruby Source Code Warehouse" project. The intent of this project is to help you "Learn Ruby by Example" TM.

Other links

The source code

# Win32::Console:  an object implementing the Win32 API Console functions
# Copyright (C) 2003 Gonzalo Garramuno (ggarramuno@aol.com)
#
# Original Win32API_Console was:
# Copyright (C) 2001 Michael L. Semon (mlsemon@sega.net)

begin
  # If Console.so is available, use that.  Otherwise, we define
  # equivalent functions in ruby (a tad slower)
  # That dll should define everything in an identical interface
  # to all the ruby code that the rescue below defines.
  require "Console.so"
  STDERR.print "Using faster, DLL Console.so\n" if $DEBUG

rescue Exception

  STDERR.print "Using slower, non-DLL Console.rb\n" if $DEBUG

  module Win32
    class Console
    end
  end

  # The WINDOWS constants
  module Win32::Console::Constants
    STD_INPUT_HANDLE          = 0xFFFFFFF6
    STD_OUTPUT_HANDLE         = 0xFFFFFFF5
    STD_ERROR_HANDLE          = 0xFFFFFFF4
    INVALID_HANDLE_VALUE      = 0xFFFFFFFF
    GENERIC_READ              = 0x80000000
    GENERIC_WRITE             = 0x40000000
    FILE_SHARE_READ           = 0x00000001
    FILE_SHARE_WRITE          = 0x00000002
    CONSOLE_TEXTMODE_BUFFER   = 0x00000001

    FOREGROUND_BLUE           = 0x0001
    FOREGROUND_GREEN          = 0x0002
    FOREGROUND_RED            = 0x0004
    FOREGROUND_INTENSITY      = 0x0008
    BACKGROUND_BLUE           = 0x0010
    BACKGROUND_GREEN          = 0x0020
    BACKGROUND_RED            = 0x0040
    BACKGROUND_INTENSITY      = 0x0080

    ENABLE_PROCESSED_INPUT    = 0x0001
    ENABLE_LINE_INPUT         = 0x0002
    ENABLE_ECHO_INPUT         = 0x0004
    ENABLE_WINDOW_INPUT       = 0x0008
    ENABLE_MOUSE_INPUT        = 0x0010
    ENABLE_PROCESSED_OUTPUT   = 0x0001
    ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002

    KEY_EVENT                 = 0x0001
    MOUSE_EVENT               = 0x0002
    WINDOW_BUFFER_SIZE_EVENT  = 0x0004
    MENU_EVENT                = 0x0008
    FOCUS_EVENT               = 0x0010

    CAPSLOCK_ON               = 0x0080
    ENHANCED_KEY              = 0x0100
    NUMLOCK_ON                = 0x0020
    SHIFT_PRESSED             = 0x0010
    LEFT_CTRL_PRESSED         = 0x0008
    RIGHT_CTRL_PRESSED        = 0x0004
    LEFT_ALT_PRESSED          = 0x0002
    RIGHT_ALT_PRESSED         = 0x0001
    SCROLLLOCK_ON             = 0x0040

    MOUSE_WHEELED             = 0x0004
    DOUBLE_CLICK              = 0x0002
    MOUSE_MOVED               = 0x0001

    FROM_LEFT_1ST_BUTTON_PRESSED    = 0x0001
    FROM_LEFT_2ND_BUTTON_PRESSED    = 0x0004
    FROM_LEFT_3RD_BUTTON_PRESSED    = 0x0008
    FROM_LEFT_4TH_BUTTON_PRESSED    = 0x0010
    RIGHTMOST_BUTTON_PRESSED        = 0x0002

    CTRL_C_EVENT              = 0x0000
    CTRL_BREAK_EVENT          = 0x0001
    CTRL_CLOSE_EVENT          = 0x0002
    CTRL_LOGOFF_EVENT         = 0x0005
    CTRL_SHUTDOWN_EVENT       = 0x0006
  end

  # The actual api to access windows functions
  class Win32::Console::API
    require 'Win32API'

    private
    # This is a class-wide cache that will hold Win32API objects.  As each 
    # Win32API object is about 920 bytes, I didn't want to initialize all of 
    # them at one time.  That would waste about 42 kB for this object because 
    # it has 47 functions.  However, to not have a cache at all would reduce 
    # the speed of this object by 164%.
    @@m_AllocConsole = nil
    @@m_CreateConsoleScreenBuffer = nil
    @@m_FillConsoleOutputAttribute = nil
    @@m_FillConsoleOutputCharacter = nil
    @@m_FlushConsoleInputBuffer = nil
    @@m_FreeConsole = nil
    @@m_GenerateConsoleCtrlEvent = nil
    @@m_GetConsoleCP = nil
    @@m_GetConsoleCursorInfo = nil
    @@m_GetConsoleMode = nil
    @@m_GetConsoleOutputCP = nil
    @@m_GetConsoleScreenBufferInfo = nil
    @@m_GetConsoleTitle = nil
    @@m_GetConsoleWindow = nil
    @@m_GetLargestConsoleWindowSize = nil
    @@m_GetNumberOfConsoleInputEvents = nil
    @@m_GetNumberOfConsoleMouseButtons = nil
    @@m_GetStdHandle = nil
    @@m_PeekConsoleInput = nil
    @@m_ReadConsole = nil
    @@m_ReadConsoleInput = nil
    @@m_ReadConsoleOutput = nil
    @@m_ReadConsoleOutputAttribute = nil
    @@m_ReadConsoleOutputCharacter = nil
    @@m_ScrollConsoleScreenBuffer = nil
    @@m_SetConsoleActiveScreenBuffer = nil
    @@m_SetConsoleCP = nil
    @@m_SetConsoleCursorInfo = nil
    @@m_SetConsoleCursorPosition = nil
    @@m_SetConsoleMode = nil
    @@m_SetConsoleOutputCP = nil
    @@m_SetConsoleScreenBufferSize = nil
    @@m_SetConsoleTextAttribute = nil
    @@m_SetConsoleTitle = nil
    @@m_SetConsoleWindowInfo = nil
    @@m_SetStdHandle = nil
    @@m_WriteConsole = nil
    @@m_WriteConsoleInput = nil
    @@m_WriteConsoleOutput = nil
    @@m_WriteConsoleOutputAttribute = nil
    @@m_WriteConsoleOutputCharacter = nil

    public

    class << self

    
      def constant(t)
	begin
	  eval "return Win32::Console::Constants::#{t}"
	rescue
	  return nil
	end
      end


     def AllocConsole()
       if @@m_AllocConsole == nil
	  @@m_AllocConsole = Win32API.new( "kernel32", "AllocConsole", 
					  [], 'l' )
       end
       @@m_AllocConsole.call()
     end

      def CreateConsoleScreenBuffer( dwDesiredAccess, dwShareMode, dwFlags )
        if @@m_CreateConsoleScreenBuffer == nil
	  @@m_CreateConsoleScreenBuffer = Win32API.new( "kernel32", "CreateConsoleScreenBuffer", ['l', 'l', 'p', 'l', 'p'], 'l' )
        end
        @@m_CreateConsoleScreenBuffer.call( dwDesiredAccess, dwShareMode, 
					    nil, dwFlags, nil )
      end



     def FillConsoleOutputAttribute( hConsoleOutput, wAttribute, nLength, 
				      col, row )
       if @@m_FillConsoleOutputAttribute == nil
	  @@m_FillConsoleOutputAttribute = Win32API.new( "kernel32", "FillConsoleOutputAttribute", ['l', 'i', 'l', 'l', 'p'], 'l' )
       end
	dwWriteCoord = (row << 16) + col
	lpNumberOfAttrsWritten = ' ' * 4
       @@m_FillConsoleOutputAttribute.call( hConsoleOutput, wAttribute, 
					    nLength, dwWriteCoord, 
					    lpNumberOfAttrsWritten )
	return lpNumberOfAttrsWritten.unpack('L')
     end



     def FillConsoleOutputCharacter( hConsoleOutput, cCharacter, nLength, 
				      col, row )
       if @@m_FillConsoleOutputCharacter == nil
	  @@m_FillConsoleOutputCharacter = Win32API.new( "kernel32", "FillConsoleOutputCharacter", ['l', 'i', 'l', 'l', 'p'], 'l' )
       end
	dwWriteCoord = (row << 16) + col
	lpNumberOfAttrsWritten = ' ' * 4
       @@m_FillConsoleOutputCharacter.call( hConsoleOutput, cCharacter, 
					    nLength, dwWriteCoord, 
					    lpNumberOfAttrsWritten )
	return lpNumberOfAttrsWritten.unpack('L')
     end


      def FlushConsoleInputBuffer( hConsoleInput )
        if @@m_FlushConsoleInputBuffer == nil
	  @@m_FlushConsoleInputBuffer = Win32API.new( "kernel32", 
						     "FillConsoleInputBuffer",
						     ['l'], 'l' )
        end
        @@m_FlushConsoleInputBuffer.call( hConsoleInput )
      end


      def FreeConsole()
        if @@m_FreeConsole == nil
	  @@m_FreeConsole = Win32API.new( "kernel32", "FreeConsole", [], 'l' )
        end
        @@m_FreeConsole.call()
      end


      def GenerateConsoleCtrlEvent( dwCtrlEvent, dwProcessGroupId )
        if @@m_GenerateConsoleCtrlEvent == nil
	  @@m_GenerateConsoleCtrlEvent = Win32API.new( "kernel32", "GenerateConsoleCtrlEvent", ['l', 'l'], 'l' )
        end
        @@m_GenerateConsoleCtrlEvent.call( dwCtrlEvent, dwProcessGroupId )
      end

     def GetConsoleCP()
       if @@m_GetConsoleCP == nil
	  @@m_GetConsoleCP = Win32API.new( "kernel32", "GetConsoleCP", 
					  [], 'l' )
       end
       @@m_GetConsoleCP.call()
     end

     def GetConsoleCursorInfo( hConsoleOutput )
       if @@m_GetConsoleCursorInfo == nil
	  @@m_GetConsoleCursorInfo = Win32API.new( "kernel32", 
						  "GetConsoleCursorInfo", 
						  ['l', 'p'], 'l' )
       end
	lpConsoleCursorInfo = ' ' * 8
       @@m_GetConsoleCursorInfo.call( hConsoleOutput, lpConsoleCursorInfo )
	return lpConsoleCursorInfo.unpack('LL')
     end

      def GetConsoleMode( hConsoleHandle )
        if @@m_GetConsoleMode == nil
	  @@m_GetConsoleMode = Win32API.new( "kernel32", "GetConsoleMode", 
					    ['l', 'p'], 'l' )
        end
	lpMode = ' ' * 4
        @@m_GetConsoleMode.call( hConsoleHandle, lpMode )
	return lpMode.unpack('L')
      end

     def GetConsoleOutputCP()
       if @@m_GetConsoleOutputCP == nil
	  @@m_GetConsoleOutputCP = Win32API.new( "kernel32", 
						"GetConsoleOutputCP", [], 'l' )
       end
       @@m_GetConsoleOutputCP.call()
     end

     def GetConsoleScreenBufferInfo( hConsoleOutput )
       if @@m_GetConsoleScreenBufferInfo == nil
	  @@m_GetConsoleScreenBufferInfo = Win32API.new( "kernel32", "GetConsoleScreenBufferInfo", ['l', 'p'], 'l' )
       end
	lpBuffer = ' ' * 22
       @@m_GetConsoleScreenBufferInfo.call( hConsoleOutput, lpBuffer )
	return lpBuffer.unpack('SSSSSssssSS')
     end

     def GetConsoleTitle()
        if @@m_GetConsoleTitle == nil
	  @@m_GetConsoleTitle = Win32API.new( "kernel32", "GetConsoleTitle", 
					     ['p', 'l'], 'l' )
        end
	nSize = 120
	lpConsoleTitle = ' ' * nSize
        @@m_GetConsoleTitle.call( lpConsoleTitle, nSize )
	return lpConsoleTitle.strip
      end

     def GetConsoleWindow()
       if @@m_GetConsoleWindow == nil
	  @@m_GetConsoleWindow = Win32API.new( "kernel32", "GetConsoleWindow",
					      [], 'l' )
       end
       @@m_GetConsoleWindow.call()
     end

      def GetLargestConsoleWindowSize( hConsoleOutput )
        if @@m_GetLargestConsoleWindowSize == nil
	  @@m_GetLargestConsoleWindowSize = Win32API.new( "kernel32", "GetLargestConsoleWindowSize", ['l'], 'l' )
        end
        coord = @@m_GetLargestConsoleWindowSize.call( hConsoleOutput )
	x = coord >> 16
	y = coord & 0x0000ffff
	return [x,y]
      end

      def GetNumberOfConsoleInputEvents( hConsoleInput )
        if @@m_GetNumberOfConsoleInputEvents == nil
	  @@m_GetNumberOfConsoleInputEvents = Win32API.new( "kernel32", "GetNumberOfConsoleInputEvents", ['l', 'p'], 'l' )
        end
	lpcNumberOfEvents = 0
        @@m_GetNumberOfConsoleInputEvents.call( hConsoleInput, 
					       lpcNumberOfEvents )
	return lpcNumberOfEvents
      end

      def GetNumberOfConsoleMouseButtons( )
        if @@m_GetNumberOfConsoleMouseButtons == nil
	  @@m_GetNumberOfConsoleMouseButtons = Win32API.new( "kernel32", "GetNumberOfConsoleMouseButtons", ['p'], 'l' )
        end
	lpNumberOfMouseButtons = 0
        @@m_GetNumberOfConsoleMouseButtons.call( lpNumberOfMouseButtons )
	return lpNumberOfMouseButtons
      end

     def GetStdHandle( nStdHandle )
       if @@m_GetStdHandle == nil
	  @@m_GetStdHandle = Win32API.new( "kernel32", "GetStdHandle", 
					  ['l'], 'l' )
       end
       @@m_GetStdHandle.call( nStdHandle )
     end

      # <> : This is not an actual API function, just a concept description in the SDK.

      def PeekConsoleInput( hConsoleInput )
        if @@m_PeekConsoleInput == nil
	  @@m_PeekConsoleInput = Win32API.new( "kernel32", "PeekConsoleInput",
					      ['l', 'p', 'l', 'p'], 'l' )
        end
	lpNumberOfEventsRead = ' ' * 4
	lpBuffer = ' ' * 20
	nLength  = 20
        @@m_PeekConsoleInput.call( hConsoleInput, lpBuffer, nLength, 
				   lpNumberOfEventsRead )
	type = lpBuffer.unpack('s')[0]

	case type
	when KEY_EVENT
	  return lpBuffer.unpack('sSSSSCS') 
	when MOUSE_EVENT
	  return lpBuffer.unpack('sSSSS')
	when WINDOW_BUFFER_SIZE_EVENT
	  return lpBuffer.unpack('sS') 
	when MENU_EVENT
	  return lpBuffer.unpack('sS') 
	when FOCUS_EVENT
	  return lpBuffer.unpack('sS')
	else
	  return []
	end
      end

      def ReadConsole( hConsoleInput, lpBuffer, nNumberOfCharsToRead )
        if @@m_ReadConsole == nil
	  @@m_ReadConsole = Win32API.new( "kernel32", "ReadConsole", 
					 ['l', 'p', 'l', 'p', 'p'], 'l' )
        end
	lpBuffer = ' ' * nNumberOfCharsToRead unless lpBuffer
	lpNumberOfCharsRead = ' ' * 4
	lpReserved = ' ' * 4
        @@m_ReadConsole.call( hConsoleInput, lpBuffer, nNumberOfCharsToRead, 
			     lpNumberOfCharsRead, lpReserved )
	return lpNumberOfCharsRead.unpack('L')
      end

      def ReadConsoleInput( hConsoleInput )
        if @@m_ReadConsoleInput == nil
	  @@m_ReadConsoleInput = Win32API.new( "kernel32", "ReadConsoleInput",
					      ['l', 'p', 'l', 'p'], 'l' )
        end
	lpNumberOfEventsRead = ' ' * 4
	lpBuffer = ' ' * 20
	nLength  = 20
        @@m_ReadConsoleInput.call( hConsoleInput, lpBuffer, nLength, 
				  lpNumberOfEventsRead )
	type = lpBuffer.unpack('s')[0] 

	case type
	when KEY_EVENT
	  return lpBuffer.unpack('sSSSSCS') 
	when MOUSE_EVENT
	  return lpBuffer.unpack('sSSSS')
	when WINDOW_BUFFER_SIZE_EVENT
	  return lpBuffer.unpack('sS') 
	when MENU_EVENT
	  return lpBuffer.unpack('sS') 
	when FOCUS_EVENT
	  return lpBuffer.unpack('sS')
	else
	  return []
	end
      end

      def ReadConsoleOutput( hConsoleOutput, lpBuffer, cols, rows,
			    bufx, bufy, left, top, right, bottom )
        if @@m_ReadConsoleOutput == nil
	  @@m_ReadConsoleOutput = Win32API.new( "kernel32", 
					       "ReadConsoleOutput", 
					       ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	dwBufferSize  = cols * rows * 4
	lpBuffer = ' ' * dwBufferSize
	dwBufferCoord = (bufy << 16) + bufx
	lpReadRegion  = [ left, top, right, bottom ].pack('ssss')
        @@m_ReadConsoleOutput.call( hConsoleOutput, lpBuffer, dwBufferSize, 
				   dwBufferCoord, lpReadRegion )
      end

      def ReadConsoleOutputAttribute( hConsoleOutput, nLength, col, row )
        if @@m_ReadConsoleOutputAttribute == nil
	  @@m_ReadConsoleOutputAttribute = Win32API.new( "kernel32", "ReadConsoleOutputAttribute", ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	lpAttribute = ' ' * nLength
	dwReadCoord = (row << 16) + col
	lpNumberOfAttrsRead = ' ' * 4
        @@m_ReadConsoleOutputAttribute.call( hConsoleOutput, lpAttribute, 
					    nLength, dwReadCoord, 
					    lpNumberOfAttrsRead )
	return lpAttribute
      end

      def ReadConsoleOutputCharacter( hConsoleOutput, lpCharacter, nLength, 
				      col, row )
        if @@m_ReadConsoleOutputCharacter == nil
	  @@m_ReadConsoleOutputCharacter = Win32API.new( "kernel32", "ReadConsoleOutputCharacter", ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	dwReadCoord = (row << 16) + col
	lpNumberOfCharsRead = ' ' * 4
        @@m_ReadConsoleOutputCharacter.call( hConsoleOutput, lpCharacter, 
					    nLength, dwReadCoord, 
					    lpNumberOfCharsRead )
	return lpNumberOfCharsRead.unpack('L')
      end

     def ScrollConsoleScreenBuffer( hConsoleOutput, 
				    left1, top1, right1, bottom1,
				    col, row, char, attr,
				    left2, top2, right2, bottom2 )
       if @@m_ScrollConsoleScreenBuffer == nil
	  @@m_ScrollConsoleScreenBuffer = Win32API.new( "kernel32", "ScrollConsoleScreenBuffer", ['l', 'p', 'p', 'l', 'p'], 'l' )
       end
	lpScrollRectangle = [left1, top1, right1, bottom1].pack('ssss')
	lpClipRectangle   = [left2, top2, right2, bottom2].pack('ssss')
	dwDestinationOrigin = (row << 16) + col
	lpFill = [char, attr].pack('ss')
       @@m_ScrollConsoleScreenBuffer.call( hConsoleOutput, lpScrollRectangle,
					   lpClipRectangle, 
					   dwDestinationOrigin, lpFill )
     end

     def SetConsoleActiveScreenBuffer( hConsoleOutput )
       if @@m_SetConsoleActiveScreenBuffer == nil
	  @@m_SetConsoleActiveScreenBuffer = Win32API.new( "kernel32", "SetConsoleActiveScreenBuffer", ['l'], 'l' )
       end
       @@m_SetConsoleActiveScreenBuffer.call( hConsoleOutput )
     end

      # <>:  Will probably not be implemented.

     def SetConsoleCP( wCodePageID )
       if @@m_SetConsoleCP == nil
	  @@m_SetConsoleCP = Win32API.new( "kernel32", "SetConsoleCP", 
					  ['l'], 'l' )
       end
       @@m_SetConsoleCP.call( wCodePageID )
     end

     def SetConsoleCursorInfo( hConsoleOutput, col, row )
       if @@m_SetConsoleCursorInfo == nil
	  @@m_SetConsoleCursorInfo = Win32API.new( "kernel32", 
						  "SetConsoleCursorInfo", 
						  ['l', 'p'], 'l' )
       end
	lpConsoleCursorInfo = [size,visi].pack('LL')
       @@m_SetConsoleCursorInfo.call( hConsoleOutput, lpConsoleCursorInfo )
     end

     def SetConsoleCursorPosition( hConsoleOutput, col, row )
       if @@m_SetConsoleCursorPosition == nil
	  @@m_SetConsoleCursorPosition = Win32API.new( "kernel32", "SetConsoleCursorPosition", ['l', 'p'], 'l' )
       end
	dwCursorPosition = (row << 16) + col
       @@m_SetConsoleCursorPosition.call( hConsoleOutput, dwCursorPosition )
     end

     def SetConsoleMode( hConsoleHandle, lpMode )
       if @@m_SetConsoleMode == nil
	  @@m_SetConsoleMode = Win32API.new( "kernel32", "SetConsoleMode", 
					    ['l', 'p'], 'l' )
       end
       @@m_SetConsoleMode.call( hConsoleHandle, lpMode )
     end

     def SetConsoleOutputCP( wCodePageID )
       if @@m_SetConsoleOutputCP == nil
	  @@m_SetConsoleOutputCP = Win32API.new( "kernel32", 
						"GetConsoleOutputCP", 
						['l'], 'l' )
       end
       @@m_SetConsoleOutputCP.call( wCodePageID )
     end

      def SetConsoleScreenBufferSize( hConsoleOutput, col, row )
        if @@m_SetConsoleScreenBufferSize == nil
	  @@m_SetConsoleScreenBufferSize = Win32API.new( "kernel32", "SetConsoleScreenBufferSize", ['l', 'l'], 'l' )
        end
	dwSize = (row << 16) + col
        @@m_SetConsoleScreenBufferSize.call( hConsoleOutput, dwSize )
      end

     def SetConsoleTextAttribute( hConsoleOutput, wAttributes )
       if @@m_SetConsoleTextAttribute == nil
	  @@m_SetConsoleTextAttribute = Win32API.new( "kernel32", "SetConsoleTextAttribute", ['l', 'i'], 'l' )
       end
       @@m_SetConsoleTextAttribute.call( hConsoleOutput, wAttributes )
     end

      def SetConsoleTitle( lpConsoleTitle )
        if @@m_SetConsoleTitle == nil
	  @@m_SetConsoleTitle = Win32API.new( "kernel32", "SetConsoleTitle", 
					     ['p'], 'l' )
        end
        @@m_SetConsoleTitle.call( lpConsoleTitle )
      end

      def SetConsoleWindowInfo( hConsoleOutput, bAbsolute, 
			        left, top, right, bottom )
        if @@m_SetConsoleWindowInfo == nil
	  @@m_SetConsoleWindowInfo = Win32API.new( "kernel32", 
						  "SetConsoleWindowInfo", 
						  ['l', 'l', 'p'], 'l' )
        end
	lpConsoleWindow = [ left, top, right, bottom ].pack('ssss')
        @@m_SetConsoleWindowInfo.call( hConsoleOutput, bAbsolute, 
				      lpConsoleWindow )
      end

      def SetStdHandle( nStdHandle, hHandle )
        if @@m_SetStdHandle == nil
	  @@m_SetStdHandle = Win32API.new( "kernel32", "SetStdHandle",
					  ['l', 'l'], 'l' )
        end
        @@m_SetStdHandle.call( nStdHandle, hHandle )
      end

     def WriteConsole( hConsoleOutput, lpBuffer )
       if @@m_WriteConsole == nil
	  @@m_WriteConsole = Win32API.new( "kernel32", "WriteConsole",
					  ['l', 'p', 'l', 'p', 'p'], 'l' )
       end
	nNumberOfCharsToWrite = lpBuffer.length()
	lpNumberOfCharsWritten = ' ' * 4
	lpReserved = ' ' * 4
       @@m_WriteConsole.call( hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
			      lpNumberOfCharsWritten,  lpReserved )
	return lpNumberOfCharsWritten
     end

      def WriteConsoleInput( hConsoleInput, lpBuffer )
        if @@m_WriteConsoleInput == nil
	  @@m_WriteConsoleInput = Win32API.new( "kernel32", "WriteConsoleInput", ['l', 'p', 'l', 'p'], 'l' )
        end
        @@m_WriteConsoleInput.call( hConsoleInput, lpBuffer, nLength, 
				   lpNumberOfEventsWritten )
      end

      # @@ Todo: Test this
      def WriteConsoleOutput( hConsoleOutput, buffer, cols, rows,
			     bufx, bufy, left, top, right, bottom )
        if @@m_WriteConsoleOutput == nil
	  @@m_WriteConsoleOutput = Win32API.new( "kernel32", "WriteConsoleOutput", ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	lpBuffer = buffer.flatten.pack('ss' * buffer.length() * 2)
	dwBufferSize = (buffer.length() << 16) + 2
	dwBufferCoord = (row << 16) + col 
	lpWriteRegion = [ left, top, right, bottom ].pack('ssss')
        @@m_WriteConsoleOutput.call( hConsoleOutput, lpBuffer, dwBufferSize,
				    dwBufferCoord, lpWriteRegion )
      end

      def WriteConsoleOutputAttribute( hConsoleOutput, lpAttribute, col, row )
        if @@m_WriteConsoleOutputAttribute == nil
	  @@m_WriteConsoleOutputAttribute = Win32API.new( "kernel32", "WriteConsoleOutputAttribute", ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	nLength = lpAttribute.length()
	dwWriteCoord = (row << 16) + col
	lpNumberOfAttrsWritten = ' ' * 4
        @@m_WriteConsoleOutputAttribute.call( hConsoleOutput, lpAttribute, 
					     nLength, dwWriteCoord, 
					     lpNumberOfAttrsWritten )
	return lpNumberOfAttrsWritten.unpack('L')
      end

      def WriteConsoleOutputCharacter( hConsoleOutput, lpCharacter, col, row )
        if @@m_WriteConsoleOutputCharacter == nil
	  @@m_WriteConsoleOutputCharacter = Win32API.new( "kernel32", "WriteConsoleOutputCharacter", ['l', 'p', 'l', 'l', 'p'], 'l' )
        end
	nLength = lpCharacter.length()
	dwWriteCoord = (row << 16) + col
	lpNumberOfCharsWritten = ' ' * 4
        @@m_WriteConsoleOutputCharacter.call( hConsoleOutput, lpCharacter, 
					     nLength, dwWriteCoord, 
					     lpNumberOfCharsWritten )
	return lpNumberOfCharsWritten.unpack('L')
      end

    end
  end

end  # rescue



module Win32
  class Console

    VERSION = '1.0'

    include Win32::Console::Constants

    def initialize( t = nil )
      if t and ( t == STD_INPUT_HANDLE or t == STD_OUTPUT_HANDLE or
		 t == STD_ERROR_HANDLE )
	@handle = API.GetStdHandle( t )
      else
	param1 = GENERIC_READ    | GENERIC_WRITE
	param2 = FILE_SHARE_READ | FILE_SHARE_WRITE
	@handle = API.CreateConsoleScreenBuffer( param1, param2, 
						 CONSOLE_TEXTMODE_BUFFER )
      end
    end


    def Display
      return API.SetConsoleActiveScreenBuffer(@handle)
    end

    def Select(type)
      return API.SetStdHandle(type,@handle)
    end

    def Title(title = nil)
      if title
	return API.SetConsoleTitle(title)
      else
	return API.GetConsoleTitle()
      end
    end

    def WriteChar(s, col, row)
      API.WriteConsoleOutputCharacter( @handle, s, col, row )
    end

    def ReadChar(size, col, row)
      buffer = ' ' * size
      if API.ReadConsoleOutputCharacter( @handle, buffer, size, col, row )
	return buffer
      else
	return nil
      end
    end

    def WriteAttr(attr, col, row)
      API.WriteConsoleOutputAttribute( @handle, attr, col, row )
    end

    def ReadAttr(size, col, row)
      x = API.ReadConsoleOutputAttribute( @handle, size, col, row )
      return x.unpack('c'*size)
    end


    def Cursor(*t)
      col, row, size, visi = t
      if col
	row = -1 if !row
	if col < 0 or row < 0
	  curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
	  col = curr_col if col < 0
	  row = curr_row if row < 0
	end
	API.SetConsoleCursorPosition( @handle, col, row )
	if size and visi
	  curr_size, curr_visi = API.GetConsoleCursorInfo( @handle )
	  size = curr_size if size < 0
	  visi = curr_visi if visi < 0
	  size = 1 if size < 1
	  size = 99 if size > 99
	  API.SetConsoleCursorInfo( @handle, size, visi )
	end
      else
	d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
	curr_size, curr_visi = API.GetConsoleCursorInfo( @handle )
        return [ curr_col, curr_row, curr_size, curr_visi ]
      end
    end

    def Write(s)
      API.WriteConsole( @handle, s )
    end

    def ReadRect( left, top, right, bottom )
      col = right  - left + 1
      row = bottom - top  + 1
      size = col * row
      buffer = ' ' * size * 4
      if API.ReadConsoleOutput( @handle, buffer, col, row, 0, 0, 
			       left, top, right, bottom )
	#return buffer.unpack('US'*size)  # for unicode
	return buffer.unpack('axS'*size)  # for ascii
      else
	return nil
      end
    end

    def WriteRect( buffer, left, top, right, bottom )
      col = right  - left + 1
      row = bottom - top  + 1
      API.WriteConsoleOutput( @handle, buffer, col, row, 0, 0, 
			     left, top, right, bottom )
    end



    def Scroll( left1, top1, right1, bottom1,
	       col, row, char, attr,
	       left2, top2, right2, bottom2 )
      API.ScrollConsoleScreenBuffer(@handle, left1, top1, right1, bottom1,
				    col, row, char, attr,
				    left2, top2, right2, bottom2)
    end


    def MaxWindow(flag = nil)
      if !flag
	info = API.GetConsoleScreenBufferInfo(@handle)
        return info[9], info[10]
      else
        return API.GetLargestConsoleWindowSize(@handle)
      end
    end


    def Info()
      return API.GetConsoleScreenBufferInfo( @handle )
    end


    def GetEvents()
      return API.GetNumberOfConsoleInputEvents(@handle)
    end


    def Flush()
      return API.FlushConsoleInputBuffer(@handle)
    end

    def InputChar(number = nil)
      number = 1 unless number
      buffer = ' ' * number
      if API.ReadConsole(@handle, buffer, number) == number
	return buffer
      else
	return nil
      end
    end


    def Input()
      API.ReadConsoleInput(@handle)
    end


    def PeekInput()
      API.PeekConsoleInput(@handle)
    end


    def Mode(mode = nil)
      if mode
	mode = mode.pack('L') if mode === Array
	API.SetConsoleMode(@handle, mode)
      else
	return API.GetConsoleMode(@handle)
      end
    end

    def WriteInput(*t)
      API.WriteConsoleInput(@handle, *t)
    end

    def Attr(*attr)
      if attr.size > 0
	API.SetConsoleTextAttribute( @handle, attr[0] )
      else
	info = API.GetConsoleScreenBufferInfo( @handle )
	return info[4]
      end
    end


    def Size(*t)
      if t.size == 0
	col, row = API.GetConsoleScreenBufferInfo(@handle )
        return [col, row]
      else
	row = -1 if !t[1]
	col = -1 if !t[0]
	if col < 0 or row < 0
	  curr_col, curr_row = Size()
	  col = curr_col if col < 0
	  row = curr_row if row < 0
	end
	API.SetConsoleScreenBufferSize(@handle, row, col)
      end
    end

    def Window(*t)
      if t.size != 5
	info = API.GetConsoleScreenBufferInfo( @handle )
	return info[5..8]
      else
	API.SetConsoleWindowInfo(@handle, t[0], t[1], t[2], t[3], t[4])
      end
    end

    def FillAttr(attr, number = 1, col = -1, row = -1)
      if col < 0 or row < 0
	d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
        col = curr_col if col < 0
        row = curr_row if row < 0
      end
      API.FillConsoleOutputAttribute(@handle, attr, number, col, row)
    end

    def FillChar(char, number, col = -1, row = -1)
      if col < 0 or row < 0
	d, d, curr_col, curr_row = API.GetConsoleScreenBufferInfo(@handle)
        col = curr_col if col < 0
        row = curr_row if row < 0
      end
      API.FillConsoleOutputCharacter(@handle, char[0], number, col, row)
    end

    def Cls()
      attr = ATTR_NORMAL
      x, y = Size()
      left, top, right , bottom = Window()
      vx = right  - left
      vy = bottom - top
      FillChar(' ', x*y, 0, 0)
      FillAttr(attr, x*y, 0, 0)
      Cursor(0,0)
      Window(1,0,0,vx,vy)
    end

    def Console.Free()
      API.FreeConsole()
    end

    def Console.Alloc()
      API.AllocConsole()
    end

    def Console.MouseButtons()
      API.GetNumberOfConsoleMouseButtons()
    end

    def Console.InputCP(codepage=nil)
      if codepage
	API.SetConsoleCP(codepage)
      else
	return API.GetConsoleCP()
      end
    end

    def Console.OutputCP(codepage=nil)
      if codepage
	API.SetConsoleOutputCP(codepage)
      else
	return API.GetConsoleOutputCP()
      end
    end

    def Console.GenerateCtrlEvent( type=nil, pid=nil )
      type = API.constant('CTRL_C_EVENT') if type == nil
      pid  = 0 if pid == nil
      API.GenerateConsoleCtrlEvent(type, pid)
    end

  end
end





FG_BLACK        = 0
FG_BLUE         = Win32::Console::API.constant("FOREGROUND_BLUE")
FG_LIGHTBLUE    = Win32::Console::API.constant("FOREGROUND_BLUE")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_RED          = Win32::Console::API.constant("FOREGROUND_RED")
FG_LIGHTRED     = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_GREEN        = Win32::Console::API.constant("FOREGROUND_GREEN")
FG_LIGHTGREEN   = Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_MAGENTA      = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")
FG_LIGHTMAGENTA = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_CYAN         = Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")
FG_LIGHTCYAN    = Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_BROWN        = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_GREEN")
FG_YELLOW       = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")
FG_GRAY         = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")
FG_WHITE        = Win32::Console::API.constant("FOREGROUND_RED")|
                  Win32::Console::API.constant("FOREGROUND_GREEN")|
                  Win32::Console::API.constant("FOREGROUND_BLUE")|
                  Win32::Console::API.constant("FOREGROUND_INTENSITY")

BG_BLACK        = 0
BG_BLUE         = Win32::Console::API.constant("BACKGROUND_BLUE")
BG_LIGHTBLUE    = Win32::Console::API.constant("BACKGROUND_BLUE")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_RED          = Win32::Console::API.constant("BACKGROUND_RED")
BG_LIGHTRED     = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_GREEN        = Win32::Console::API.constant("BACKGROUND_GREEN")
BG_LIGHTGREEN   = Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_MAGENTA      = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")
BG_LIGHTMAGENTA = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_CYAN         = Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")
BG_LIGHTCYAN    = Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_BROWN        = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_GREEN")
BG_YELLOW       = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")
BG_GRAY         = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")
BG_WHITE        = Win32::Console::API.constant("BACKGROUND_RED")|
                  Win32::Console::API.constant("BACKGROUND_GREEN")|
                  Win32::Console::API.constant("BACKGROUND_BLUE")|
                  Win32::Console::API.constant("BACKGROUND_INTENSITY")

ATTR_NORMAL  = FG_GRAY  | BG_BLACK
ATTR_INVERSE = FG_BLACK | BG_GRAY

include Win32::Console::Constants




Copyright 1998-2008 Alvin Alexander
All Rights Reserved.
 
devdaily.com is based in louisville, kentucky, and this web site is hosted by godaddy.com