winConsole.cpp

Engine/source/platformWin32/winConsole.cpp

More...

Namespaces:

namespace

This namespace contains the core of the console functionality.

Public Variables

Public Functions

DefineEngineFunction(enableWinConsole , void , (bool flag) , "enableWinConsole(bool);" )
winConsoleConsumer(U32 level, const char * line)

Detailed Description

Public Variables

WinConsole * WindowsConsole 

Public Functions

DefineEngineFunction(enableWinConsole , void , (bool flag) , "enableWinConsole(bool);" )

winConsoleConsumer(U32 level, const char * line)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "core/util/rawData.h"
 25#include "core/strings/stringFunctions.h"
 26#include "core/strings/unicode.h"
 27
 28#include "platformWin32/platformWin32.h"
 29#include "platformWin32/winConsole.h"
 30#include "console/consoleTypes.h"
 31#include "console/engineAPI.h"
 32#include "core/util/journal/process.h"
 33
 34
 35WinConsole *WindowsConsole = NULL;
 36
 37namespace Con
 38{
 39   extern bool alwaysUseDebugOutput;
 40}
 41
 42DefineEngineFunction( enableWinConsole, void, (bool flag), , "enableWinConsole(bool);")
 43{
 44   WindowsConsole->enable(flag);
 45}
 46
 47void WinConsole::create()
 48{
 49   if( !WindowsConsole )
 50      WindowsConsole = new WinConsole();
 51}
 52
 53void WinConsole::destroy()
 54{
 55   if( WindowsConsole )
 56      delete WindowsConsole;
 57   WindowsConsole = NULL;
 58}
 59
 60void WinConsole::enable(bool enabled)
 61{
 62   winConsoleEnabled = enabled;
 63   if(winConsoleEnabled)
 64   {
 65      AllocConsole();
 66      const char *title = Con::getVariable("Con::WindowTitle");
 67      if (title && *title)
 68      {
 69#ifdef UNICODE
 70         UTF16 buf[512];
 71         convertUTF8toUTF16((UTF8 *)title, buf);
 72         SetConsoleTitle(buf);
 73#else
 74         SetConsoleTitle(title);
 75#endif
 76      }
 77      stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
 78      stdIn  = GetStdHandle(STD_INPUT_HANDLE);
 79      stdErr = GetStdHandle(STD_ERROR_HANDLE);
 80
 81      printf("%s", Con::getVariable("Con::Prompt"));
 82   }
 83}
 84
 85bool WinConsole::isEnabled()
 86{
 87   if ( WindowsConsole )
 88      return WindowsConsole->winConsoleEnabled;
 89
 90   return false;
 91}
 92
 93static void winConsoleConsumer(U32 level, const char *line)
 94{
 95   if (WindowsConsole)
 96   {
 97      WindowsConsole->processConsoleLine(line);
 98#ifndef TORQUE_SHIPPING
 99      // see console.cpp for a description of Con::alwaysUseDebugOutput
100      if( level == ConsoleLogEntry::Error  || Con::alwaysUseDebugOutput)
101      {
102         // [rene, 04/05/2008] This is incorrect.  Should do conversion from UTF8 here.
103         //    Skipping for the sake of speed.  Not meant to be seen by user anyway.
104         OutputDebugStringA( line );
105         OutputDebugStringA( "\n" );
106      }
107#endif
108   }
109}
110
111WinConsole::WinConsole()
112{
113   for (S32 iIndex = 0; iIndex < MAX_CMDS; iIndex ++)
114      rgCmds[iIndex][0] = '\0';
115
116   iCmdIndex = 0;
117   winConsoleEnabled = false;
118   Con::addConsumer(winConsoleConsumer);
119   inpos = 0;
120   lineOutput = false;
121
122   Process::notify(this, &WinConsole::process, PROCESS_LAST_ORDER);
123}
124
125WinConsole::~WinConsole()
126{
127   Process::remove(this, &WinConsole::process);
128   Con::removeConsumer(winConsoleConsumer);
129}
130
131void WinConsole::printf(const char *s, ...)
132{
133   // Get the line into a buffer.
134   static const S32 BufSize = 4096;
135   static char buffer[4096];
136   DWORD bytes;
137   va_list args;
138   va_start(args, s);
139   _vsnprintf(buffer, BufSize, s, args);
140   // Replace tabs with carats, like the "real" console does.
141   char *pos = buffer;
142   while (*pos) {
143      if (*pos == '\t') {
144         *pos = '^';
145      }
146      pos++;
147   }
148   // Axe the color characters.
149   Con::stripColorChars(buffer);
150   // Print it.
151   WriteFile(stdOut, buffer, strlen(buffer), &bytes, NULL);
152   FlushFileBuffers( stdOut );
153}
154
155void WinConsole::processConsoleLine(const char *consoleLine)
156{
157   if(winConsoleEnabled)
158   {
159      inbuf[inpos] = 0;
160      if(lineOutput)
161         printf("%s\n", consoleLine);
162      else
163         printf("%c%s\n%s%s", '\r', consoleLine, Con::getVariable("Con::Prompt"), inbuf);
164   }
165}
166
167void WinConsole::process()
168{
169   if(winConsoleEnabled)
170   {
171      DWORD numEvents;
172      GetNumberOfConsoleInputEvents(stdIn, &numEvents);
173      if(numEvents)
174      {
175         INPUT_RECORD rec[20];
176         char outbuf[512];
177         S32 outpos = 0;
178
179         ReadConsoleInput(stdIn, rec, 20, &numEvents);
180         DWORD evt;
181         for(evt = 0; evt < numEvents; evt++)
182         {
183            if(rec[evt].EventType == KEY_EVENT)
184            {
185               KEY_EVENT_RECORD *ke = &(rec[evt].Event.KeyEvent);
186               if(ke->bKeyDown)
187               {
188                  switch (ke->uChar.AsciiChar)
189                  {
190                     // If no ASCII char, check if it's a handled virtual key
191                     case 0:
192                        switch (ke->wVirtualKeyCode)
193                        {
194                           // UP ARROW
195                           case 0x26 :
196                              // Go to the previous command in the cyclic array
197                              if ((-- iCmdIndex) < 0)
198                                 iCmdIndex = MAX_CMDS - 1;
199
200                              // If this command isn't empty ...
201                              if (rgCmds[iCmdIndex][0] != '\0')
202                              {
203                                 // Obliterate current displayed text
204                                 for (S32 i = outpos = 0; i < inpos; i ++)
205                                 {
206                                    outbuf[outpos ++] = '\b';
207                                    outbuf[outpos ++] = ' ';
208                                    outbuf[outpos ++] = '\b';
209                                 }
210
211                                 // Copy command into command and display buffers
212                                 for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos ++, outpos ++)
213                                 {
214                                    outbuf[outpos] = rgCmds[iCmdIndex][inpos];
215                                    inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
216                                 }
217                              }
218                              // If previous is empty, stay on current command
219                              else if ((++ iCmdIndex) >= MAX_CMDS)
220                              {
221                                 iCmdIndex = 0;
222                              }
223
224                              break;
225
226                           // DOWN ARROW
227                           case 0x28 : {
228                              // Go to the next command in the command array, if
229                              // it isn't empty
230                              if (rgCmds[iCmdIndex][0] != '\0' && (++ iCmdIndex) >= MAX_CMDS)
231                                  iCmdIndex = 0;
232
233                              // Obliterate current displayed text
234                              for (S32 i = outpos = 0; i < inpos; i ++)
235                              {
236                                 outbuf[outpos ++] = '\b';
237                                 outbuf[outpos ++] = ' ';
238                                 outbuf[outpos ++] = '\b';
239                              }
240
241                              // Copy command into command and display buffers
242                              for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos ++, outpos ++)
243                              {
244                                 outbuf[outpos] = rgCmds[iCmdIndex][inpos];
245                                 inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
246                              }
247                              }
248                              break;
249
250                           // LEFT ARROW
251                           case 0x25 :
252                              break;
253
254                           // RIGHT ARROW
255                           case 0x27 :
256                              break;
257
258                           default :
259                              break;
260                        }
261                        break;
262                     case '\b':
263                        if(inpos > 0)
264                        {
265                           outbuf[outpos++] = '\b';
266                           outbuf[outpos++] = ' ';
267                           outbuf[outpos++] = '\b';
268                           inpos--;
269                        }
270                        break;
271                     case '\t':
272                        // In the output buffer, we're going to have to erase the current line (in case
273                        // we're cycling through various completions) and write out the whole input
274                        // buffer, so (inpos * 3) + complen <= 512.  Should be OK.  The input buffer is
275                        // also 512 chars long so that constraint will also be fine for the input buffer.
276                        {
277                           // Erase the current line.
278                           U32 i;
279                           for (i = 0; i < inpos; i++) {
280                              outbuf[outpos++] = '\b';
281                              outbuf[outpos++] = ' ';
282                              outbuf[outpos++] = '\b';
283                           }
284                           // Modify the input buffer with the completion.
285                           U32 maxlen = 512 - (inpos * 3);
286                           if (ke->dwControlKeyState & SHIFT_PRESSED) {
287                              inpos = Con::tabComplete(inbuf, inpos, maxlen, false);
288                           }
289                           else {
290                              inpos = Con::tabComplete(inbuf, inpos, maxlen, true);
291                           }
292                           // Copy the input buffer to the output.
293                           for (i = 0; i < inpos; i++) {
294                              outbuf[outpos++] = inbuf[i];
295                           }
296                        }
297                        break;
298                     case '\n':
299                     case '\r':
300                        outbuf[outpos++] = '\r';
301                        outbuf[outpos++] = '\n';
302
303                        inbuf[inpos] = 0;
304                        outbuf[outpos] = 0;
305                        printf("%s", outbuf);
306
307                        // Pass the line along to the console for execution.
308                        {
309                           RawData rd;
310                           rd.size = inpos + 1;
311                           rd.data = ( S8* ) inbuf;
312
313                           Con::smConsoleInput.trigger(rd);
314                        }
315
316                        // If we've gone off the end of our array, wrap
317                        // back to the beginning
318                        if (iCmdIndex >= MAX_CMDS)
319                            iCmdIndex %= MAX_CMDS;
320
321                        // Put the new command into the array
322                        strcpy(rgCmds[iCmdIndex ++], inbuf);
323
324                        printf("%s", Con::getVariable("Con::Prompt"));
325                        inpos = outpos = 0;
326                        break;
327                     default:
328                        inbuf[inpos++] = ke->uChar.AsciiChar;
329                        outbuf[outpos++] = ke->uChar.AsciiChar;
330                        break;
331                  }
332               }
333            }
334         }
335         if(outpos)
336         {
337            outbuf[outpos] = 0;
338            printf("%s", outbuf);
339         }
340      }
341   }
342}
343