From 21543141ddb5ffd4a6f8e11254ca9015fef36a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 19 Apr 2009 20:59:08 +0000 Subject: [PATCH] * Applied slightly changed patch by Olivier that adds basic xterm style mouse support, thanks! * This probably closes bug #2854, confirmation pending. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30268 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/terminal/TermConst.h | 1 + src/apps/terminal/TermParse.cpp | 105 +++++++++++------- src/apps/terminal/TermView.cpp | 153 +++++++++++++++++++-------- src/apps/terminal/TermView.h | 4 + src/apps/terminal/TerminalBuffer.cpp | 11 ++ src/apps/terminal/TerminalBuffer.h | 2 + 6 files changed, 192 insertions(+), 84 deletions(-) diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index e201e92d19..4b9214cd84 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -91,6 +91,7 @@ const uint32 MSG_REMOVE_RESIZE_VIEW_IF_NEEDED = 'rmrv'; const uint32 MSG_TERMINAL_BUFFER_CHANGED = 'bufc'; const uint32 MSG_SET_TERMNAL_TITLE = 'sett'; const uint32 MSG_QUIT_TERMNAL = 'qutt'; +const uint32 MSG_REPORT_ANY_MOUSE_EVENT = 'mous'; // Preference Read/Write Keys const char* const PREF_HALF_FONT_FAMILY = "Half Font Family"; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index f4647429b4..cebac0f0af 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -1,9 +1,12 @@ /* - * Copyright 2001-2007, Haiku, Inc. + * Copyright 2001-2009, Haiku, Inc. * Copyright (c) 2003-4 Kian Duffy - * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. + * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. * Distributed under the terms of the MIT license. */ + +//! Escape sequence parse and character encoding. + #include "TermParse.h" #include @@ -23,25 +26,19 @@ #include "VTparse.h" -////////////////////////////////////////////////////////////////////////////// -// EscParse ... Escape sequence parse and character encoding. -// -////////////////////////////////////////////////////////////////////////////// - - extern int gUTF8GroundTable[]; /* UTF8 Ground table */ extern int gCS96GroundTable[]; /* CS96 Ground table */ extern int gISO8859GroundTable[]; /* ISO8859 & EUC Ground table */ extern int gSJISGroundTable[]; /* Shift-JIS Ground table */ -extern int gEscTable[]; /* ESC */ -extern int gCsiTable[]; /* ESC [ */ -extern int gDecTable[]; /* ESC [ ? */ -extern int gScrTable[]; /* ESC # */ -extern int gIgnoreTable[]; /* ignore table */ -extern int gIesTable[]; /* ignore ESC table */ +extern int gEscTable[]; /* ESC */ +extern int gCsiTable[]; /* ESC [ */ +extern int gDecTable[]; /* ESC [ ? */ +extern int gScrTable[]; /* ESC # */ +extern int gIgnoreTable[]; /* ignore table */ +extern int gIesTable[]; /* ignore ESC table */ extern int gEscIgnoreTable[]; /* ESC ignore table */ -extern int gMbcsTable[]; /* ESC $ */ +extern int gMbcsTable[]; /* ESC $ */ @@ -101,7 +98,7 @@ TermParse::StartThreads(TerminalBuffer *buffer) status_t status = InitPtyReader(); if (status < B_OK) { - fBuffer = NULL; + fBuffer = NULL; return status; } @@ -109,9 +106,9 @@ TermParse::StartThreads(TerminalBuffer *buffer) if (status < B_OK) { StopPtyReader(); fBuffer = NULL; - return status; + return status; } - + return B_OK; } @@ -126,9 +123,9 @@ TermParse::StopThreads() StopPtyReader(); StopTermParse(); - + fBuffer = NULL; - + return B_OK; } @@ -144,7 +141,7 @@ TermParse::InitTermParse() B_DISPLAY_PRIORITY, this); resume_thread(fParseThread); - + return B_OK; } @@ -164,7 +161,7 @@ TermParse::InitPtyReader() if (fReaderLocker < 0) { delete_sem(fReaderSem); fReaderSem = -1; - return fReaderLocker; + return fReaderLocker; } fReaderThread = spawn_thread(_ptyreader_thread, "PtyReader", @@ -174,8 +171,8 @@ TermParse::InitPtyReader() fReaderSem = -1; delete_sem(fReaderLocker); fReaderLocker = -1; - return fReaderThread; - } + return fReaderThread; + } resume_thread(fReaderThread); @@ -189,7 +186,7 @@ TermParse::StopTermParse() if (fParseThread >= 0) { status_t dummy; wait_for_thread(fParseThread, &dummy); - fParseThread = -1; + fParseThread = -1; } } @@ -201,7 +198,7 @@ TermParse::StopPtyReader() delete_sem(fReaderSem); fReaderSem = -1; } - if (fReaderLocker >= 0) { + if (fReaderLocker >= 0) { delete_sem(fReaderLocker); fReaderLocker = -1; } @@ -212,7 +209,7 @@ TermParse::StopPtyReader() status_t status; wait_for_thread(fReaderThread, &status); - fReaderThread = -1; + fReaderThread = -1; } } @@ -227,11 +224,11 @@ TermParse::PtyReader() // If Pty Buffer nearly full, snooze this thread, and continue. while (READ_BUF_SIZE - bufferSize < MIN_PTY_BUFFER_SPACE) { status_t status; - do { + do { status = acquire_sem(fReaderLocker); } while (status == B_INTERRUPTED); if (status < B_OK) - return status; + return status; bufferSize = fReadBufferSize; } @@ -309,7 +306,7 @@ TermParse::EscParse() int top, bot; int cs96 = 0; uchar curess = 0; - + char cbuf[4], dstbuf[4]; char *ptr; @@ -381,7 +378,7 @@ TermParse::EscParse() case CASE_PRINT_GR: /* case iso8859 gr character, or euc */ ptr = cbuf; - if (now_coding == B_EUC_CONVERSION + if (now_coding == B_EUC_CONVERSION || now_coding == B_EUC_KR_CONVERSION || now_coding == B_JIS_CONVERSION || now_coding == B_GBK_CONVERSION @@ -469,7 +466,7 @@ TermParse::EscParse() break; cbuf[1] = c; cbuf[2] = '\0'; - + fBuffer->InsertChar(cbuf, 2, attr); break; @@ -502,7 +499,7 @@ TermParse::EscParse() case CASE_SCS_STATE: { cs96 = 0; - uchar dummy; + uchar dummy; _NextParseChar(dummy); parsestate = groundtable; break; @@ -819,7 +816,7 @@ TermParse::EscParse() // screen->max_col + 1, False); parsestate = groundtable; break; - + // case CASE_GSETS: // screen->gsets[scstype] = GSET(c) | cs96; // parsestate = groundtable; @@ -879,14 +876,14 @@ TermParse::EscParse() uchar mode_char; _NextParseChar(mode_char); if (mode_char != '0' - && mode_char != '1' + && mode_char != '1' && mode_char != '2') { parsestate = groundtable; break; } uchar current_char; _NextParseChar(current_char); - while (_NextParseChar(current_char) == B_OK + while (_NextParseChar(current_char) == B_OK && current_char != 0x7) { if (!isprint(current_char & 0x7f) || len+2 >= sizeof(string)) @@ -987,7 +984,7 @@ TermParse::EscParse() break; } } - + return B_OK; } @@ -1109,8 +1106,23 @@ TermParse::_DecPrivateModeSet(int value) // Use Alternate Screen Buffer. fBuffer->UseAlternateScreenBuffer(false); break; + case 1000: + // TODO: Send Mouse X & Y on button press and release. + break; + case 1003: + // Use All Motion Mouse Tracking + fBuffer->ReportAnyMouseEvent(true); + break; case 1034: - // Interpret "meta" key, sets eighth bit. + // TODO: Interprete "meta" key, sets eighth bit. + // Not supported yet. + break; + case 1036: + // TODO: Send ESC when Meta modifies a key + // Not supported yet. + break; + case 1039: + // TODO: Send ESC when Alt modifies a key // Not supported yet. break; case 1049: @@ -1155,8 +1167,23 @@ TermParse::_DecPrivateModeReset(int value) // Use Normal Screen Buffer. fBuffer->UseNormalScreenBuffer(); break; + case 1000: + // TODO: Don't send Mouse X & Y on button press and release. + break; + case 1003: + // Disable All Motion Mouse Tracking. + fBuffer->ReportAnyMouseEvent(false); + break; case 1034: - // Don’t interpret "meta" key. + // Don't interprete "meta" key. + // Not supported yet. + break; + case 1036: + // TODO: Don't send ESC when Meta modifies a key + // Not supported yet. + break; + case 1039: + // TODO: Don't send ESC when Alt modifies a key // Not supported yet. break; case 1049: diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 7c06cbb30c..2bfe94fe9f 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -170,7 +170,8 @@ TermView::TermView(BRect frame, int32 argc, const char** argv, int32 historySize fColumns(COLUMNS_DEFAULT), fRows(ROWS_DEFAULT), fEncoding(M_UTF8), - fScrBufSize(historySize) + fScrBufSize(historySize), + fReportAnyMouseEvent(false) { _InitObject(argc, argv); } @@ -183,7 +184,8 @@ TermView::TermView(int rows, int columns, int32 argc, const char** argv, fColumns(columns), fRows(rows), fEncoding(M_UTF8), - fScrBufSize(historySize) + fScrBufSize(historySize), + fReportAnyMouseEvent(false) { _InitObject(argc, argv); SetTermSize(fRows, fColumns, true); @@ -207,7 +209,8 @@ TermView::TermView(BMessage* archive) fColumns(COLUMNS_DEFAULT), fRows(ROWS_DEFAULT), fEncoding(M_UTF8), - fScrBufSize(1000) + fScrBufSize(1000), + fReportAnyMouseEvent(false) { // We need this SetFlags(Flags() | B_WILL_DRAW | B_PULSE_NEEDED); @@ -277,6 +280,7 @@ TermView::_InitObject(int32 argc, const char** argv) fMouseTracking = false; fIMflag = false; fCheckMouseTracking = false; + fReportAnyMouseEvent = false; fTextBuffer = new(std::nothrow) TerminalBuffer; if (fTextBuffer == NULL) @@ -1333,18 +1337,18 @@ TermView::MessageReceived(BMessage *msg) //rgb_color *color; int32 i = 0; - + if (msg->FindRef("refs", i++, &ref) == B_OK) { // first check if secondary mouse button is pressed int32 buttons = 0; msg->FindInt32("buttons", &buttons); - + if (buttons == B_SECONDARY_MOUSE_BUTTON) { // start popup menu _SecondaryMouseButtonDropped(msg); return; } - + _DoFileDrop(ref); while (msg->FindRef("refs", i++, &ref) == B_OK) { @@ -1517,7 +1521,13 @@ TermView::MessageReceived(BMessage *msg) SetTitle(title); break; } - + case MSG_REPORT_ANY_MOUSE_EVENT: + { + bool reportAnyMouseEvent; + if (msg->FindBool("reportAnyMouseEvent", &reportAnyMouseEvent) == B_OK) + fReportAnyMouseEvent = reportAnyMouseEvent; + break; + } case MSG_REMOVE_RESIZE_VIEW_IF_NEEDED: { BPoint point; @@ -1630,30 +1640,30 @@ TermView::_SecondaryMouseButtonDropped(BMessage* msg) BMessage* insertMessage = new BMessage(*msg); insertMessage->what = kSecondaryMouseDropAction; insertMessage->AddInt8("action", kInsert); - + BMessage* cdMessage = new BMessage(*msg); cdMessage->what = kSecondaryMouseDropAction; cdMessage->AddInt8("action", kChangeDirectory); - + BMessage* lnMessage = new BMessage(*msg); lnMessage->what = kSecondaryMouseDropAction; lnMessage->AddInt8("action", kLinkFiles); - + BMessage* mvMessage = new BMessage(*msg); mvMessage->what = kSecondaryMouseDropAction; mvMessage->AddInt8("action", kMoveFiles); - + BMessage* cpMessage = new BMessage(*msg); cpMessage->what = kSecondaryMouseDropAction; cpMessage->AddInt8("action", kCopyFiles); - + BMenuItem* insertItem = new BMenuItem("Insert Path", insertMessage); BMenuItem* cdItem = new BMenuItem("Change Directory", cdMessage); BMenuItem* lnItem = new BMenuItem("Create Link Here", lnMessage); BMenuItem* mvItem = new BMenuItem("Move Here", mvMessage); BMenuItem* cpItem = new BMenuItem("Copy Here", cpMessage); BMenuItem* chItem = new BMenuItem("Cancel", NULL); - + // if the refs point to different directorys disable the cd menu item bool differentDirs = false; BDirectory firstDir; @@ -1667,14 +1677,14 @@ TermView::_SecondaryMouseButtonDropped(BMessage* msg) dir.SetTo(&ref); else entry.GetParent(&dir); - + if (i == 1) { node_ref nodeRef; dir.GetNodeRef(&nodeRef); firstDir.SetTo(&nodeRef); } else if (firstDir != dir) { differentDirs = true; - break; + break; } } if (differentDirs) @@ -1700,10 +1710,10 @@ TermView::_DoSecondaryMouseDropAction(BMessage* msg) { int8 action = -1; msg->FindInt8("action", &action); - + BString outString = ""; BString itemString = ""; - + switch (action) { case kInsert: break; @@ -1723,22 +1733,22 @@ TermView::_DoSecondaryMouseDropAction(BMessage* msg) default: return; } - + bool listContainsDirectory = false; entry_ref ref; - int32 i = 0; + int32 i = 0; while (msg->FindRef("refs", i++, &ref) == B_OK) { BEntry ent(&ref); BNode node(&ref); BPath path(&ent); BString string(path.Path()); - + if (node.IsDirectory()) listContainsDirectory = true; - + if (i > 1) itemString += " "; - + if (action == kChangeDirectory) { if (!node.IsDirectory()) { int32 slash = string.FindLast("/"); @@ -1751,18 +1761,18 @@ TermView::_DoSecondaryMouseDropAction(BMessage* msg) string.CharacterEscape(kEscapeCharacters, '\\'); itemString += string; } - + if (listContainsDirectory && action == kCopyFiles) outString += " -R"; outString += itemString; - + if (action == kLinkFiles || action == kMoveFiles || action == kCopyFiles) outString += " ."; - + if (action != kInsert) outString += "\n"; - + _WritePTY(outString.String(), outString.Length()); } @@ -2023,6 +2033,37 @@ TermView::_MouseDistanceSinceLastClick(BPoint where) } +void +TermView::_SendMouseEvent(int32 buttons, int32 mode, int32 x, int32 y, + bool motion) +{ + char xtermButtons; + if (buttons == B_PRIMARY_MOUSE_BUTTON) + xtermButtons = 32 + 0; + else if (buttons == B_SECONDARY_MOUSE_BUTTON) + xtermButtons = 32 + 1; + else if (buttons == B_TERTIARY_MOUSE_BUTTON) + xtermButtons = 32 + 2; + else + xtermButtons = 32 + 3; + + if (motion) + xtermButtons += 32; + + char xtermX = x + 1 + 32; + char xtermY = y + 1 + 32; + + char destBuffer[6]; + destBuffer[0] = '\033'; + destBuffer[1] = '['; + destBuffer[2] = 'M'; + destBuffer[3] = xtermButtons; + destBuffer[4] = xtermX; + destBuffer[5] = xtermY; + fShell->Write(destBuffer, 6); +} + + void TermView::MouseDown(BPoint where) { @@ -2030,10 +2071,19 @@ TermView::MouseDown(BPoint where) MakeFocus(); int32 buttons; + int32 modifier; Window()->CurrentMessage()->FindInt32("buttons", &buttons); + Window()->CurrentMessage()->FindInt32("modifiers", &modifier); fMouseButtons = buttons; + if (fReportAnyMouseEvent) { + + TermPos clickPos = _ConvertToTerminal(where); + _SendMouseEvent(buttons, modifier, clickPos.x, clickPos.y, false); + return; + } + // paste button if ((buttons & (B_SECONDARY_MOUSE_BUTTON | B_TERTIARY_MOUSE_BUTTON)) != 0) { Paste(gMouseClipboard); @@ -2043,14 +2093,13 @@ TermView::MouseDown(BPoint where) // Select Region if (buttons == B_PRIMARY_MOUSE_BUTTON) { - int32 mod, clicks; - Window()->CurrentMessage()->FindInt32("modifiers", &mod); + int32 clicks; Window()->CurrentMessage()->FindInt32("clicks", &clicks); if (_HasSelection()) { TermPos inPos = _ConvertToTerminal(where); if (_CheckSelectedRegion(inPos)) { - if (mod & B_CONTROL_KEY) { + if (modifier & B_CONTROL_KEY) { BPoint p; uint32 bt; do { @@ -2081,7 +2130,7 @@ TermView::MouseDown(BPoint where) TermPos clickPos = _ConvertToTerminal(where); - if (mod & B_SHIFT_KEY) { + if (modifier & B_SHIFT_KEY) { fInitialSelectionStart = clickPos; fInitialSelectionEnd = clickPos; _ExtendSelection(fInitialSelectionStart, true, false); @@ -2098,22 +2147,21 @@ TermView::MouseDown(BPoint where) case 1: fCheckMouseTracking = true; fSelectGranularity = SELECT_CHARS; - break; + break; case 2: - _SelectWord(where, (mod & B_SHIFT_KEY) != 0, false); + _SelectWord(where, (modifier & B_SHIFT_KEY) != 0, false); fMouseTracking = true; fSelectGranularity = SELECT_WORDS; break; case 3: - _SelectLine(where, (mod & B_SHIFT_KEY) != 0, false); + _SelectLine(where, (modifier & B_SHIFT_KEY) != 0, false); fMouseTracking = true; fSelectGranularity = SELECT_LINES; break; } - } - + } fLastClickPoint = where; } @@ -2121,6 +2169,15 @@ TermView::MouseDown(BPoint where) void TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message) { + if (fReportAnyMouseEvent) { + int32 modifier; + Window()->CurrentMessage()->FindInt32("modifiers", &modifier); + + TermPos clickPos = _ConvertToTerminal(where); + _SendMouseEvent(fMouseButtons, modifier, clickPos.x, clickPos.y, true); + return; + } + if (fCheckMouseTracking) { if (_MouseDistanceSinceLastClick(where) > 9) fMouseTracking = true; @@ -2169,15 +2226,15 @@ TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message) } _ExtendSelection(_ConvertToTerminal(where), true, true); - break; + break; } case SELECT_WORDS: _SelectWord(where, true, true); - break; + break; case SELECT_LINES: _SelectLine(where, true, true); - break; - } + break; + } } @@ -2196,16 +2253,22 @@ TermView::MouseUp(BPoint where) // clipboard. int32 buttons; Window()->CurrentMessage()->FindInt32("buttons", &buttons); - if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0 - && (fMouseButtons & B_PRIMARY_MOUSE_BUTTON) != 0) { - Copy(gMouseClipboard); - } + if (fReportAnyMouseEvent) { + TermPos clickPos = _ConvertToTerminal(where); + _SendMouseEvent(0, 0, clickPos.x, clickPos.y, false); + } else { + if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0 + && (fMouseButtons & B_PRIMARY_MOUSE_BUTTON) != 0) { + Copy(gMouseClipboard); + } + + } fMouseButtons = buttons; } -// Select a range of text +//! Select a range of text. void TermView::_Select(TermPos start, TermPos end, bool inclusive, bool setInitialSelection) @@ -2267,7 +2330,7 @@ TermView::_Select(TermPos start, TermPos end, bool inclusive, } -// extend selection (shift + mouse click) +//! Extend selection (shift + mouse click). void TermView::_ExtendSelection(TermPos pos, bool inclusive, bool useInitialSelection) diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index 604444bea1..eb335fcf92 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -177,6 +177,8 @@ private: void _ScrollTo(float y, bool scrollGfx); void _ScrollToRange(TermPos start, TermPos end); + void _SendMouseEvent(int32 button, int32 mode, int32 x, + int32 y, bool motion); private: class CharClassifier; @@ -251,6 +253,8 @@ private: bool fCheckMouseTracking; int fSelectGranularity; BPoint fLastClickPoint; + + bool fReportAnyMouseEvent; // Input Method parameter. int fIMViewPtr; diff --git a/src/apps/terminal/TerminalBuffer.cpp b/src/apps/terminal/TerminalBuffer.cpp index d243018817..c8d2ce7e34 100644 --- a/src/apps/terminal/TerminalBuffer.cpp +++ b/src/apps/terminal/TerminalBuffer.cpp @@ -74,6 +74,17 @@ TerminalBuffer::Encoding() const } +void +TerminalBuffer::ReportAnyMouseEvent(bool reportAnyMouseEvent) +{ + if (fListenerValid) { + BMessage message(MSG_REPORT_ANY_MOUSE_EVENT); + message.AddBool("reportAnyMouseEvent", reportAnyMouseEvent); + fListener.SendMessage(&message); + } +} + + void TerminalBuffer::SetEncoding(int encoding) { diff --git a/src/apps/terminal/TerminalBuffer.h b/src/apps/terminal/TerminalBuffer.h index 05fc1e2ece..5da3af5630 100644 --- a/src/apps/terminal/TerminalBuffer.h +++ b/src/apps/terminal/TerminalBuffer.h @@ -34,6 +34,8 @@ public: void UseAlternateScreenBuffer(bool clear); void UseNormalScreenBuffer(); + + void ReportAnyMouseEvent(bool reportAnyMouseEvent); protected: virtual void NotifyListener();