diff --git a/src/apps/terminal/AppearPrefView.cpp b/src/apps/terminal/AppearPrefView.cpp index cb4d9261c1..1b662bc082 100644 --- a/src/apps/terminal/AppearPrefView.cpp +++ b/src/apps/terminal/AppearPrefView.cpp @@ -65,6 +65,10 @@ AppearancePrefView::AppearancePrefView(const char* name, B_TRANSLATE("Allow bold text"), new BMessage(MSG_ALLOW_BOLD_CHANGED)); + fUseOptionAsMetaKey = new BCheckBox( + B_TRANSLATE("Use left Option as Meta key"), + new BMessage(MSG_USE_OPTION_AS_META_CHANGED)); + fWarnOnExit = new BCheckBox( B_TRANSLATE("Confirm exit if active programs exist"), new BMessage(MSG_WARN_ON_EXIT_CHANGED)); @@ -140,6 +144,7 @@ AppearancePrefView::AppearancePrefView(const char* name, B_CELLS_32x8, 8.0, "", new BMessage(MSG_COLOR_CHANGED))) .Add(fBlinkCursor) .Add(fAllowBold) + .Add(fUseOptionAsMetaKey) .Add(fWarnOnExit); fTabTitle->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT); @@ -172,6 +177,7 @@ AppearancePrefView::Revert() fBlinkCursor->SetValue(pref->getBool(PREF_BLINK_CURSOR)); fAllowBold->SetValue(pref->getBool(PREF_ALLOW_BOLD)); + fUseOptionAsMetaKey->SetValue(pref->getBool(PREF_USE_OPTION_AS_META)); fWarnOnExit->SetValue(pref->getBool(PREF_WARN_ON_EXIT)); _SetCurrentColorScheme(); @@ -194,6 +200,7 @@ AppearancePrefView::AttachedToWindow() fWindowTitle->SetTarget(this); fBlinkCursor->SetTarget(this); fAllowBold->SetTarget(this); + fUseOptionAsMetaKey->SetTarget(this); fWarnOnExit->SetTarget(this); fFontField->Menu()->SetTargetForItems(this); @@ -338,6 +345,15 @@ AppearancePrefView::MessageReceived(BMessage* msg) } break; + case MSG_USE_OPTION_AS_META_CHANGED: + if (PrefHandler::Default()->getBool(PREF_USE_OPTION_AS_META) + != fUseOptionAsMetaKey->Value()) { + PrefHandler::Default()->setBool(PREF_USE_OPTION_AS_META, + fUseOptionAsMetaKey->Value()); + modified = true; + } + break; + case MSG_WARN_ON_EXIT_CHANGED: if (PrefHandler::Default()->getBool(PREF_WARN_ON_EXIT) != fWarnOnExit->Value()) { diff --git a/src/apps/terminal/AppearPrefView.h b/src/apps/terminal/AppearPrefView.h index 5482937ca7..05dd7e39c9 100644 --- a/src/apps/terminal/AppearPrefView.h +++ b/src/apps/terminal/AppearPrefView.h @@ -25,6 +25,7 @@ static const uint32 MSG_TAB_TITLE_SETTING_CHANGED = 'mtts'; static const uint32 MSG_WINDOW_TITLE_SETTING_CHANGED = 'mwts'; static const uint32 MSG_BLINK_CURSOR_CHANGED = 'mbcc'; static const uint32 MSG_ALLOW_BOLD_CHANGED = 'mabc'; +static const uint32 MSG_USE_OPTION_AS_META_CHANGED = 'momc'; static const uint32 MSG_WARN_ON_EXIT_CHANGED = 'mwec'; static const uint32 MSG_COLS_CHANGED = 'mccl'; static const uint32 MSG_HISTORY_CHANGED = 'mhst'; @@ -78,6 +79,7 @@ private: BCheckBox* fBlinkCursor; BCheckBox* fAllowBold; + BCheckBox* fUseOptionAsMetaKey; BCheckBox* fWarnOnExit; BMenuField* fFontField; diff --git a/src/apps/terminal/PrefHandler.cpp b/src/apps/terminal/PrefHandler.cpp index 99bf741ede..458f7f33ec 100644 --- a/src/apps/terminal/PrefHandler.cpp +++ b/src/apps/terminal/PrefHandler.cpp @@ -9,6 +9,7 @@ * Authors: * Kian Duffy, myob@users.sourceforge.net * Daniel Furrer, assimil8or@users.sourceforge.net + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ @@ -89,6 +90,7 @@ static const pref_defaults kTermDefaults[] = { { PREF_TAB_TITLE, "%1d: %p%e" }, { PREF_WINDOW_TITLE, "%T% i: %t" }, { PREF_BLINK_CURSOR, PREF_TRUE }, + { PREF_USE_OPTION_AS_META, PREF_FALSE }, { PREF_WARN_ON_EXIT, PREF_TRUE }, { PREF_CURSOR_STYLE, PREF_BLOCK_CURSOR }, { PREF_EMULATE_BOLD, PREF_FALSE }, diff --git a/src/apps/terminal/TermApp.cpp b/src/apps/terminal/TermApp.cpp index 3c63582a07..ff1328c672 100644 --- a/src/apps/terminal/TermApp.cpp +++ b/src/apps/terminal/TermApp.cpp @@ -8,6 +8,7 @@ * Authors: * Jeremiah Bailey, * Kian Duffy, + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, */ @@ -179,6 +180,10 @@ void TermApp::MessageReceived(BMessage* message) { switch (message->what) { + case B_KEY_MAP_LOADED: + fTermWindow->PostMessage(message); + break; + case MSG_ACTIVATE_TERM: fTermWindow->Activate(); break; diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index 0f25319623..b4e01a5902 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -7,6 +7,7 @@ * * Authors: * Kian Duffy, myob@users.sourceforge.net + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ #ifndef TERMCONST_H_INCLUDED @@ -79,6 +80,7 @@ static const uint32 MSG_SET_TERMINAL_TITLE = 'sett'; static const uint32 MSG_SET_TERMINAL_COLORS = 'setc'; static const uint32 MSG_RESET_TERMINAL_COLORS = 'rstc'; static const uint32 MSG_QUIT_TERMNAL = 'qutt'; +static const uint32 MSG_ENABLE_META_KEY = 'emtk'; static const uint32 MSG_REPORT_MOUSE_EVENT = 'mous'; static const uint32 MSG_SAVE_WINDOW_POSITION = 'swps'; static const uint32 MSG_MOVE_TAB_LEFT = 'mvtl'; @@ -133,6 +135,8 @@ static const char* const PREF_TEXT_ENCODING = "Text encoding"; static const char* const PREF_BLINK_CURSOR = "Blinking cursor"; static const char* const PREF_ALLOW_BOLD = "Allow bold text"; +static const char* const PREF_USE_OPTION_AS_META = + "Use left Option as Meta key"; static const char* const PREF_WARN_ON_EXIT = "Warn on exit"; static const char* const PREF_CURSOR_STYLE = "Cursor style"; static const char* const PREF_EMULATE_BOLD = "Emulate bold"; diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index b8ac127e14..aaec4e1bd1 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -6,6 +6,7 @@ * * Authors: * Kian Duffy, myob@users.sourceforge.net + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ @@ -1395,12 +1396,12 @@ TermParse::_DecPrivateModeSet(int value) fBuffer->ReportAnyMouseEvent(true); break; case 1034: - // TODO: Interprete "meta" key, sets eighth bit. - // Not supported yet. + // Interpret "meta" key, sets eighth bit. + fBuffer->EnableInterpretMetaKey(true); break; case 1036: - // TODO: Send ESC when Meta modifies a key - // Not supported yet. + // Send ESC when Meta modifies a key + fBuffer->EnableMetaKeySendsEscape(true); break; case 1039: // TODO: Send ESC when Alt modifies a key @@ -1470,12 +1471,12 @@ TermParse::_DecPrivateModeReset(int value) fBuffer->ReportAnyMouseEvent(false); break; case 1034: - // Don't interprete "meta" key. - // Not supported yet. + // Don't interpret "meta" key. + fBuffer->EnableInterpretMetaKey(false); break; case 1036: - // TODO: Don't send ESC when Meta modifies a key - // Not supported yet. + // Don't send ESC when Meta modifies a key + fBuffer->EnableMetaKeySendsEscape(false); break; case 1039: // TODO: Don't send ESC when Alt modifies a key diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index f29c61586c..c574fc9c5f 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -9,6 +9,7 @@ * Kian Duffy, myob@users.sourceforge.net * Y.Hayakawa, hida@sawada.riec.tohoku.ac.jp * Jonathan Schleifer, js@webkeks.org + * Simon South, simon@simonsouth.net * Ingo Weinhold, ingo_weinhold@gmx.de * Clemens Zeidler, haiku@Clemens-Zeidler.de * Siarzhuk Zharski, zharik@gmx.li @@ -307,6 +308,11 @@ TermView::_InitObject(const ShellParameters& shellParameters) fSelection.SetHighlighter(this); fSelection.SetRange(TermPos(0, 0), TermPos(0, 0)); fPrevPos = TermPos(-1, - 1); + fKeymap = NULL; + fKeymapChars = NULL; + fUseOptionAsMetaKey = false; + fInterpretMetaKey = true; + fMetaKeySendsEscape = true; fReportX10MouseEvent = false; fReportNormalMouseEvent = false; fReportButtonMouseEvent = false; @@ -719,6 +725,33 @@ TermView::SetEncoding(int encoding) } +void +TermView::SetKeymap(const key_map* keymap, const char* chars) +{ + delete fKeymap; + delete[] fKeymapChars; + + fKeymap = keymap; + fKeymapChars = chars; + + fKeymapTableForModifiers.Put(B_SHIFT_KEY, + &fKeymap->shift_map); + fKeymapTableForModifiers.Put(B_CAPS_LOCK, + &fKeymap->caps_map); + fKeymapTableForModifiers.Put(B_CAPS_LOCK | B_SHIFT_KEY, + &fKeymap->caps_shift_map); + fKeymapTableForModifiers.Put(B_CONTROL_KEY, + &fKeymap->control_map); +} + + +void +TermView::SetUseOptionAsMetaKey(bool enable) +{ + fUseOptionAsMetaKey = enable && fKeymap != NULL && fKeymapChars != NULL; +} + + void TermView::SetMouseClipboard(BClipboard *clipboard) { @@ -1801,6 +1834,16 @@ TermView::MessageReceived(BMessage *msg) fCursorHidden = hidden; break; } + case MSG_ENABLE_META_KEY: + { + bool enable; + if (msg->FindBool("enableInterpretMetaKey", &enable) == B_OK) + fInterpretMetaKey = enable; + + if (msg->FindBool("enableMetaKeySendsEscape", &enable) == B_OK) + fMetaKeySendsEscape = enable; + break; + } case MSG_REPORT_MOUSE_EVENT: { bool report; diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index 364682342a..366f6913e5 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -7,6 +7,7 @@ * Authors: * Stefano Ceccherini, stefano.ceccherini@gmail.com * Kian Duffy, myob@users.sourceforge.net + * Simon South, simon@simonsouth.net * Ingo Weinhold, ingo_weinhold@gmx.de * Siarzhuk Zharski, zharik@gmx.li */ @@ -15,6 +16,8 @@ #include +#include +#include #include #include #include @@ -98,6 +101,10 @@ public: void SetScrollBar(BScrollBar* scrollBar); BScrollBar* ScrollBar() const { return fScrollBar; }; + void SetKeymap(const key_map* keymap, + const char* chars); + void SetUseOptionAsMetaKey(bool enable); + void SetMouseClipboard(BClipboard *); void MakeDebugSnapshots(); @@ -335,6 +342,15 @@ private: HighlightList fHighlights; + // keyboard + const key_map* fKeymap; + const char* fKeymapChars; + HashMap, const int(*)[128]> + fKeymapTableForModifiers; + bool fUseOptionAsMetaKey; + bool fInterpretMetaKey; + bool fMetaKeySendsEscape; + // mouse int32 fMouseButtons; int32 fModifiers; diff --git a/src/apps/terminal/TermViewStates.cpp b/src/apps/terminal/TermViewStates.cpp index e24fa8dc91..706ca3f588 100644 --- a/src/apps/terminal/TermViewStates.cpp +++ b/src/apps/terminal/TermViewStates.cpp @@ -8,6 +8,7 @@ * Stefano Ceccherini, stefano.ceccherini@gmail.com * Kian Duffy, myob@users.sourceforge.net * Y.Hayakawa, hida@sawada.riec.tohoku.ac.jp + * Simon South, simon@simonsouth.net * Ingo Weinhold, ingo_weinhold@gmx.de * Clemens Zeidler, haiku@Clemens-Zeidler.de * Siarzhuk Zharski, zharik@gmx.li @@ -208,6 +209,55 @@ TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes) fView->_ActivateCursor(true); + // Handle the Option key when used as Meta + if ((mod & B_LEFT_OPTION_KEY) != 0 && fView->fUseOptionAsMetaKey + && (fView->fInterpretMetaKey || fView->fMetaKeySendsEscape)) { + const char* bytes; + int8 numBytes; + + // Determine the character produced by the same keypress without the + // Option key + mod &= B_SHIFT_KEY | B_CAPS_LOCK | B_CONTROL_KEY; + if (mod == 0) { + bytes = (const char*)&rawChar; + numBytes = 1; + } else { + const int (*keymapTable)[128] = + fView->fKeymapTableForModifiers.Get(mod); + bytes = &fView->fKeymapChars[(*keymapTable)[key]]; + numBytes = *(bytes++); + } + + if (numBytes <= 0) + return; + + fView->_ScrollTo(0, true); + + char outputBuffer[2]; + const char* toWrite = bytes; + + if (fView->fMetaKeySendsEscape) { + fView->fShell->Write("\e", 1); + } else if (numBytes == 1) { + char byte = *bytes | 0x80; + + // The eighth bit has special meaning in UTF-8, so if that encoding + // is in use recode the output (as xterm does) + if (fView->fEncoding == M_UTF8) { + outputBuffer[0] = 0xc0 | ((byte >> 6) & 0x03); + outputBuffer[1] = 0x80 | (byte & 0x3f); + numBytes = 2; + } else { + outputBuffer[0] = byte; + numBytes = 1; + } + toWrite = outputBuffer; + } + + fView->fShell->Write(toWrite, numBytes); + return; + } + // handle multi-byte chars if (numBytes > 1) { if (fView->fEncoding != M_UTF8) { diff --git a/src/apps/terminal/TermWindow.cpp b/src/apps/terminal/TermWindow.cpp index 056ad77faf..d1752fe784 100644 --- a/src/apps/terminal/TermWindow.cpp +++ b/src/apps/terminal/TermWindow.cpp @@ -10,6 +10,7 @@ * Kian Duffy, myob@users.sourceforge.net * Daniel Furrer, assimil8or@users.sourceforge.net * John Scipione, jscipione@gmail.com + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ @@ -202,6 +203,9 @@ TermWindow::TermWindow(const BString& title, Arguments* args) fTerminalRoster.SetListener(this); int32 id = fTerminalRoster.ID(); + // fetch the current keymap + get_key_map(&fKeymap, &fKeymapChars); + // apply the title settings fTitle.pattern = title; if (fTitle.pattern.Length() == 0) { @@ -272,6 +276,9 @@ TermWindow::~TermWindow() for (int32 i = 0; Session* session = _SessionAt(i); i++) delete session; + + delete fKeymap; + delete[] fKeymapChars; } @@ -673,6 +680,10 @@ TermWindow::MessageReceived(BMessage *message) bool findresult; switch (message->what) { + case B_KEY_MAP_LOADED: + _UpdateKeymap(); + break; + case B_COPY: _ActiveTermView()->Copy(be_clipboard); break; @@ -895,6 +906,18 @@ TermWindow::MessageReceived(BMessage *message) break; } + case MSG_USE_OPTION_AS_META_CHANGED: + { + bool useOptionAsMetaKey + = PrefHandler::Default()->getBool(PREF_USE_OPTION_AS_META); + + for (int32 i = 0; i < fTabView->CountTabs(); i++) { + TermView* view = _TermViewAt(i); + view->SetUseOptionAsMetaKey(useOptionAsMetaKey); + } + break; + } + case FULLSCREEN: if (!fSavedFrame.IsValid()) { // go fullscreen _ActiveTermView()->DisableResizeView(); @@ -1306,6 +1329,10 @@ TermWindow::_AddTab(Arguments* args, const BString& currentDirectory) if (charset != NULL) view->SetEncoding(charset->GetConversionID()); + view->SetKeymap(fKeymap, fKeymapChars); + view->SetUseOptionAsMetaKey( + PrefHandler::Default()->getBool(PREF_USE_OPTION_AS_META)); + _SetTermColors(containerView); int32 tabIndex = fTabView->CountTabs() - 1; @@ -1994,3 +2021,18 @@ TermWindow::_MoveWindowInScreen(BWindow* window) BSize screenSize(BScreen(window).Frame().Size()); window->MoveTo(BLayoutUtils::MoveIntoFrame(frame, screenSize).LeftTop()); } + + +void +TermWindow::_UpdateKeymap() +{ + delete fKeymap; + delete[] fKeymapChars; + + get_key_map(&fKeymap, &fKeymapChars); + + for (int32 i = 0; i < fTabView->CountTabs(); i++) { + TermView* view = _TermViewAt(i); + view->SetKeymap(fKeymap, fKeymapChars); + } +} diff --git a/src/apps/terminal/TermWindow.h b/src/apps/terminal/TermWindow.h index f99157b833..ddc3415e71 100644 --- a/src/apps/terminal/TermWindow.h +++ b/src/apps/terminal/TermWindow.h @@ -32,6 +32,7 @@ #define TERM_WINDOW_H +#include #include #include #include @@ -188,6 +189,8 @@ private: void _MoveWindowInScreen(BWindow* window); + void _UpdateKeymap(); + private: TerminalRoster fTerminalRoster; @@ -228,6 +231,9 @@ private: bool fMatchWord; bool fFullScreen; + + key_map* fKeymap; + char* fKeymapChars; }; diff --git a/src/apps/terminal/TerminalBuffer.cpp b/src/apps/terminal/TerminalBuffer.cpp index 396cd728cb..2637285f00 100644 --- a/src/apps/terminal/TerminalBuffer.cpp +++ b/src/apps/terminal/TerminalBuffer.cpp @@ -5,6 +5,7 @@ * * Authors: * Ingo Weinhold, ingo_weinhold@gmx.de + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ @@ -90,6 +91,28 @@ TerminalBuffer::Encoding() const } +void +TerminalBuffer::EnableInterpretMetaKey(bool enable) +{ + if (fListenerValid) { + BMessage message(MSG_ENABLE_META_KEY); + message.AddBool("enableInterpretMetaKey", enable); + fListener.SendMessage(&message); + } +} + + +void +TerminalBuffer::EnableMetaKeySendsEscape(bool enable) +{ + if (fListenerValid) { + BMessage message(MSG_ENABLE_META_KEY); + message.AddBool("enableMetaKeySendsEscape", enable); + fListener.SendMessage(&message); + } +} + + void TerminalBuffer::ReportX10MouseEvent(bool reportX10MouseEvent) { diff --git a/src/apps/terminal/TerminalBuffer.h b/src/apps/terminal/TerminalBuffer.h index aa856beb6d..e4d198765e 100644 --- a/src/apps/terminal/TerminalBuffer.h +++ b/src/apps/terminal/TerminalBuffer.h @@ -5,6 +5,7 @@ * * Authors: * Ingo Weinhold, ingo_weinhold@gmx.de + * Simon South, simon@simonsouth.net * Siarzhuk Zharski, zharik@gmx.li */ #ifndef TERMINAL_BUFFER_H @@ -52,6 +53,9 @@ public: void UseAlternateScreenBuffer(bool clear); void UseNormalScreenBuffer(); + void EnableInterpretMetaKey(bool enable); + void EnableMetaKeySendsEscape(bool enable); + void ReportX10MouseEvent(bool report); void ReportNormalMouseEvent(bool report); void ReportButtonMouseEvent(bool report);