1. #include <iostream>
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include <conio.h>
  5. #include <stdlib.h>
  6. #include <string>
  7. #define BUFFERSIZE     80 * 25
  8. using namespace std;
  9.  
  10. /**
  11.  * Improved scrolly routine! Uses 80 columns by 25 rows
  12.  * in a Windows console, written in Code::Blocks, tested
  13.  * on Windows 7 Professional SP1
  14.  *
  15.  * @Author: Shaun B
  16.  * @Version: 1.0.0.2 - 2012-09-05
  17.  *
  18.  **/
  19.  
  20. int main();
  21. void ClrScr (short, short, short, short, signed char, char);
  22. void Print (short, short, signed char, char *, ...);
  23. void hideCursor();
  24. void scroll();
  25. void exchangeToDisplay();
  26.  
  27. static unsigned short counter;
  28. static unsigned short i;
  29. static char Erase[BUFFERSIZE];
  30. // Sets variables for:
  31. //  Scrolly message -
  32. static char scrolly [] = "....................This is a scrolly text....................Nah nah nah nah nahhhh....................Like a BAWS....................#\0";
  33. //  Display string -
  34. static char display [80];
  35. //  Keyboard input -
  36. static char character;
  37. //  Running boolean -
  38. static char run = 1;
  39. //  Sleep time -
  40. static signed int sleep = 100;
  41. //  Char buffer for scroll function -
  42. static char buffer[1];
  43. static HANDLE hStdout, hNewScreenBuffer;
  44. static SMALL_RECT srctReadRect;
  45. static SMALL_RECT srctWriteRect;
  46. static CHAR_INFO chiBuffer[BUFFERSIZE];
  47. static COORD coordBufSize = {0};
  48. static COORD coordBufCoord = {0};
  49. static BOOL fSuccess;
  50. static va_list List;
  51. static unsigned short FormattedStringLength;
  52.  
  53. int main ()
  54. {
  55.     // Sets default console size, colours and title:
  56.     system("mode CON: COLS=80 LINES=25");
  57.     system("title Scrolly started at %TIME% on %DATE%");
  58.     // Switches off blinking cursor:
  59.     SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_INSERT_MODE);
  60.     hideCursor();
  61.     // Clears screen from x, y to x1, y1, setting default colours and sending a space
  62.     ClrScr (0, 0, 25, 80, 0x12, 32);
  63.     // Sets up display string:
  64.     exchangeToDisplay();
  65.     // Main loop:
  66.     while(run)
  67.     {
  68.         // Printing the display string at 0, 0 with colours E and 3
  69.         Print (0, 0, 0xe3, display);
  70.         // Does the same for the bottom row of the console:
  71.         Print (24, 0, 0x90, display);
  72.         if (_kbhit())
  73.         {
  74.             character=_getch();
  75.         }
  76.         // Checks for space...
  77.         if(character==32)
  78.         {
  79.             // If so, stops main loop:
  80.             run=0;
  81.         }
  82.         // Checks for left arrow and arrow down...
  83.         if((character==75 || character==80) && sleep<255)
  84.         {
  85.             // Increases sleep call (higher is slower):
  86.             sleep+=10;
  87.         }
  88.         // Checks for other arrow keys...
  89.         if((character==72 || character==77) && sleep>0)
  90.         {
  91.             // Decreases sleep call:
  92.             sleep-=10;
  93.         }
  94.         // Clears character buffer if set:
  95.         if(character)
  96.         {
  97.             character=0;
  98.         }
  99.         // Checks if time exceeds longest sleep time:
  100.         if(sleep>254)
  101.         {
  102.             sleep=255;
  103.         }
  104.         // Checks if time exceeds shortest sleep time:
  105.         if(sleep<1)
  106.         {
  107.             sleep=0;
  108.         }
  109.         // Calls scroll function:
  110.         scroll();
  111.         // Calls sleep function:
  112.         Sleep(sleep+1);
  113.     }
  114.     system("cls");
  115.     std::cout<<"Goodbye!"<<endl;
  116.     // Returns when loop is exited:
  117.     return 0;
  118. }
  119.  
  120. void ClrScr (short x, short y, short NoOfLines, short EraseLength, signed char EraseColor, char ErasePattern)
  121. {
  122.     //Erase[BUFFERSIZE] = {0};
  123.     counter = NoOfLines * EraseLength;
  124.     for (i = 0; i < counter; i++)
  125.     {
  126.         Erase[i] = ErasePattern;
  127.     }
  128.     // Adds terminator (just in case)
  129.     if(Erase[i]!='\0')
  130.     {
  131.         Erase[i] = '\0';
  132.     }
  133.     Print (x, y, EraseColor, Erase);
  134. }
  135.  
  136. void Print (short x, short y, signed char Color, char *String, ...)
  137. {
  138.     FormattedStringLength = 0;
  139.     char FormattedString[BUFFERSIZE] = {0};
  140.     counter = 0;
  141.     unsigned char bottom = 0;
  142.  
  143.     hStdout =           GetStdHandle(STD_OUTPUT_HANDLE);
  144.     hNewScreenBuffer =  CreateConsoleScreenBuffer(
  145.                         GENERIC_READ |           // read/write access
  146.                         GENERIC_WRITE,
  147.                         0,                       // not shared
  148.                         NULL,                    // no security attributes
  149.                         CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE
  150.                         NULL);                   // reserved; must be NULL
  151.     va_start (List, String);
  152.     vsprintf (FormattedString, String, List);
  153.     FormattedStringLength = (unsigned short) strlen (FormattedString);
  154.     while(counter<FormattedStringLength)
  155.     {
  156.         counter++;
  157.         if(counter%80==0)
  158.         {
  159.             bottom++;
  160.         }
  161.     }
  162.     va_end (List);
  163.  
  164.     // Make the new screen buffer the active screen buffer.
  165.     // Set the source rectangle.
  166.     srctReadRect.Top = x;
  167.     srctReadRect.Left = y;
  168.     srctReadRect.Bottom = bottom;
  169.     srctReadRect.Right = 80;
  170.  
  171.     // The temporary buffer size is 25 rows x 80 columns.
  172.     coordBufSize.Y = bottom;
  173.     coordBufSize.X = 80;
  174.  
  175.     // The top left destination cell of the temporary buffer is
  176.     // row 0, col 0.
  177.     coordBufCoord.X = 0;
  178.     coordBufCoord.Y = 0;
  179.  
  180.     // Copy the block from the screen buffer to the temp. buffer.
  181.     fSuccess =  ReadConsoleOutput(
  182.                 hStdout,        // screen buffer to read from
  183.                 chiBuffer,      // buffer to copy into
  184.                 coordBufSize,   // col-row size of chiBuffer
  185.                 coordBufCoord,  // top left dest. cell in chiBuffer
  186.                 &srctReadRect); // screen buffer source rectangle
  187.    
  188.     // Set the destination rectangle.
  189.     srctWriteRect.Top = x;
  190.     srctWriteRect.Left = y;
  191.     srctWriteRect.Bottom = 25;
  192.     srctWriteRect.Right = 80;
  193.  
  194.     // Gets buffer information:
  195.     for (i = 0; i < BUFFERSIZE; i++)
  196.     {
  197.                 chiBuffer[i].Attributes = Color;
  198.         chiBuffer[i].Char.AsciiChar = FormattedString[i];
  199.     }
  200.     // Copy from the temporary buffer to the new screen buffer.
  201.     WriteConsoleOutput(
  202.         hStdout,      // screen buffer to write to
  203.         chiBuffer,        // buffer to copy from
  204.         coordBufSize,     // col-row size of chiBuffer
  205.         coordBufCoord,    // top left src cell in chiBuffer
  206.         &srctWriteRect);  // dest. screen buffer rectangle
  207. }
  208.  
  209. // Turns off blinking cursor:
  210. void hideCursor()
  211. {
  212.     CONSOLE_CURSOR_INFO lpCursor;
  213.     lpCursor.bVisible = 0;
  214.     lpCursor.dwSize = 20;
  215.     SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&lpCursor);
  216. }
  217.  
  218. void scroll()
  219. {
  220.     // Sets counter to zero:
  221.     counter=0;
  222.     // The buffer will preserve the first char otherwise the
  223.     // scrolling won't wrap around:
  224.     buffer[0]=scrolly[counter];
  225.     // Loop will happen whilst the terminator hasn't been reached:
  226.     while(scrolly[counter]!='#')
  227.     {
  228.         // Moves each character one element to the left:
  229.         scrolly[counter]=scrolly[counter+1];
  230.         // Increase our counter
  231.         counter++;
  232.     }
  233.     // Puts the old first character from the start to the end so
  234.     // it wraps around:
  235.     scrolly[counter-1]=buffer[0];
  236.     // Checks to see if the terminator has been over-written, if not
  237.     // then it's restored:
  238.     if(scrolly[counter]!='#')
  239.     {
  240.         scrolly[counter]='#';
  241.     }
  242.     exchangeToDisplay();
  243. }
  244.  
  245. void exchangeToDisplay()
  246. {
  247.     // Writes the first 80 characters of our [shuffled] scrolly text
  248.     // to our display string:
  249.     for(counter=0; counter<80;counter++)
  250.     {
  251.         display[counter] = scrolly[counter];
  252.     }
  253. }