diff --git a/src/apps/terminal/Jamfile b/src/apps/terminal/Jamfile index c8a114e927..7a480d917c 100644 --- a/src/apps/terminal/Jamfile +++ b/src/apps/terminal/Jamfile @@ -33,6 +33,7 @@ Application Terminal : TermParse.cpp TermScrollView.cpp TermView.cpp + TermViewStates.cpp TermWindow.cpp TitlePlaceholderMapper.cpp VTKeyTbl.c diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 89faf10feb..b448017c37 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -62,22 +62,13 @@ #include "TermConst.h" #include "TerminalBuffer.h" #include "TerminalCharClassifier.h" +#include "TermViewStates.h" #include "VTkeymap.h" -// defined in VTKeyTbl.c -extern int function_keycode_table[]; -extern char *function_key_char_table[]; - #define ROWS_DEFAULT 25 #define COLUMNS_DEFAULT 80 -// selection granularity -enum { - SELECT_CHARS, - SELECT_WORDS, - SELECT_LINES -}; #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Terminal TermView" @@ -101,7 +92,6 @@ static property_info sPropList[] = { static const uint32 kUpdateSigWinch = 'Rwin'; static const uint32 kBlinkCursor = 'BlCr'; -static const uint32 kAutoScroll = 'AScr'; static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s @@ -320,14 +310,15 @@ TermView::_InitObject(const ShellParameters& shellParameters) fConsiderClockedSync = false; fSelStart = TermPos(-1, -1); fSelEnd = TermPos(-1, -1); - fMouseTracking = false; - fCheckMouseTracking = false; fPrevPos = TermPos(-1, - 1); fReportX10MouseEvent = false; fReportNormalMouseEvent = false; fReportButtonMouseEvent = false; fReportAnyMouseEvent = false; fMouseClipboard = be_clipboard; + fDefaultState = new(std::nothrow) DefaultState(this); + fSelectState = new(std::nothrow) SelectState(this); + fActiveState = NULL; fTextBuffer = new(std::nothrow) TerminalBuffer; if (fTextBuffer == NULL) @@ -371,9 +362,14 @@ TermView::_InitObject(const ShellParameters& shellParameters) if (error < B_OK) return error; + if (fDefaultState == NULL || fSelectState == NULL) + return B_NO_MEMORY; + SetLowColor(fTextBackColor); SetViewColor(B_TRANSPARENT_32_BIT); + _NextState(fDefaultState); + return B_OK; } @@ -385,6 +381,8 @@ TermView::~TermView() _DetachShell(); + delete fDefaultState; + delete fSelectState; delete fSyncRunner; delete fAutoScrollRunner; delete fCharClassifier; @@ -1388,165 +1386,7 @@ TermView::MakeFocus(bool focusState) void TermView::KeyDown(const char *bytes, int32 numBytes) { - int32 key, mod, rawChar; - BMessage *currentMessage = Looper()->CurrentMessage(); - if (currentMessage == NULL) - return; - - currentMessage->FindInt32("modifiers", &mod); - currentMessage->FindInt32("key", &key); - currentMessage->FindInt32("raw_char", &rawChar); - - _ActivateCursor(true); - - // handle multi-byte chars - if (numBytes > 1) { - if (fEncoding != M_UTF8) { - char destBuffer[16]; - int32 destLen = sizeof(destBuffer); - int32 state = 0; - convert_from_utf8(fEncoding, bytes, &numBytes, destBuffer, - &destLen, &state, '?'); - _ScrollTo(0, true); - fShell->Write(destBuffer, destLen); - return; - } - - _ScrollTo(0, true); - fShell->Write(bytes, numBytes); - return; - } - - // Terminal filters RET, ENTER, F1...F12, and ARROW key code. - const char *toWrite = NULL; - - switch (*bytes) { - case B_RETURN: - if (rawChar == B_RETURN) - toWrite = "\r"; - break; - - case B_DELETE: - toWrite = DELETE_KEY_CODE; - break; - - case B_BACKSPACE: - // Translate only the actual backspace key to the backspace - // code. CTRL-H shall just be echoed. - if (!((mod & B_CONTROL_KEY) && rawChar == 'h')) - toWrite = BACKSPACE_KEY_CODE; - break; - - case B_LEFT_ARROW: - if (rawChar == B_LEFT_ARROW) { - if ((mod & B_SHIFT_KEY) != 0) { - if (fListener != NULL) - fListener->PreviousTermView(this); - return; - } - if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY)) - toWrite = CTRL_LEFT_ARROW_KEY_CODE; - else - toWrite = LEFT_ARROW_KEY_CODE; - } - break; - - case B_RIGHT_ARROW: - if (rawChar == B_RIGHT_ARROW) { - if ((mod & B_SHIFT_KEY) != 0) { - if (fListener != NULL) - fListener->NextTermView(this); - return; - } - if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY)) - toWrite = CTRL_RIGHT_ARROW_KEY_CODE; - else - toWrite = RIGHT_ARROW_KEY_CODE; - } - break; - - case B_UP_ARROW: - if (mod & B_SHIFT_KEY) { - _ScrollTo(fScrollOffset - fFontHeight, true); - return; - } - if (rawChar == B_UP_ARROW) { - if (mod & B_CONTROL_KEY) - toWrite = CTRL_UP_ARROW_KEY_CODE; - else - toWrite = UP_ARROW_KEY_CODE; - } - break; - - case B_DOWN_ARROW: - if (mod & B_SHIFT_KEY) { - _ScrollTo(fScrollOffset + fFontHeight, true); - return; - } - - if (rawChar == B_DOWN_ARROW) { - if (mod & B_CONTROL_KEY) - toWrite = CTRL_DOWN_ARROW_KEY_CODE; - else - toWrite = DOWN_ARROW_KEY_CODE; - } - break; - - case B_INSERT: - if (rawChar == B_INSERT) - toWrite = INSERT_KEY_CODE; - break; - - case B_HOME: - if (rawChar == B_HOME) - toWrite = HOME_KEY_CODE; - break; - - case B_END: - if (rawChar == B_END) - toWrite = END_KEY_CODE; - break; - - case B_PAGE_UP: - if (mod & B_SHIFT_KEY) { - _ScrollTo(fScrollOffset - fFontHeight * fRows, true); - return; - } - if (rawChar == B_PAGE_UP) - toWrite = PAGE_UP_KEY_CODE; - break; - - case B_PAGE_DOWN: - if (mod & B_SHIFT_KEY) { - _ScrollTo(fScrollOffset + fFontHeight * fRows, true); - return; - } - if (rawChar == B_PAGE_DOWN) - toWrite = PAGE_DOWN_KEY_CODE; - break; - - case B_FUNCTION_KEY: - for (int32 i = 0; i < 12; i++) { - if (key == function_keycode_table[i]) { - toWrite = function_key_char_table[i]; - break; - } - } - break; - } - - // If the above code proposed an alternative string to write, we get it's - // length. Otherwise we write exactly the bytes passed to this method. - size_t toWriteLen; - if (toWrite != NULL) { - toWriteLen = strlen(toWrite); - } else { - toWrite = bytes; - toWriteLen = numBytes; - } - - _ScrollTo(0, true); - fShell->Write(toWrite, toWriteLen); + fActiveState->KeyDown(bytes, numBytes); } @@ -1593,6 +1433,9 @@ TermView::FrameResized(float width, float height) void TermView::MessageReceived(BMessage *msg) { + if (fActiveState->MessageReceived(msg)) + return; + entry_ref ref; const char *ctrl_l = "\x0c"; @@ -1829,9 +1672,6 @@ TermView::MessageReceived(BMessage *msg) case kUpdateSigWinch: _UpdateSIGWINCH(); break; - case kAutoScroll: - _AutoScrollUpdate(); - break; case kSecondaryMouseDropAction: _DoSecondaryMouseDropAction(msg); break; @@ -2480,98 +2320,13 @@ TermView::MouseDown(BPoint where) if (!IsFocus()) MakeFocus(); - int32 buttons; - int32 modifier; - Window()->CurrentMessage()->FindInt32("buttons", &buttons); - Window()->CurrentMessage()->FindInt32("modifiers", &modifier); + BMessage* currentMessage = Window()->CurrentMessage(); + int32 buttons = currentMessage->GetInt32("buttons", 0); + int32 modifiers = currentMessage->GetInt32("modifiers", 0); + + fActiveState->MouseDown(where, buttons, modifiers); fMouseButtons = buttons; - - if (fReportAnyMouseEvent || fReportButtonMouseEvent - || fReportNormalMouseEvent || fReportX10MouseEvent) { - 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(fMouseClipboard); - fLastClickPoint = where; - return; - } - - // Select Region - if (buttons == B_PRIMARY_MOUSE_BUTTON) { - int32 clicks; - Window()->CurrentMessage()->FindInt32("clicks", &clicks); - - if (_HasSelection()) { - TermPos inPos = _ConvertToTerminal(where); - if (_CheckSelectedRegion(inPos)) { - if (modifier & B_CONTROL_KEY) { - BPoint p; - uint32 bt; - do { - GetMouse(&p, &bt); - - if (bt == 0) { - _Deselect(); - return; - } - - snooze(40000); - - } while (abs((int)(where.x - p.x)) < 4 - && abs((int)(where.y - p.y)) < 4); - - InitiateDrag(); - return; - } - } - } - - // If mouse has moved too much, disable double/triple click. - if (_MouseDistanceSinceLastClick(where) > 8) - clicks = 1; - - SetMouseEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, - B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); - - TermPos clickPos = _ConvertToTerminal(where); - - if (modifier & B_SHIFT_KEY) { - fInitialSelectionStart = clickPos; - fInitialSelectionEnd = clickPos; - _ExtendSelection(fInitialSelectionStart, true, false); - } else { - _Deselect(); - fInitialSelectionStart = clickPos; - fInitialSelectionEnd = clickPos; - } - - // If clicks larger than 3, reset mouse click counter. - clicks = (clicks - 1) % 3 + 1; - - switch (clicks) { - case 1: - fCheckMouseTracking = true; - fSelectGranularity = SELECT_CHARS; - break; - - case 2: - _SelectWord(where, (modifier & B_SHIFT_KEY) != 0, false); - fMouseTracking = true; - fSelectGranularity = SELECT_WORDS; - break; - - case 3: - _SelectLine(where, (modifier & B_SHIFT_KEY) != 0, false); - fMouseTracking = true; - fSelectGranularity = SELECT_LINES; - break; - } - } fLastClickPoint = where; } @@ -2579,111 +2334,17 @@ TermView::MouseDown(BPoint where) void TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message) { - if (fReportAnyMouseEvent || fReportButtonMouseEvent) { - int32 modifier; - Window()->CurrentMessage()->FindInt32("modifiers", &modifier); - - TermPos clickPos = _ConvertToTerminal(where); - - if (fReportButtonMouseEvent) { - if (fPrevPos.x != clickPos.x || fPrevPos.y != clickPos.y) { - _SendMouseEvent(fMouseButtons, modifier, clickPos.x, clickPos.y, - true); - } - fPrevPos = clickPos; - return; - } - _SendMouseEvent(fMouseButtons, modifier, clickPos.x, clickPos.y, true); - return; - } - - if (fCheckMouseTracking) { - if (_MouseDistanceSinceLastClick(where) > 9) - fMouseTracking = true; - } - if (!fMouseTracking) - return; - - bool doAutoScroll = false; - - if (where.y < 0) { - doAutoScroll = true; - fAutoScrollSpeed = where.y; - where.x = 0; - where.y = 0; - } - - BRect bounds(Bounds()); - if (where.y > bounds.bottom) { - doAutoScroll = true; - fAutoScrollSpeed = where.y - bounds.bottom; - where.x = bounds.right; - where.y = bounds.bottom; - } - - if (doAutoScroll) { - if (fAutoScrollRunner == NULL) { - BMessage message(kAutoScroll); - fAutoScrollRunner = new (std::nothrow) BMessageRunner( - BMessenger(this), &message, 10000); - } - } else { - delete fAutoScrollRunner; - fAutoScrollRunner = NULL; - } - - switch (fSelectGranularity) { - case SELECT_CHARS: - { - // If we just start selecting, we first select the initially - // hit char, so that we get a proper initial selection -- the char - // in question, which will thus always be selected, regardless of - // whether selecting forward or backward. - if (fInitialSelectionStart == fInitialSelectionEnd) { - _Select(fInitialSelectionStart, fInitialSelectionEnd, true, - true); - } - - _ExtendSelection(_ConvertToTerminal(where), true, true); - break; - } - case SELECT_WORDS: - _SelectWord(where, true, true); - break; - case SELECT_LINES: - _SelectLine(where, true, true); - break; - } + fActiveState->MouseMoved(where, transit, message); } void TermView::MouseUp(BPoint where) { - fCheckMouseTracking = false; - fMouseTracking = false; + int32 buttons = Window()->CurrentMessage()->GetInt32("buttons", 0); - if (fAutoScrollRunner != NULL) { - delete fAutoScrollRunner; - fAutoScrollRunner = NULL; - } + fActiveState->MouseUp(where, buttons); - // When releasing the first mouse button, we copy the selected text to the - // clipboard. - int32 buttons; - Window()->CurrentMessage()->FindInt32("buttons", &buttons); - - if (fReportAnyMouseEvent || fReportButtonMouseEvent - || fReportNormalMouseEvent) { - 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(fMouseClipboard); - } - - } fMouseButtons = buttons; } @@ -2844,22 +2505,6 @@ TermView::_SelectLine(BPoint where, bool extend, bool useInitialSelection) } -void -TermView::_AutoScrollUpdate() -{ - if (fMouseTracking && fAutoScrollRunner != NULL && fScrollBar != NULL) { - float value = fScrollBar->Value(); - _ScrollTo(value + fAutoScrollSpeed, true); - if (fAutoScrollSpeed < 0) { - _ExtendSelection(_ConvertToTerminal(BPoint(0, 0)), true, true); - } else { - _ExtendSelection(_ConvertToTerminal(Bounds().RightBottom()), true, - true); - } - } -} - - bool TermView::_CheckSelectedRegion(const TermPos &pos) const { @@ -3222,6 +2867,18 @@ TermView::_CancelInputMethod() } +void +TermView::_NextState(State* state) +{ + if (state != fActiveState) { + if (fActiveState != NULL) + fActiveState->Exited(); + fActiveState = state; + fActiveState->Entered(); + } +} + + // #pragma mark - Listener diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index 9e0721511a..429097db82 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -143,6 +143,16 @@ protected: private: class CharClassifier; + class State; + class StandardBaseState; + class DefaultState; + class SelectState; + + friend class State; + friend class StandardBaseState; + friend class DefaultState; + friend class SelectState; + private: // point and text offset conversion inline int32 _LineAt(float y); @@ -199,8 +209,6 @@ private: void _SelectLine(BPoint where, bool extend, bool useInitialSelection); - void _AutoScrollUpdate(); - bool _CheckSelectedRegion(const TermPos& pos) const; bool _CheckSelectedRegion(int32 row, int32 firstColumn, int32& lastColumn) const; @@ -218,6 +226,8 @@ private: void _HandleInputMethodLocationRequest(); void _CancelInputMethod(); + void _NextState(State* state); + private: Listener* fListener; Shell* fShell; @@ -252,8 +262,6 @@ private: // Cursor position. TermPos fCursor; - int32 fMouseButtons; - // Terminal rows and columns. int fColumns; int fRows; @@ -293,18 +301,21 @@ private: TermPos fSelEnd; TermPos fInitialSelectionStart; TermPos fInitialSelectionEnd; - bool fMouseTracking; - bool fCheckMouseTracking; - int fSelectGranularity; BPoint fLastClickPoint; // mouse + int32 fMouseButtons; TermPos fPrevPos; bool fReportX10MouseEvent; bool fReportNormalMouseEvent; bool fReportButtonMouseEvent; bool fReportAnyMouseEvent; BClipboard* fMouseClipboard; + + // states + DefaultState* fDefaultState; + SelectState* fSelectState; + State* fActiveState; }; diff --git a/src/apps/terminal/TermViewStates.cpp b/src/apps/terminal/TermViewStates.cpp new file mode 100644 index 0000000000..e74194dc18 --- /dev/null +++ b/src/apps/terminal/TermViewStates.cpp @@ -0,0 +1,563 @@ +/* + * Copyright 2001-2013, Haiku, Inc. + * Copyright 2003-2004 Kian Duffy, myob@users.sourceforge.net + * Parts Copyright 1998-1999 Kazuho Okui and Takashi Murai. + * All rights reserved. Distributed under the terms of the MIT license. + * + * Authors: + * Stefano Ceccherini, stefano.ceccherini@gmail.com + * Kian Duffy, myob@users.sourceforge.net + * Y.Hayakawa, hida@sawada.riec.tohoku.ac.jp + * Ingo Weinhold, ingo_weinhold@gmx.de + * Clemens Zeidler, haiku@Clemens-Zeidler.de + * Siarzhuk Zharski, zharik@gmx.li + */ + + +#include "TermViewStates.h" + +#include +#include +#include +#include + +#include "Shell.h" +#include "TermConst.h" +#include "VTkeymap.h" +#include "VTKeyTbl.h" + + +// selection granularity +enum { + SELECT_CHARS, + SELECT_WORDS, + SELECT_LINES +}; + +static const uint32 kAutoScroll = 'AScr'; + + +// #pragma mark - State + + +TermView::State::State(TermView* view) + : + fView(view) +{ +} + + +TermView::State::~State() +{ +} + + +void +TermView::State::Entered() +{ +} + + +void +TermView::State::Exited() +{ +} + + +bool +TermView::State::MessageReceived(BMessage* message) +{ + return false; +} + + +void +TermView::State::KeyDown(const char* bytes, int32 numBytes) +{ +} + + +void +TermView::State::MouseDown(BPoint where, int32 buttons, int32 modifiers) +{ +} + + +void +TermView::State::MouseMoved(BPoint where, uint32 transit, + const BMessage* message) +{ +} + + +void +TermView::State::MouseUp(BPoint where, int32 buttons) +{ +} + + +// #pragma mark - StandardBaseState + + +TermView::StandardBaseState::StandardBaseState(TermView* view) + : + State(view) +{ +} + + +bool +TermView::StandardBaseState::_StandardMouseMoved(BPoint where) +{ + if (!fView->fReportAnyMouseEvent && !fView->fReportButtonMouseEvent) + return false; + + int32 modifier; + fView->Window()->CurrentMessage()->FindInt32("modifiers", &modifier); + + TermPos clickPos = fView->_ConvertToTerminal(where); + + if (fView->fReportButtonMouseEvent) { + if (fView->fPrevPos.x != clickPos.x + || fView->fPrevPos.y != clickPos.y) { + fView->_SendMouseEvent(fView->fMouseButtons, modifier, + clickPos.x, clickPos.y, true); + } + fView->fPrevPos = clickPos; + } else { + fView->_SendMouseEvent(fView->fMouseButtons, modifier, clickPos.x, + clickPos.y, true); + } + + return true; +} + + +// #pragma mark - DefaultState + + +TermView::DefaultState::DefaultState(TermView* view) + : + StandardBaseState(view) +{ +} + + +void +TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes) +{ + int32 key, mod, rawChar; + BMessage *currentMessage = fView->Looper()->CurrentMessage(); + if (currentMessage == NULL) + return; + + currentMessage->FindInt32("modifiers", &mod); + currentMessage->FindInt32("key", &key); + currentMessage->FindInt32("raw_char", &rawChar); + + fView->_ActivateCursor(true); + + // handle multi-byte chars + if (numBytes > 1) { + if (fView->fEncoding != M_UTF8) { + char destBuffer[16]; + int32 destLen = sizeof(destBuffer); + int32 state = 0; + convert_from_utf8(fView->fEncoding, bytes, &numBytes, destBuffer, + &destLen, &state, '?'); + fView->_ScrollTo(0, true); + fView->fShell->Write(destBuffer, destLen); + return; + } + + fView->_ScrollTo(0, true); + fView->fShell->Write(bytes, numBytes); + return; + } + + // Terminal filters RET, ENTER, F1...F12, and ARROW key code. + const char *toWrite = NULL; + + switch (*bytes) { + case B_RETURN: + if (rawChar == B_RETURN) + toWrite = "\r"; + break; + + case B_DELETE: + toWrite = DELETE_KEY_CODE; + break; + + case B_BACKSPACE: + // Translate only the actual backspace key to the backspace + // code. CTRL-H shall just be echoed. + if (!((mod & B_CONTROL_KEY) && rawChar == 'h')) + toWrite = BACKSPACE_KEY_CODE; + break; + + case B_LEFT_ARROW: + if (rawChar == B_LEFT_ARROW) { + if ((mod & B_SHIFT_KEY) != 0) { + if (fView->fListener != NULL) + fView->fListener->PreviousTermView(fView); + return; + } + if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY)) + toWrite = CTRL_LEFT_ARROW_KEY_CODE; + else + toWrite = LEFT_ARROW_KEY_CODE; + } + break; + + case B_RIGHT_ARROW: + if (rawChar == B_RIGHT_ARROW) { + if ((mod & B_SHIFT_KEY) != 0) { + if (fView->fListener != NULL) + fView->fListener->NextTermView(fView); + return; + } + if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY)) + toWrite = CTRL_RIGHT_ARROW_KEY_CODE; + else + toWrite = RIGHT_ARROW_KEY_CODE; + } + break; + + case B_UP_ARROW: + if (mod & B_SHIFT_KEY) { + fView->_ScrollTo(fView->fScrollOffset - fView->fFontHeight, + true); + return; + } + if (rawChar == B_UP_ARROW) { + if (mod & B_CONTROL_KEY) + toWrite = CTRL_UP_ARROW_KEY_CODE; + else + toWrite = UP_ARROW_KEY_CODE; + } + break; + + case B_DOWN_ARROW: + if (mod & B_SHIFT_KEY) { + fView->_ScrollTo(fView->fScrollOffset + fView->fFontHeight, + true); + return; + } + + if (rawChar == B_DOWN_ARROW) { + if (mod & B_CONTROL_KEY) + toWrite = CTRL_DOWN_ARROW_KEY_CODE; + else + toWrite = DOWN_ARROW_KEY_CODE; + } + break; + + case B_INSERT: + if (rawChar == B_INSERT) + toWrite = INSERT_KEY_CODE; + break; + + case B_HOME: + if (rawChar == B_HOME) + toWrite = HOME_KEY_CODE; + break; + + case B_END: + if (rawChar == B_END) + toWrite = END_KEY_CODE; + break; + + case B_PAGE_UP: + if (mod & B_SHIFT_KEY) { + fView->_ScrollTo( + fView->fScrollOffset - fView->fFontHeight * fView->fRows, + true); + return; + } + if (rawChar == B_PAGE_UP) + toWrite = PAGE_UP_KEY_CODE; + break; + + case B_PAGE_DOWN: + if (mod & B_SHIFT_KEY) { + fView->_ScrollTo( + fView->fScrollOffset + fView->fFontHeight * fView->fRows, + true); + return; + } + if (rawChar == B_PAGE_DOWN) + toWrite = PAGE_DOWN_KEY_CODE; + break; + + case B_FUNCTION_KEY: + for (int32 i = 0; i < 12; i++) { + if (key == function_keycode_table[i]) { + toWrite = function_key_char_table[i]; + break; + } + } + break; + } + + // If the above code proposed an alternative string to write, we get it's + // length. Otherwise we write exactly the bytes passed to this method. + size_t toWriteLen; + if (toWrite != NULL) { + toWriteLen = strlen(toWrite); + } else { + toWrite = bytes; + toWriteLen = numBytes; + } + + fView->_ScrollTo(0, true); + fView->fShell->Write(toWrite, toWriteLen); +} + + +void +TermView::DefaultState::MouseDown(BPoint where, int32 buttons, int32 modifiers) +{ + if (fView->fReportAnyMouseEvent || fView->fReportButtonMouseEvent + || fView->fReportNormalMouseEvent || fView->fReportX10MouseEvent) { + TermPos clickPos = fView->_ConvertToTerminal(where); + fView->_SendMouseEvent(buttons, modifiers, clickPos.x, clickPos.y, + false); + return; + } + + // paste button + if ((buttons & (B_SECONDARY_MOUSE_BUTTON | B_TERTIARY_MOUSE_BUTTON)) != 0) { + fView->Paste(fView->fMouseClipboard); + return; + } + + // Select Region + if (buttons == B_PRIMARY_MOUSE_BUTTON) { + fView->fSelectState->Prepare(where, modifiers); + fView->_NextState(fView->fSelectState); + } +} + + +void +TermView::DefaultState::MouseMoved(BPoint where, uint32 transit, + const BMessage* message) +{ + _StandardMouseMoved(where); +} + + +// #pragma mark - SelectState + + +TermView::SelectState::SelectState(TermView* view) + : + StandardBaseState(view), + fSelectGranularity(SELECT_CHARS), + fCheckMouseTracking(false), + fMouseTracking(false) +{ +} + + +void +TermView::SelectState::Prepare(BPoint where, int32 modifiers) +{ + int32 clicks; + fView->Window()->CurrentMessage()->FindInt32("clicks", &clicks); + + if (fView->_HasSelection()) { + TermPos inPos = fView->_ConvertToTerminal(where); + if (fView->_CheckSelectedRegion(inPos)) { + if (modifiers & B_CONTROL_KEY) { + BPoint p; + uint32 bt; + do { + fView->GetMouse(&p, &bt); + + if (bt == 0) { + fView->_Deselect(); + return; + } + + snooze(40000); + + } while (abs((int)(where.x - p.x)) < 4 + && abs((int)(where.y - p.y)) < 4); + + fView->InitiateDrag(); + return; + } + } + } + + // If mouse has moved too much, disable double/triple click. + if (fView->_MouseDistanceSinceLastClick(where) > 8) + clicks = 1; + + fView->SetMouseEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, + B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS); + + TermPos clickPos = fView->_ConvertToTerminal(where); + + if (modifiers & B_SHIFT_KEY) { + fView->fInitialSelectionStart = clickPos; + fView->fInitialSelectionEnd = clickPos; + fView->_ExtendSelection(fView->fInitialSelectionStart, true, false); + } else { + fView->_Deselect(); + fView->fInitialSelectionStart = clickPos; + fView->fInitialSelectionEnd = clickPos; + } + + // If clicks larger than 3, reset mouse click counter. + clicks = (clicks - 1) % 3 + 1; + + switch (clicks) { + case 1: + fCheckMouseTracking = true; + fSelectGranularity = SELECT_CHARS; + break; + + case 2: + fView->_SelectWord(where, (modifiers & B_SHIFT_KEY) != 0, false); + fMouseTracking = true; + fSelectGranularity = SELECT_WORDS; + break; + + case 3: + fView->_SelectLine(where, (modifiers & B_SHIFT_KEY) != 0, false); + fMouseTracking = true; + fSelectGranularity = SELECT_LINES; + break; + } +} + + +bool +TermView::SelectState::MessageReceived(BMessage* message) +{ + if (message->what == kAutoScroll) { + _AutoScrollUpdate(); + return true; + } + + return false; +} + + +void +TermView::SelectState::MouseMoved(BPoint where, uint32 transit, + const BMessage* message) +{ + if (_StandardMouseMoved(where)) + return; + + if (fCheckMouseTracking) { + if (fView->_MouseDistanceSinceLastClick(where) > 9) + fMouseTracking = true; + } + if (!fMouseTracking) + return; + + bool doAutoScroll = false; + + if (where.y < 0) { + doAutoScroll = true; + fView->fAutoScrollSpeed = where.y; + where.x = 0; + where.y = 0; + } + + BRect bounds(fView->Bounds()); + if (where.y > bounds.bottom) { + doAutoScroll = true; + fView->fAutoScrollSpeed = where.y - bounds.bottom; + where.x = bounds.right; + where.y = bounds.bottom; + } + + if (doAutoScroll) { + if (fView->fAutoScrollRunner == NULL) { + BMessage message(kAutoScroll); + fView->fAutoScrollRunner = new (std::nothrow) BMessageRunner( + BMessenger(fView), &message, 10000); + } + } else { + delete fView->fAutoScrollRunner; + fView->fAutoScrollRunner = NULL; + } + + switch (fSelectGranularity) { + case SELECT_CHARS: + { + // If we just start selecting, we first select the initially + // hit char, so that we get a proper initial selection -- the char + // in question, which will thus always be selected, regardless of + // whether selecting forward or backward. + if (fView->fInitialSelectionStart == fView->fInitialSelectionEnd) { + fView->_Select(fView->fInitialSelectionStart, + fView->fInitialSelectionEnd, true, true); + } + + fView->_ExtendSelection(fView->_ConvertToTerminal(where), true, + true); + break; + } + case SELECT_WORDS: + fView->_SelectWord(where, true, true); + break; + case SELECT_LINES: + fView->_SelectLine(where, true, true); + break; + } +} + + +void +TermView::SelectState::MouseUp(BPoint where, int32 buttons) +{ + fCheckMouseTracking = false; + fMouseTracking = false; + + if (fView->fAutoScrollRunner != NULL) { + delete fView->fAutoScrollRunner; + fView->fAutoScrollRunner = NULL; + } + + // When releasing the first mouse button, we copy the selected text to the + // clipboard. + + if (fView->fReportAnyMouseEvent || fView->fReportButtonMouseEvent + || fView->fReportNormalMouseEvent) { + TermPos clickPos = fView->_ConvertToTerminal(where); + fView->_SendMouseEvent(0, 0, clickPos.x, clickPos.y, false); + } else { + if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0 + && (fView->fMouseButtons & B_PRIMARY_MOUSE_BUTTON) != 0) { + fView->Copy(fView->fMouseClipboard); + } + + } + + fView->_NextState(fView->fDefaultState); +} + + +void +TermView::SelectState::_AutoScrollUpdate() +{ + if (fMouseTracking && fView->fAutoScrollRunner != NULL + && fView->fScrollBar != NULL) { + float value = fView->fScrollBar->Value(); + fView->_ScrollTo(value + fView->fAutoScrollSpeed, true); + if (fView->fAutoScrollSpeed < 0) { + fView->_ExtendSelection( + fView->_ConvertToTerminal(BPoint(0, 0)), true, true); + } else { + fView->_ExtendSelection( + fView->_ConvertToTerminal(fView->Bounds().RightBottom()), true, + true); + } + } +} diff --git a/src/apps/terminal/TermViewStates.h b/src/apps/terminal/TermViewStates.h new file mode 100644 index 0000000000..26ff862069 --- /dev/null +++ b/src/apps/terminal/TermViewStates.h @@ -0,0 +1,88 @@ +/* + * Copyright 2001-2013, Haiku, Inc. + * Copyright (c) 2003-4 Kian Duffy + * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. + * + * Distributed under the terms of the MIT license. + * Authors: + * Stefano Ceccherini, stefano.ceccherini@gmail.com + * Kian Duffy, myob@users.sourceforge.net + * Ingo Weinhold, ingo_weinhold@gmx.de + * Siarzhuk Zharski, zharik@gmx.li + */ +#ifndef TERMVIEW_STATES_H +#define TERMVIEW_STATES_H + + +#include "TermView.h" + + +class TermView::State { +public: + State(TermView* view); + virtual ~State(); + + virtual void Entered(); + virtual void Exited(); + + virtual bool MessageReceived(BMessage* message); + // returns true, if handled + + virtual void KeyDown(const char* bytes, int32 numBytes); + + virtual void MouseDown(BPoint where, int32 buttons, + int32 modifiers); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* message); + virtual void MouseUp(BPoint where, int32 buttons); + +protected: + TermView* fView; +}; + + +class TermView::StandardBaseState : public TermView::State { +public: + StandardBaseState(TermView* view); + +protected: + bool _StandardMouseMoved(BPoint where); +}; + + +class TermView::DefaultState : public TermView::StandardBaseState { +public: + DefaultState(TermView* view); + + virtual void KeyDown(const char* bytes, int32 numBytes); + + virtual void MouseDown(BPoint where, int32 buttons, + int32 modifiers); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* message); +}; + + +class TermView::SelectState : public TermView::StandardBaseState { +public: + SelectState(TermView* view); + + void Prepare(BPoint where, int32 modifiers); + + virtual bool MessageReceived(BMessage* message); + + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* message); + virtual void MouseUp(BPoint where, int32 buttons); + +private: + void _AutoScrollUpdate(); + +private: + int32 fSelectGranularity; + bool fCheckMouseTracking; + bool fMouseTracking; +}; + + +#endif // TERMVIEW_STATES_H