24 #include <QApplication>
28 #include <QGridLayout>
29 #include <QPaintEvent>
31 #include <QResizeEvent>
38 #include <QMessageBox>
39 #include <QDragEnterEvent>
47 #define WIN32_LEAN_AND_MEAN
48 #if ! defined (_WIN32_WINNT) && ! defined (NTDDI_VERSION)
49 #define _WIN32_WINNT 0x0500
61 #define LOGFILENAME "QConsole.log"
63 #define HIDDEN_CONSOLE
66 # pragma warning(disable : 4996)
104 QString esc =
"\x1b";
107 if (ev->key () == Qt::Key_Delete)
109 else if (!ev->text ().isEmpty ())
148 case Qt::Key_PageDown:
196 void log (
const char* fmt, ...);
200 const char* devName);
215 void setCursorColor (
bool useForegroundColor,
const QColor& color);
221 void drawSelection (QPainter& p,
int cx1,
int cy1,
int cx2,
int cy2,
226 void drawText (QPainter& p,
int cx1,
int cy1,
int cx2,
int cy2,
273 if (end.y () < begin.y ()
274 || (end.y () == begin.y () && end.x () < begin.x ()))
281 : q (parent), m_command (cmd), m_cursorBlinking (false),
282 m_hasBlinkingCursor (true), m_cursorType (
BlockCursor),
283 m_beginSelection (0, 0), m_endSelection (0, 0), m_settingSelection (false),
284 m_process (NULL), m_inWheelEvent (false)
289 log (
"Detaching from existing console (if any)...\n");
291 log (
"Closing standard IO...\n");
296 #ifdef HIDDEN_CONSOLE
297 HWINSTA hOrigSta, hNewSta;
300 hOrigSta = GetProcessWindowStation ();
301 hNewSta = CreateWindowStation (NULL, 0, GENERIC_ALL, NULL);
302 log (
"Current Windows station: %p.\nNew Windows station: %p.\n", hOrigSta,
304 if (! SetProcessWindowStation (hNewSta))
305 log (
"Failed to switch to new Windows station.\n");
307 if (! AllocConsole ())
308 log (
"Failed to create new console.\n");
309 #ifdef HIDDEN_CONSOLE
310 if (! SetProcessWindowStation (hOrigSta))
311 log (
"Failed to restore original Windows station.\n");
312 if (! CloseWindowStation (hNewSta))
313 log (
"Failed to close new Windows station.\n");
316 log (
"New (hidden) console created.\n");
322 log (
"Standard input/output/error set up.\n");
324 *stdin = *(fdopen (0,
"rb"));
325 *stdout = *(fdopen (1,
"wb"));
326 *stderr = *(fdopen (2,
"wb"));
328 log (
"POSIX standard streams created.\n");
330 setvbuf (stdin, NULL, _IONBF, 0);
331 setvbuf (stdout, NULL, _IONBF, 0);
332 setvbuf (stderr, NULL, _IONBF, 0);
334 log (
"POSIX standard stream buffers adjusted.\n");
336 HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
338 log (
"Console allocated: hStdOut: %p\n", hStdOut);
344 #ifdef HIDDEN_CONSOLE
348 CONSOLE_SCREEN_BUFFER_INFO sbi;
350 GetConsoleScreenBufferInfo (hStdOut, &sbi);
351 m_bufferSize = QSize (sbi.dwSize.X, qMax (sbi.dwSize.Y, (SHORT)500));
353 sbi.srWindow.Right - sbi.srWindow.Left + 1,
354 sbi.srWindow.Bottom - sbi.srWindow.Top + 1);
355 m_cursorPos = QPoint (sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y);
357 log (
"Initial console parameters:\n");
360 log (
" window: (%d, %d) -> (%d, %d) [%d x %d]\n",
365 wchar_t titleBuf[260];
366 GetConsoleTitleW (titleBuf,
sizeof (titleBuf));
367 q->setWindowTitle (QString::fromWCharArray (titleBuf));
369 m_font.setFamily (
"Lucida Console");
371 m_font.setStyleHint (QFont::TypeWriter);
379 QGridLayout* l =
new QGridLayout (parent);
380 l->setContentsMargins (0, 0, 0, 0);
392 SetConsoleTextAttribute (
m_stdOut, 0xF0);
407 parent->setFocusPolicy (Qt::StrongFocus);
461 const char* name,
const char* devName)
463 log (
"Opening %s...\n", devName);
465 int fd = open (devName, _O_RDWR | _O_BINARY);
471 log (
"Opened %s is not at target file descriptor %d, "
472 "duplicating...\n", name, targetFd);
473 if (dup2 (fd, targetFd) == -1)
474 log (
"Failed to duplicate file descriptor: errno=%d.\n", errno);
475 if (close (fd) == -1)
476 log (
"Failed to close original file descriptor: errno=%d.\n",
480 log (
"%s opened and assigned to file descriptor %d.\n", devName, fd);
481 if (! SetStdHandle (stdHandleId, (HANDLE) _get_osfhandle (targetFd)))
482 log (
"Failed to re-assign %s: error=%08x.\n", name, GetLastError ());
485 log (
"Failed to open %s: errno=%d.\n", devName, errno);
506 COORD bufSize, bufCoord;
510 nr = end.y () - begin.y () + 1;
519 bufRect.Top = begin.y ();
520 bufRect.Bottom = end.y ();
522 if (ReadConsoleOutput (
m_stdOut, buf, bufSize, bufCoord, &bufRect))
524 int start_pos = begin.x ();
525 int end_pos = (nr - 1) *
m_bufferSize.width () + end.x ();
526 int lastNonSpace = -1;
528 for (
int i = start_pos; i <= end_pos; i++)
532 if (lastNonSpace >= 0)
533 selection.truncate (lastNonSpace);
534 selection.append (
'\n');
535 lastNonSpace = selection.length ();
538 QChar c (buf[i].Char.UnicodeChar);
540 selection.append (c);
542 lastNonSpace = selection.length ();
545 if (lastNonSpace >= 0)
546 selection.truncate (lastNonSpace);
597 QPalette palette (color);
619 CONSOLE_SCREEN_BUFFER_INFO sbi;
620 GetConsoleScreenBufferInfo (
m_stdOut, &sbi);
628 int cx2,
int cy2,
int cw,
int ch)
632 int ascent = p.fontMetrics ().ascent ();
634 int y = ascent + cy1 * ch;;
636 for (
int j = cy1; j <= cy2; j++, y += ch)
639 bool hasChar =
false;
643 for (
int i = cx1; i <= cx2; i++)
645 CHAR_INFO* ci = &(
m_buffer[stride*j+i]);
647 if ((ci->Attributes & 0x00ff) != attr)
653 if (hasChar || (attr & 0x00f0))
656 p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
664 attr = (ci->Attributes & 0x00ff);
665 p.setBrush (
m_colors[(attr >> 4) & 0x000f]);
670 if (ci->Char.UnicodeChar != L
' ')
674 if (len != 0 && (hasChar || (attr & 0x00f0)))
681 p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
698 QPoint begin = cellpos;
699 QPoint end = cellpos;
707 begin.ry () -= verticalScrollOffset;
708 end.ry () -= verticalScrollOffset;
710 begin.rx () -= horizontalScrollOffset;
711 end.rx () -= horizontalScrollOffset;
714 if (QChar(
m_buffer[begin.y ()*stride + begin.x ()].Char.UnicodeChar).isSpace () ==
false)
717 while(begin.x () > 0 &&
718 QChar(
m_buffer[begin.y ()*stride + begin.x () -1].Char.UnicodeChar).isSpace() ==
false)
724 QChar(
m_buffer[end.y ()*stride + end.x () +1].Char.UnicodeChar).isSpace() ==
false)
731 while(begin.x () > 0 &&
732 QChar(
m_buffer[begin.y ()*stride + begin.x () -1].Char.UnicodeChar).isSpace())
738 QChar(
m_buffer[end.y ()*stride + end.x () +1].Char.UnicodeChar).isSpace ())
745 begin.ry () += verticalScrollOffset;
746 end.ry () += verticalScrollOffset;
748 begin.rx () += horizontalScrollOffset;
749 end.rx () += horizontalScrollOffset;
766 int cx2,
int cy2,
int cw,
int ch)
773 bool haveSelection = (begin != end);
781 begin.ry () -= verticalScrollOffset;
782 end.ry () -= verticalScrollOffset;
784 begin.rx () -= horizontalScrollOffset;
785 end.rx () -= horizontalScrollOffset;
787 int ascent = p.fontMetrics ().ascent ();
790 int y = ascent + cy1 * ch;;
791 for (
int j = cy1; j <= cy2; j++, y += ch)
793 int charsThisLine = 0;
795 bool hasChar =
false;
798 for (
int i = cx1; i <= cx2; i++)
800 CHAR_INFO* ci = &(
m_buffer[stride*j+i]);
802 if ((ci->Attributes & 0x00ff) != attr)
807 charsThisLine += len;
813 attr = (ci->Attributes & 0x00ff);
818 if (ci->Char.UnicodeChar != L
' ')
822 if (len != 0 && (hasChar || (attr & 0x00f0)))
823 charsThisLine += len;
825 if (haveSelection && j >= begin.y () && j <= end.y ())
827 int selectionBegin = j == begin.y () ? begin.x (): 0;
829 int len = ((j == end.y () && end.x () < charsThisLine)
830 ? end.x () - selectionBegin + 1
831 : stride - selectionBegin);
833 p.fillRect (selectionBegin * cw, y-ascent, len * cw, ch,
855 p.fillRect (rect, color);
861 int penWidth = qMax (1, p.pen().width());
863 p.drawRect (rect.adjusted (penWidth/2, penWidth/2,
864 - penWidth/2 - penWidth%2,
865 - penWidth/2 - penWidth%2));
870 p.drawLine (rect.left (), rect.bottom (),
871 rect.right (), rect.bottom ());
875 p.drawLine (rect.left (), rect.top (),
876 rect.left (), rect.bottom ());
884 int cx2,
int cy2,
int cw,
int ch)
892 s.reserve (cx2 - cx1 + 1);
894 int ascent = p.fontMetrics ().ascent ();
897 int y = ascent + cy1 * ch;;
898 for (
int j = cy1; j <= cy2; j++, y += ch)
902 bool hasChar =
false;
906 for (
int i = cx1; i <= cx2; i++)
908 CHAR_INFO* ci = &(
m_buffer[stride*j+i]);
910 if ((ci->Attributes & 0x00ff) != attr)
916 if (hasChar || (attr & 0x00f0))
917 p.drawText (x, y, s);
919 x += (s.length () * cw);
924 attr = (ci->Attributes & 0x00ff);
929 s.append (ci->Char.UnicodeChar);
930 if (ci->Char.UnicodeChar != L
' ')
934 if (! s.isEmpty () && (hasChar || (attr & 0x00f0)))
940 p.drawText (x, y, s);
952 if (close (fd) == -1)
953 log (
"Failed to close file descriptor %d: errno=%d.\n", fd, errno);
954 if (! CloseHandle (GetStdHandle (stdHandleId)))
955 log (
"Failed to close Win32 %s: error=%08x.\n", name, GetLastError ());
962 #ifdef DEBUG_QCONSOLE
969 vfprintf (flog, fmt, l);
991 m_charSize.rwidth () = fm.averageCharWidth ();
994 m_consoleRect.setWidth (winSize.width () / fm.averageCharWidth ());
995 m_consoleRect.setHeight (winSize.height () / fm.lineSpacing ());
1014 qputenv (
"LINES", QByteArray::number (
m_consoleRect.height ()));
1015 qputenv (
"COLUMNS", QByteArray::number (
m_consoleRect.width ()));
1026 log (
"Console resized:\n");
1027 log (
" widget size: %d x %d\n", winSize.width (), winSize.height ());
1030 log (
" window: (%d, %d) -> (%d, %d) [%d x %d]\n",
1046 CONSOLE_SCREEN_BUFFER_INFO sbi;
1049 GetConsoleScreenBufferInfo (hStdOut, &sbi);
1054 bs.X = sbi.dwSize.X;
1056 sr.Left = sbi.srWindow.Left;
1057 sr.Right = sbi.srWindow.Right;
1061 if (bs.Y > sbi.dwSize.Y)
1063 SetConsoleScreenBufferSize (hStdOut, bs);
1064 SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1068 SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1069 SetConsoleScreenBufferSize (hStdOut, bs);
1076 if (bs.X > sbi.dwSize.X)
1078 SetConsoleScreenBufferSize (hStdOut, bs);
1079 SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1083 SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1084 SetConsoleScreenBufferSize (hStdOut, bs);
1087 log (
"Sync'ing console parameters:\n");
1088 log (
" buffer size: %d x %d\n", bs.X, bs.Y);
1089 log (
" window: (%d, %d) -> (%d, %d)\n",
1090 sr.Left, sr.Top, sr.Right, sr.Bottom);
1121 qCritical (
"cannot read console output");
1137 log (
"Horizontal scrollbar parameters updated: %d/%d/%d/%d\n",
1155 log (
"Vertical scrollbar parameters updated: %d/%d/%d/%d\n",
1178 log (
"Scrolling window horizontally: (%d, %d) -> (%d, %d) [%d x %d]\n",
1179 r.Left, r.Top, r.Right, r.Bottom,
1180 r.Right - r.Left + 1, r.Bottom - r.Top + 1);
1182 if (SetConsoleWindowInfo (hStdOut, TRUE, &r))
1205 log (
"Scrolling window vertically: (%d, %d) -> (%d, %d) [%d x %d]\n",
1206 r.Left, r.Top, r.Right, r.Bottom,
1207 r.Right - r.Left + 1, r.Bottom - r.Top + 1);
1209 if (SetConsoleWindowInfo (hStdOut, TRUE, &r))
1230 CONSOLE_SCREEN_BUFFER_INFO sbi;
1231 HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
1233 static wchar_t titleBuf[260];
1235 GetConsoleTitleW (titleBuf,
sizeof (titleBuf));
1236 QString title = QString::fromWCharArray (titleBuf);
1240 q->setWindowTitle (title);
1244 if (GetConsoleScreenBufferInfo (hStdOut, &sbi))
1279 sbi.srWindow.Right - sbi.srWindow.Left + 1,
1280 sbi.srWindow.Bottom - sbi.srWindow.Top + 1);
1310 cmd = qgetenv (
"COMSPEC").constData ();
1312 if (! cmd.isEmpty ())
1315 PROCESS_INFORMATION pi;
1317 ZeroMemory (&si,
sizeof (si));
1318 si.cb =
sizeof (si);
1319 ZeroMemory (&pi,
sizeof (pi));
1321 if (CreateProcessW (NULL,
1322 (LPWSTR)cmd.unicode (),
1332 CloseHandle (pi.hThread);
1348 #define TEXT_CHUNK_SIZE 512
1353 int len = s.length ();
1355 DWORD nEvents = 0, written;
1356 HANDLE hStdIn = GetStdHandle (STD_INPUT_HANDLE);
1358 ZeroMemory (events,
sizeof (events));
1360 for (
int i = 0; i < len; i++)
1364 if (c == L
'\r' || c == L
'\n')
1366 if (c == L
'\r' && i < (len - 1) && s.at (i+1) == L
'\n')
1370 events[nEvents].EventType = KEY_EVENT;
1371 events[nEvents].Event.KeyEvent.bKeyDown = TRUE;
1372 events[nEvents].Event.KeyEvent.wRepeatCount = 1;
1373 events[nEvents].Event.KeyEvent.wVirtualKeyCode =
1375 events[nEvents].Event.KeyEvent.wVirtualScanCode = 0;
1376 events[nEvents].Event.KeyEvent.uChar.UnicodeChar = c.unicode ();
1377 events[nEvents].Event.KeyEvent.dwControlKeyState = 0;
1380 WriteConsoleInput (hStdIn, events, nEvents, &written);
1382 ZeroMemory (events,
sizeof (events));
1387 events[nEvents].EventType = KEY_EVENT;
1388 events[nEvents].Event.KeyEvent.bKeyDown = TRUE;
1389 events[nEvents].Event.KeyEvent.wRepeatCount = 1;
1390 events[nEvents].Event.KeyEvent.wVirtualKeyCode =
1391 LOBYTE (VkKeyScan (c.unicode ()));
1392 events[nEvents].Event.KeyEvent.wVirtualScanCode = 0;
1393 events[nEvents].Event.KeyEvent.uChar.UnicodeChar = c.unicode ();
1394 events[nEvents].Event.KeyEvent.dwControlKeyState = 0;
1399 || (nEvents > 0 && i == (len - 1)))
1401 WriteConsoleInput (hStdIn, events, nEvents, &written);
1403 ZeroMemory (events,
sizeof (events));
1425 installEventFilter (
this);
1433 parent, SLOT (set_screen_size (
int,
int)));
1435 setAcceptDrops (
true);
1468 else if (event->button () == Qt::LeftButton)
1490 if (event->button () == Qt::LeftButton)
1499 QTimer::singleShot (QApplication::doubleClickInterval (),
this,
1507 if (event->button () == Qt::LeftButton)
1535 QRect updateRect =
event->rect ();
1537 int cx1 = updateRect.left () / cw;
1538 int cy1 = updateRect.top () / ch;
1539 int cx2 = qMin (
d->
m_consoleRect.width () - 1, updateRect.right () / cw);
1540 int cy2 = qMin (
d->
m_consoleRect.height () - 1, updateRect.bottom () / ch);
1549 d->
drawText (p, cx1, cy1, cx2, cy2, cw, ch);
1635 QWidget::focusInEvent (event);
1647 QWidget::focusOutEvent (event);
1654 if (event->type () == QEvent::KeyPress)
1656 QKeyEvent* k =
static_cast<QKeyEvent*
>(event);
1657 if (k->key () == Qt::Key_Tab)
1680 QWidget::keyPressEvent (event);
1733 const QColor& color)
1757 d->
log (
"emit set_screen_size_signal (%d, %d)\n", columns, lines);
1766 if(!hasFocus())
return;
1768 QClipboard *clipboard = QApplication::clipboard ();
1772 if (selection.isEmpty ())
1779 clipboard->setText (selection);
1788 if(!hasFocus())
return;
1790 QString
text = QApplication::clipboard()->
text (QClipboard::Clipboard);
1792 if (! text.isEmpty ())
1800 if(!hasFocus())
return;
1819 if (event->mimeData ()->hasUrls ())
1821 event->acceptProposedAction();
1831 if (event->mimeData ()->hasUrls ())
1833 foreach (QUrl url, event->mimeData ()->urls ())
1835 if(dropText.length () > 0)
1837 dropText += url.toLocalFile ();
QScrollBar * m_verticalScrollBar
QConsoleView * m_consoleView
void horizontalScrollValueChanged(int value)
void resizeEvent(QResizeEvent *event)
void setScrollBufferSize(int value)
void setBlinkingCursor(bool blink)
QConsoleThread * m_consoleThread
void updateHorizontalScrollBar(void)
void log(const char *fmt,...)
void focusOutEvent(QFocusEvent *)
friend class QConsoleView
void drawSelection(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
void setCursorType(CursorType type, bool blinking)
void selectWord(const QPoint &cellPos)
void tripleClickTimeout(void)
void terminal_interrupt(void)
void updateConsoleView(bool grab=true)
QConsolePrivate(QWinTerminalImpl *parent, const QString &cmd=QString())
void set_global_shortcuts_signal(bool)
void titleChanged(const QString &)
void monitorConsole(void)
void syncConsoleParameters(void)
void updateSelection(void)
QColor backgroundColor(void) const
friend class QConsoleThread
void closeStandardIO(int fd, DWORD stdHandleId, const char *name)
F77_RET_T const double const double double * d
void updateConsoleSize(bool sync=false, bool allow_smaller_width=false)
void monitorConsole(void)
void init_terminal_size(void)
void sendConsoleText(const QString &s)
void grabConsoleBuffer(CHAR_INFO *buf=0)
void setCursorColor(bool useForegoundColor, const QColor &color)
void setSelectionColor(const QColor &color)
F77_RET_T const double const double * f
QTimer * m_consoleWatcher
void report_status_message(const QString &)
void set_global_shortcuts(bool focus_out)
static const int BLINK_DELAY
text(const graphics_handle &mh, const graphics_handle &p)
void verticalScrollValueChanged(int value)
std::complex< double > w(std::complex< double > z, double relerr=0)
QString getSelection(void)
void clearSelection(void)
QConsoleView(QWinTerminalImpl *parent=0)
void setHorizontalScrollValue(int value)
void setForegroundColor(const QColor &color)
QColor foregroundColor(void) const
void mouseReleaseEvent(QMouseEvent *event)
void keyPressEvent(QKeyEvent *)
static QString translateKey(QKeyEvent *ev)
void setScrollBufferSize(int value)
void sendText(const QString &s)
QColor selectionColor(void) const
void paintEvent(QPaintEvent *event)
void mouseTripleClickEvent(QMouseEvent *event)
void focusInEvent(QFocusEvent *)
void set_screen_size_signal(int, int)
QPoint posToCell(const QPoint &pt)
void setSize(int columns, int lines)
void setBackgroundColor(const QColor &color)
void setBackgroundColor(const QColor &color)
void has_extra_interrupt(bool)
void setBlinkingCursorState(bool blink)
void viewPaintEvent(QConsoleView *, QPaintEvent *)
QColor cursorColor(void) const
void dropEvent(QDropEvent *event)
void drawTextBackground(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
void setTerminalFont(const QFont &font)
void viewResizeEvent(QConsoleView *, QResizeEvent *)
bool eventFilter(QObject *obj, QEvent *ev)
void setForegroundColor(const QColor &color)
QWinTerminalImpl(QWidget *parent=0)
void pasteClipboard(void)
void dragEnterEvent(QDragEnterEvent *event)
void mouseMoveEvent(QMouseEvent *event)
void drawText(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
QConsoleThread(QWinTerminalImpl *console)
void setVerticalScrollValue(int value)
void setSelectionColor(const QColor &color)
void mouseDoubleClickEvent(QMouseEvent *event)
void mousePressEvent(QMouseEvent *event)
static void maybeSwapPoints(QPoint &begin, QPoint &end)
void updateSelection(void)
void wheelEvent(QWheelEvent *)
void updateVerticalScrollBar(void)
KeyboardCursorType m_cursorType
void drawCursor(QPainter &p)
void selectLine(const QPoint &cellPos)
void setCursorColor(bool useForegroundColor, const QColor &color)
void setupStandardIO(DWORD stdHandleId, int fd, const char *name, const char *devName)
F77_RET_T const double * x
QTimer * m_blinkCursorTimer
QScrollBar * m_horizontalScrollBar
void blinkCursorEvent(void)