--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/terminalkeyboardcons/terminalkeyboardcons.cpp Mon Aug 23 18:10:31 2010 +0100
@@ -0,0 +1,393 @@
+// terminalkeyboardcons.cpp
+//
+// Copyright (c) 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+#include "terminalkeyboardcons.h"
+#include <fshell/common.mmh>
+#include <e32debug.h>
+#include <fshell/memoryaccess.h>
+
+const TInt KTkbdMessageId = 0xD6;
+// These are the defaults unless overridden by --console-size
+const TInt KWidth = 80;
+const TInt KHeight = 24;
+
+class CMessageWatcher : public CActive
+ {
+public:
+ CMessageWatcher(CTerminalKeyboardCons& aConsole)
+ : CActive(CActive::EPriorityStandard), iConsole(aConsole)
+ {
+ CActiveScheduler::Add(this);
+ iConsole.iDriver.RequestMessage(iStatus);
+ SetActive();
+ }
+
+ void DoCancel()
+ {
+ iConsole.iDriver.CancelMessage();
+ }
+
+ void RunL()
+ {
+ iConsole.MessageReceived(iStatus.Int());
+ if (iStatus.Int() == KErrNone)
+ {
+ iConsole.iDriver.RequestMessage(iStatus);
+ SetActive();
+ }
+ }
+
+ ~CMessageWatcher()
+ {
+ Cancel();
+ }
+
+private:
+ CTerminalKeyboardCons& iConsole;
+ };
+
+
+CTerminalKeyboardCons::CTerminalKeyboardCons()
+ : iTracker(TSize(KWidth, KHeight), this)
+ {
+ }
+
+CTerminalKeyboardCons::~CTerminalKeyboardCons()
+ {
+ CleanupUnderlyingConsole();
+ delete iWatcher;
+ iDriver.Close();
+ iTextBuffer.Close();
+ iMungedTextBuffer.Close();
+ }
+
+TInt CTerminalKeyboardCons::Create(const TDesC& aTitle, TSize aSize)
+ {
+ TRAPD(err, ConstructL(aTitle, aSize));
+ HandleConsoleCreationError(_L("TerminalKeyboard"), err);
+ return err;
+ }
+
+void CTerminalKeyboardCons::ConstructL(const TDesC& aTitle, const TSize& aSize)
+ {
+ if (aTitle == _L("debug")) SetDebug(ETrue);
+ if (aSize.iWidth > 10 && aSize.iHeight > 10)
+ {
+ // Override size now we know it, checking that it's sane-ish - be sure to do this before anything that uses the console size!
+ new (&iTracker) TCursorTracker(aSize, this);
+ }
+
+ iTextBuffer.CreateMaxL(ScreenSize().iWidth * ScreenSize().iHeight);
+#ifdef SHOW_TEXTSHELL_BORDERS
+ iMungedTextBuffer.CreateL((ScreenSize().iWidth + 2) * (ScreenSize().iHeight + 2));
+#endif
+
+ TInt err = User::LoadLogicalDevice(KTcLddDriverName);
+ if (err && err != KErrAlreadyExists)
+ {
+ Message(EError, _L("Couldn't load LDD %S: %d"), &KTcLddDriverName, err);
+ User::Leave(err);
+ }
+
+ // Idiotic driver only accepts connections from processes with nokia vid - like that will stop us
+ TUint originalVid = RProcess().VendorId();
+ RMemoryAccess memAccess;
+ User::LeaveIfError(memAccess.Open());
+ TProcessProperties props;
+ props.iVid = 0x101FB657;
+ RProcess me; me.Open(RProcess().Id());
+ memAccess.SetProcessProperties(me, props);
+
+ err = iDriver.Open();
+
+ props.iVid = originalVid;
+ memAccess.SetProcessProperties(me, props);
+ me.Close();
+ memAccess.Close();
+
+ if (err)
+ {
+ Message(EError, _L("Couldn't open RTcDriver: %d"), err);
+ User::Leave(err);
+ }
+
+ err = iDriver.Subscribe(KTkbdMessageId);
+ if (err)
+ {
+ Message(EError, _L("Couldn't subscribe: %d"), err);
+ User::Leave(err);
+ }
+
+ iWatcher = new(ELeave) CMessageWatcher(*this);
+ CleanupUnderlyingConsole();
+
+ ClearScreen();
+ }
+
+
+TInt CTerminalKeyboardCons::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+ {
+ /*if (aExtensionId == ConsoleMode::KSetConsoleModeExtension)
+ {
+ ConsoleMode::TMode mode = (ConsoleMode::TMode)(TInt)a1;
+ iInputController->SetMode(mode);
+ iOutputController->SetMode(mode);
+ return KErrNone;
+ }
+ else*/
+ /*else if (aExtensionId == ConsoleAttributes::KSetConsoleAttributesExtension)
+ {
+ ConsoleAttributes::TAttributes* attributes = (ConsoleAttributes::TAttributes*)a1;
+ return iOutputController->SetAttributes(attributes->iAttributes, attributes->iForegroundColor, attributes->iBackgroundColor);
+ }*/
+
+ TInt ret = MIosrvConsoleHelper_Extension(aExtensionId, a0, a1);
+ if (ret == KErrExtensionNotSupported) ret = CConsoleBase::Extension_(aExtensionId, a0, a1);
+ return ret;
+ }
+
+void CTerminalKeyboardCons::MessageReceived(TInt aError)
+ {
+ Message(EDebug, _L("MessageReceived err=%d"), aError);
+ TInt err = aError;
+ if (err == KErrNone)
+ {
+ TPtrC8 data;
+ err = iDriver.GetMessageData(data);
+ if (!err && data.Length() < 1) err = KErrCorrupt;
+ if (!err && !iGotKey)
+ {
+ TUint16 rawkey = data[0];
+ Message(EDebug, _L("CTerminalKeyboardCons got key %d"), (TInt)rawkey);
+
+ // Terminal keyboard doesn't support control keys or cursor keys so we use our own two-stage sticky modifier (like unix meta key I think?)
+ if (iBacktickModifierDown)
+ {
+ // Terminal keyboard sends 2,4,6,8 for cursors, so we translate backtick-2 (ie backtick-leftarrow) as meaning left arrow
+ if (rawkey == '2') rawkey = (TUint16)EKeyUpArrow;
+ else if (rawkey == '4') rawkey = (TUint16)EKeyLeftArrow;
+ else if (rawkey == '6') rawkey = (TUint16)EKeyRightArrow;
+ else if (rawkey == '8') rawkey = (TUint16)EKeyDownArrow;
+ else if (rawkey >= 'a' && rawkey <= 'z')
+ {
+ // backtick-c means CTRL-C
+ rawkey = rawkey - 'a'+1;
+ }
+ else if (rawkey == ' ') rawkey = '`'; // backtick-space is how you do a backtick
+ else if (rawkey == '`') rawkey = (TUint16)EKeyEscape; // backtick-backtick is 'escape'
+ else if (rawkey == '1') rawkey = (TUint16)EKeyTab; // backtick-1 is 'tab'
+ iBacktickModifierDown = EFalse;
+ Message(EDebug, _L("Backtick escape converted to %d"), (TInt)rawkey);
+ }
+ else if (rawkey == '`')
+ {
+ iBacktickModifierDown = ETrue;
+ return;
+ }
+
+ iKeyCode = (TKeyCode)rawkey; // Close enough for now!
+ iGotKey = ETrue;
+ }
+ }
+ if (iClientStatus)
+ {
+ User::RequestComplete(iClientStatus, err);
+ if (err == KErrNone) iGotKey = EFalse;
+ }
+ }
+
+void CTerminalKeyboardCons::Read(TRequestStatus& aStatus)
+ {
+ /*if (iClientStatus)
+ {
+ TRequestStatus* stat = &aStatus;
+ User::RequestComplete(stat, KErrInUse);
+ }
+ else*/
+ {
+ aStatus = KRequestPending;
+ iClientStatus = &aStatus;
+ if (iGotKey)
+ {
+ iGotKey = EFalse;
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ }
+ }
+
+void CTerminalKeyboardCons::ReadCancel()
+ {
+ if (iClientStatus)
+ {
+ User::RequestComplete(iClientStatus, KErrCancel);
+ }
+ }
+
+void CTerminalKeyboardCons::Write(const TDesC& aDes)
+ {
+ for (TInt i = 0; i < aDes.Length(); i++)
+ {
+ TInt textBufPos = CursorPos().iY * ScreenSize().iWidth + CursorPos().iX;
+ TChar ch(aDes[i]);
+ iTracker.WriteChar(ch);
+ if (ch.IsPrint()) iTextBuffer[textBufPos] = aDes[i];
+ }
+
+ Update();
+ }
+
+TPoint CTerminalKeyboardCons::CursorPos() const
+ {
+ return iTracker.CursorPos();
+ }
+
+void CTerminalKeyboardCons::SetCursorPosAbs(const TPoint& aPoint)
+ {
+ iTracker.SetCursorPosAbs(aPoint);
+ }
+
+void CTerminalKeyboardCons::SetCursorPosRel(const TPoint& aPoint)
+ {
+ iTracker.SetCursorPosRel(aPoint);
+ }
+
+void CTerminalKeyboardCons::SetCursorHeight(TInt /*aPercentage*/)
+ {
+ //iOutputController->SetCursorHeight(aPercentage);
+ }
+
+void CTerminalKeyboardCons::SetTitle(const TDesC& /*aDes*/)
+ {
+ //iOutputController->SetTitle(aDes);
+ }
+
+void CTerminalKeyboardCons::ClearScreen()
+ {
+ SetCursorPosAbs(TPoint(0,0));
+ iTextBuffer.Fill(' ');
+ Update();
+ }
+
+void CTerminalKeyboardCons::ClearToEndOfLine()
+ {
+ iTextBuffer.MidTPtr(CursorPos().iY * ScreenSize().iWidth + CursorPos().iX, ScreenSize().iWidth - CursorPos().iX).Fill(' ');
+ Update();
+ }
+
+TSize CTerminalKeyboardCons::ScreenSize() const
+ {
+ return iTracker.ConsoleSize();
+ }
+
+TKeyCode CTerminalKeyboardCons::KeyCode() const
+ {
+ return iKeyCode;
+ }
+
+TUint CTerminalKeyboardCons::KeyModifiers() const
+ {
+ return iKeyModifiers;
+ }
+
+// All these magic vals are as per the DOS 437 codepage http://en.wikipedia.org/wiki/CP437 and not Windows-1252 like the ws_win.cpp source incorrectly states
+// See also http://en.wikipedia.org/wiki/Box_drawing_characters
+enum
+ {
+ EBoxHorizontalBar = 0xCD,
+ EBoxVerticalBar = 0xBA,
+ EBoxTopLeft = 0xC9,
+ EBoxTopRight = 0xBB,
+ EBoxBottomLeft = 0xC8,
+ EBoxBottomRight = 0xBC,
+ };
+
+void CTerminalKeyboardCons::Update()
+ {
+#ifdef SHOW_TEXTSHELL_BORDERS
+ // Update munged buffer
+ const TInt contentWidth = ScreenSize().iWidth;
+ const TInt width = contentWidth + 2;
+ iMungedTextBuffer.SetLength(width);
+ iMungedTextBuffer.Fill(TChar(EBoxHorizontalBar));
+ iMungedTextBuffer[0] = EBoxTopLeft;
+ iMungedTextBuffer[width-1] = EBoxTopRight;
+
+ for (TInt i = 0; i < ScreenSize().iHeight; i++)
+ {
+ TPtrC line(iTextBuffer.Mid(i*contentWidth, contentWidth));
+ iMungedTextBuffer.AppendFormat(_L("%c%S%c"), EBoxVerticalBar, &line, EBoxVerticalBar);
+ }
+
+ iMungedTextBuffer.Append(EBoxBottomLeft);
+ iMungedTextBuffer.SetLength(iMungedTextBuffer.Length() + contentWidth);
+ iMungedTextBuffer.RightTPtr(contentWidth).Fill(EBoxHorizontalBar);
+ iMungedTextBuffer.Append(EBoxBottomRight);
+
+ // And send the munged buffer
+ Transmit(iMungedTextBuffer, width, ScreenSize().iHeight + 2);
+#else
+ // Just send it straight
+ Transmit(iTextBuffer, ScreenSize().iWidth, ScreenSize().iHeight);
+#endif
+ }
+
+void CTerminalKeyboardCons::Transmit(const TDesC& aBuf, TInt aWidth, TInt aHeight)
+ {
+ // This is how terminal keyboard does it - pretty horrible really
+
+ static const TInt KMaxLen = 200; // This is what terminal keyboard uses - technically you could go as far as a total of 256
+ TInt numLinesPerPrint = KMaxLen / aWidth;
+
+ TBuf<256> line;
+ TInt startLine = 0;
+ while (startLine < aHeight)
+ {
+ if (startLine == 0)
+ {
+ // First line has extra info
+ line.Format(_L("#$STIConsole#$%02d%02X%02X"), startLine, aWidth, aHeight);
+ }
+ else
+ {
+ line.Format(_L("#$STIConsole#$%02d"), startLine);
+ }
+
+ for (TInt i = 0; i < numLinesPerPrint; i++)
+ {
+ TPtrC theContents(aBuf.Mid((startLine+i)*aWidth, aWidth));
+ //RDebug::Printf("line len=%d theContents len=%d", line.Length(), theContents.Length());
+ line.Append(theContents);
+ }
+
+ RDebug::Print(line);
+ startLine += numLinesPerPrint;
+ }
+ }
+
+void CTerminalKeyboardCons::ConsoleScrolled(TInt aNumberOfLines)
+ {
+ TInt numChars = Abs(aNumberOfLines) * ScreenSize().iWidth;
+ if (aNumberOfLines > 0)
+ {
+ iTextBuffer.Delete(0, numChars);
+ iTextBuffer.AppendFill(' ', numChars);
+ }
+ else if (aNumberOfLines < 0)
+ {
+ iTextBuffer.SetLength(iTextBuffer.Length() - numChars);
+ while (numChars--) iTextBuffer.Insert(0, _L(" "));
+ }
+ }
+
+extern "C" EXPORT_C TAny* NewConsole()
+ {
+ return new CTerminalKeyboardCons;
+ }