/*
  CONSOLE.INC

  ================
  CONSOLE ROUTINES
  ================

  07/10/2014
  11/05/2018
  01/12/2023
  02/04/2025
  09/02/2026
  CP

  http://msdn.microsoft.com/en-us/library/ms686033(v=vs.85).aspx

  redirected i/o
  http://msdn.microsoft.com/en-us/library/windows/desktop/ms683457(v=vs.85).aspx

  escape sequences
  https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences


  OPTIONS
  =======
  % NoConsole
  % TryAttachConsole

  Console Modes:
  ==============
  
  001h Enable processed input
  002h Enable line input
  004h Enable input echo
  008h Enable window input
  010h Enable mouse input
  020h Enable insert mode
  040h Enable quick edit mode
  080h Enable extended flags
  
*/

  
  type COORD
    short x,y
    =
    long c
  end type
  '
  type SMALL_RECT
   short left,top,right,bottom
  end type
  '
  type CONSOLE_SCREEN_BUFFER_INFO
    COORD      dwSize;
    COORD      dwCursorPosition;
    word       wAttributes;
    SMALL_RECT srWindow;
    COORD      dwMaximumWindowSize
  end type

  type CONSOLE_CURSOR_INFO
    DWORD dwSize;
    BOOL  bVisible;
  end type


  sys ner[100]

  extern lib "KERNEL32.DLL"
  ! Sleep                      (sys msec)
  ! AttachConsole              (sys pp) as sys
  ! AllocConsole               () as sys
  ! FreeConsole                () as sys
  ! GetConsoleMode             (sys handle,*m)
  ! SetConsoleMode             (sys handle,m)
  ! GetConsoleWindow           () as sys
  ! GetStdHandle               (sys h) as sys
  ! SetConsoleCursorPosition   (sys h,coords)
  ! SetConsoleTextAttribute    (sys hOut,color)
  ! FillConsoleOutputCharacterA(sys hOut,ch,n,coords,long *writ)
  ! FillConsoleOutputAttribute (sys hOut,ab,n,coords,long *writ)
  ! GetConsoleScreenBufferInfo (sys hOut,CONSOLE_SCREEN_BUFFER_INFO*i)

  ! WriteConsole    alias "WriteConsoleA"    (sys hOut, lpBuffer, nNumberOfCharsToWrite, long lpNumberOfCharsWritten, lpReserved) as sys

  ! WriteFile       alias "WriteFile"        (sys hOut, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpOverlapped) as sys

  ! ReadConsole     alias "ReadConsoleA"     (sys hIn,lpBuffer, nNumberOfCharsToRead, long lpNumberOfCharsRead, lpInputControl) as sys

  ! ReadFile        alias "ReadFile"         (sys hIn,lpBuffer,nNumberOfCharsToRead, lpNumberOfCharsRead, lpOverlapped) as sys

  ! GetCommandLine  alias "GetCommandLineA"  () as char*
  ! SetConsoleTitle alias "SetConsoleTitleA" (char*lpConsoleTitle) as sys
  ! ShellExecute alias "ShellExecuteA" lib "Shell32.dll" _
    (sys Hwnd, char* operation,file,parameters,directory,sys ShowCmd) as sys
  ! PeekConsoleInputA
  ! FlushConsoleInputBuffer
  '! GetAsyncKeyState

  ! GetConsoleCursorInfo
  ! SetConsoleCursorInfo
  ' HANDLE               hConsoleOutput,
  ' PCONSOLE_CURSOR_INFO lpConsoleCursorInfo


  end extern

  % STD_INPUT_HANDLE  -10
  % STD_OUTPUT_HANDLE -11
  % STD_ERROR_HANDLE  -12 

  sys nner,ConsOut,ConsIn,ConsErr,ConsoleAttached
  ConsIn  = GetStdHandle STD_INPUT_HANDLE
  ConsOut = GetStdHandle STD_OUTPUT_HANDLE
  #ifndef NoConsole
    #ifdef TryAttachConsole
      if ConsOut then
        AttachConsole -1 'attach to console of parent process
        ConsoleAttached=1
      else
        AllocConsole
        ConsOut = GetStdHandle STD_OUTPUT_HANDLE
        ConsIn  = GetStdHandle STD_INPUT_HANDLE
        ConsoleAttached=0
      end if
    #else
      AllocConsole
      ConsIn  = GetStdHandle STD_INPUT_HANDLE
      ConsOut = GetStdHandle STD_OUTPUT_HANDLE
    #endif
    '
    SetConsoleTitle "OxygenBasic"

  #endif 'no sNoConsole


  def Color   SetConsoleTextAttribute ConsOut,
  def Wait    Getkey
  def WaitKey GetKey
  def Pause   Getkey


  function SetCursor(int n)
  =========================
  CONSOLE_CURSOR_INFO ci
  GetConsoleCursorInfo ConsOut,ci
  ci.bvisible=n
  SetConsoleCursorInfo ConsOut,ci
  end function


  function SetPos(int x=0,y=0)
  ============================
  COORD c={x,y}
  SetConsoleCursorPosition  ConsOut,c.c
  end function


  function cls()
  ==============
  sys   hConsole      = ConsOut
  COORD coordScreen   = { 0, 0 } 'home for the cursor 
  sys   dwConSize
  sys   cCharsWritten
  CONSOLE_SCREEN_BUFFER_INFO csbi
  '
  'Get the number of character cells in the current buffer. 
  if not GetConsoleScreenBufferInfo( hConsole, csbi ) then return
  '
  dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
  '
  'Fill the entire screen with blanks.
  if not FillConsoleOutputCharacterA( hConsole,32,dwConSize,
         coordScreen.c,cCharsWritten) then return
  '
  'Get the current text attribute.
  if not GetConsoleScreenBufferInfo( hConsole, csbi ) then return
  '
  'Set the buffer's attributes accordingly.
  if not FillConsoleOutputAttribute( hConsole,csbi.wAttributes,dwConSize,
         coordScreen.c,cCharsWritten ) then return
  '
  'Put the cursor at its home coordinates.
  SetConsoleCursorPosition( hConsole, coordScreen.c )
  end function

  function input() as string
  ==========================
  static int blen      
  static zstring bufin[0x1000]      
  ReadFile ConsIn,strptr bufin,0xffe,@blen,null
  return left bufin,blen
  end function

  'tlog3
  '
  Function output(string bufout)
  ==============================
  static long buflen,bufrit
  buflen=len bufout
  WriteFile ConsOut,strptr bufout,buflen,@bufrit,null
  End Function
  '
  Function print(string bufout)
  =============================
  static long buflen,bufrit
  buflen=len bufout
  WriteFile ConsOut,strptr bufout,buflen,@bufrit,null
  End Function
  '
  Function printl(string s)
  =========================
  static long buflen,bufrit
  string bufout=s+cr
  buflen=len bufout
  WriteFile ConsOut,strptr bufout,buflen,@bufrit,null
  End Function

  Function printl()
  =================
  print cr
  end function

  Function print()
  ================
  print ""
  end function



  'function print(string s="") 'override
  '====================================
  'output s
  'end function

  'function printl(string s="")
  '===========================
  'output s cr
  'end function

  'macro print(s="") output s
  'macro printl(s="") output s cr

  'https://learn.microsoft.com/en-us/windows/console/input-record-str

  type KEY_RECORD
  ===============
    word EventType
    word wReserved
    '
    dword bKeyDown
    word wRepeatCount
    word wVirtualKeyCode
    word wScanCode
    word wAsciiCode
    dword dwReserved
  end type

  type MOUSE_RECORD
  =================
    word EventType
    word wReserved
    '
    COORD dwMousePosition
    dword dwButtonState
    dword dwControlKeyState
    dword dwEventFlags
  end type


  ! GetAsyncKeyState lib "user32.dll" (int c) as int
  '
  static KEY_RECORD   KeyRecord
  static MOUSE_RECORD MouseRecord

  'static int mode
  'GetConsoleMode ConsIn,mode '1f7

  int mouseB
  int mouseX
  int mouseY
  int ShiftKey   '0x10 VK_SHIFT
  int ControlKey '0x11 VK_CONTROL
  '
  function inkey(int c=0) as int
  ================================
  static  KEY_RECORD k[8]
  static *MOUSE_RECORD m
  @m=@k
  static int nr
  SetConsoleMode ConsIn,0x37
  int d
  PeekConsoleInputA ConsIn,@k,8, @nr
  if nr
    if c=0
      indexbase 1
      int i,t
      for i=1 to nr
        t=k[i].EventType
        if t=1 'KEY EVENT
          if k[i].bKeyDown
            KeyRecord=k[i]
            d=KeyRecord.wVirtualKeyCode
          endif
        elseif t=2 'MOUSE EVENT
          MouseRecord=m[i]
          mouseB=MouseRecord.dwButtonState
          mouseX=MouseRecord.dwMousePosition.x
          mouseY=MouseRecord.dwMousePosition.y
          d=mouseB and 3
        endif
      next
    elseif GetAsyncKeyState(c) and 0x8000 'c<>0
      d=c
    endif
    FlushConsoleInputBuffer ConsIn
    ShiftKey=GetAsyncKeyState(0x10)
    ControlKey=GetAsyncKeyState(0x11)
    if d=0x10 or d=0x11
      return 0
    endif
    return d   
  endif
  end function


  function GetKey(int c=0) as int
  ===============================
  int d
  do
    d=inkey(c)
    if d
      if c
        if d=c
          exit do
        endif
      else 'c=0
        exit do
      endif
    endif
  loop
  return d
  end function


