diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js
index d0119a91776289d371dd6c658ee68cbbc5604d9a..809db2f2332969f5f2ded77a67831e6a9c8697bf 100644
--- a/exec/SlyEdit.js
+++ b/exec/SlyEdit.js
@@ -13,46 +13,21 @@
  * 2009-08-22 Eric Oulashin     Version 1.00
  *                              Initial public release
  * ....Removed some comments...
- * 2013-10-22 Eric Oulashin     Version 1.36 Beta
- *                              Worked on debugging & fixing a bug when quoting
- *                              with author initials to fix a bug where a large
- *                              section in certain messages wasn't getting quoted.
- * 2013-10-28 Eric Oulashin     Version 1.36
- *                              Releasing this version, as it seems to be quoting
- *                              all messages well with author initials.
- * 2013-11-09 Eric Oulashin     Version 1.37 Beta
- *                              Started trying to debug an issue where SlyEdit
- *                              sometimes uses the replying user's initials
- *                              in the last line of a paragraph of the original
- *                              author's message.
- * 2013-11-10 Eric Oulashin     Version 1.37
- *                              Releasing this version
- * 2013-11-11 Eric Oulashin     Version 1.38
- *                              Minor bug fix: If there are no text replacements
- *                              to list when the user tries to list them, the cursor
- *                              now returns to its proper place after displaying
- *                              the error.
- * 2013-11-25 Eric Oulashin     Version 1.39 Beta
- *                              Minor bug fix in wrapQuoteLinesUsingAuthorInitials() in
- *                              SlyEdit_Misc.js starting on line 2739: Added more
- *                              checks to ensure that the gQuoteLines object it
- *                              references is valid.
- *                              Minor bug fix: Updated the Ice-style color display
- *                              for the control key help text in the lower right so
- *                              that normal/high attributes don't interfere with the
- *                              high blue color of the parenthesis.
- * 2013-11-27 Eric Oulashin     Version 1.39
- *                              Releasing this version after having done some testing.
- * 2014-05-12 Eric Oulashin     Version 1.40 (not released yet)
- *                              Added a check in wrapQuoteLinesUsingAuthorInitials() in
- *                              SlyEdit_Misc.js: When building the last section info object,
- *                              added a check to the while loop that makes sure
- *                              sectionInfo.endArrIndex is greater than 0 to avoid an index
- *                              out-of-bounds issue with the check that references
- *                              gQuoteLines[sectionInfo.endArrIndex-1].  This should hopefully
- *                              fix a bug with SlyEdit crashing at that point.
- * 2014-05-21 Eric Oulashin     Version 1.40
- *                              Going ahead and releasing this version
+ * 2014-11-01 Eric Oulashin     Version 1.41 Beta
+ *                              Added support for PageUp & PageDown keys for
+ *                              message & quote line scrolling
+ * 2014-11-08 Eric OUlashin     Started working on improved paragraph detection
+ *                              for paragraphs where the first line is indented
+ *                              when wrapping non-quoted text in reply messages
+ * 2014-11-09 Eric Oulashin     Bug fix in doQuoteSelection(): Reset gQuoteLinesIndex
+ *                              to 0 when re-formatting the quote lines to ensure
+ *                              valid behavior.  gQuoteLinesTopIndex was already
+ *                              being reset to 0.
+ * 2014-11-15 Eric Oulashin     Version 1.41
+ *                              Decided to release this version with the PageUp/PageDown
+ *                              key support, improved paragraph detetion & wrapping
+ *                              for quote lines, backspace fix, and fixed DCT quote
+ *                              window top border for wide terminals.
  */
 
 /* Command-line arguments:
@@ -130,8 +105,8 @@ if (!console.term_supports(USER_ANSI))
 }
 
 // Constants
-const EDITOR_VERSION = "1.40";
-const EDITOR_VER_DATE = "2014-05-21";
+const EDITOR_VERSION = "1.41";
+const EDITOR_VER_DATE = "2014-11-15";
 
 
 // Program variables
@@ -387,6 +362,9 @@ bbs.sys_status &=~SS_PAUSEON;
 bbs.sys_status |= SS_PAUSEOFF;
 var gOldPassthru = console.ctrlkey_passthru;
 console.ctrlkey_passthru = "+ACGKLOPQRTUVWXYZ_";
+// Set some on-exit code to ensure that the original ctrl key passthru & system
+// status settings are restored upon script exit, even if there is a runtime error.
+js.on_exit("console.ctrlkey_passthru = gOldPassthru; bbs.sys_status = gOldStatus;");
 // Enable delete line in SyncTERM (Disabling ANSI Music in the process)
 console.write("\033[=1M");
 console.clear();
@@ -797,10 +775,8 @@ function doEditLoop()
    const CMDLIST_HELP_KEY          = CTRL_P;
    const QUOTE_KEY                 = CTRL_Q;
    const PROGRAM_INFO_HELP_KEY     = CTRL_R;
-   const PAGE_DOWN_KEY             = CTRL_S;
    const LIST_TXT_REPLACEMENTS_KEY = CTRL_T;
    const USER_SETTINGS_KEY         = CTRL_U;
-   const PAGE_UP_KEY               = CTRL_W;
    const EXPORT_FILE_KEY           = CTRL_X;
    const SAVE_KEY                  = CTRL_Z;
 
@@ -829,7 +805,7 @@ function doEditLoop()
    var continueOn = true;
    while (continueOn)
    {
-      userInput = getUserKey(K_NOCRLF|K_NOSPIN, gConfigSettings);
+      userInput = getKeyWithESCChars(K_NOCRLF|K_NOSPIN, gConfigSettings);
       // If userInput is blank, then the input timeout was probably
       // reached, so abort.
       if (userInput == "")
@@ -870,6 +846,7 @@ function doEditLoop()
             returnCode = 0; // Save
             continueOn = false;
             break;
+         case KEY_F1:
          case CMDLIST_HELP_KEY:
             displayCommandList(true, true, true, gCanCrossPost, gConfigSettings.userIsSysop,
                                gConfigSettings.enableTextReplacements, gConfigSettings.allowUserSettings);
@@ -1249,7 +1226,7 @@ function doEditLoop()
             currentWordLength = retObj.currentWordLength;
             console.print(chooseEditColor()); // Make sure the edit color is correct
             break;
-         case PAGE_UP_KEY: // Move 1 page up in the message
+         case KEY_PAGE_UP: // Move 1 page up in the message
             // Calculate the index of the message line shown at the top
             // of the edit area.
             var topEditIndex = gEditLinesIndex-(curpos.y-gEditTop);
@@ -1296,7 +1273,7 @@ function doEditLoop()
             }
             console.print(chooseEditColor()); // Make sure the edit color is correct
             break;
-         case PAGE_DOWN_KEY: // Move 1 page down in the message
+         case KEY_PAGE_DOWN: // Move 1 page down in the message
             // Calculate the index of the message line shown at the top
             // of the edit area, and the index of the line that would be
             // shown at the bottom of the edit area.
@@ -1576,6 +1553,11 @@ function doBackspace(pCurpos, pCurrentWordLength)
             // previous line.
             if (gEditLines[prevLineIndex].length() <= gEditWidth-1)
             {
+               // Copy the current line's "hard newline end" setting to the
+               // previous line (so that if there's a blank line below the
+               // current line, the blank line will be preserved), then remove
+               // the current edit line.
+               gEditLines[gEditLinesIndex-1].hardNewlineEnd = gEditLines[gEditLinesIndex].hardNewlineEnd;
                gEditLines.splice(gEditLinesIndex, 1);
 
                --gEditLinesIndex;
@@ -1866,10 +1848,6 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength)
    // on the screen.
    if ((reAdjusted && (gEditLines[gEditLinesIndex].text != originalAfterCharApplied)) || madeTxtReplacement)
    {
-      // TODO: In case the user entered a whole line of text without any spaces,
-      // the new character would appear on the next line, so we need to figure
-      // out where the cursor location should be.
-
       // If gTextLineIndex is >= gEditLines[gEditLinesIndex].length(), then
       // we know the current word was wrapped to the next line.  Figure out what
       // retObj.x, retObj.currentWordLength, gEditLinesIndex, and gTextLineIndex
@@ -1877,8 +1855,8 @@ function doPrintableChar(pUserInput, pCurpos, pCurrentWordLength)
       // screen to update, and deal with scrolling if necessary.
       if (gTextLineIndex >= gEditLines[gEditLinesIndex].length())
       {
-         // TODO: I changed this on 2010-02-14 to (hopefully) place the cursor
-         // where it should be 
+         // I changed this on 2010-02-14 to (hopefully) place the cursor where
+         // it should be
          // Old line (prior to 2010-02-14):
          //var numChars = gTextLineIndex - gEditLines[gEditLinesIndex].length();
          // New (2010-02-14):
@@ -2441,7 +2419,10 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
                gQuoteLines.push(doQuoteSelection.backupQuoteLines[i]);
          }
 
-         gQuoteLinesTopIndex = gQuoteLinesIndex = 0; // To prevent bad things
+         // Reset the selected quote line index & top displayed quote line index
+         // back to 0 to ensure valid screen display & scrolling behavior
+         gQuoteLinesIndex = 0;
+         gQuoteLinesTopIndex = 0;
 
          // Update the quote line prefix text and wrap the quote lines
          setQuotePrefix();
@@ -2469,6 +2450,12 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
    const quoteWinTopScreenRow = quoteTopScreenRow-1;
    const quoteWinWidth = gEditRight - gEditLeft + 1;
 
+   // For pageUp/pageDown functionality - Calculate the top quote line index
+   // for the last page.
+   var quoteWinInnerHeight = quoteBottomScreenRow - quoteTopScreenRow + 1; // # of quote lines in the quote window
+   var numPages = Math.ceil(gQuoteLines.length / quoteWinInnerHeight);
+   var topIndexForLastPage = (quoteWinInnerHeight * numPages) - quoteWinInnerHeight;
+
    // Display the top border of the quote window.
    fpDrawQuoteWindowTopBorder(quoteWinHeight, gEditLeft, gEditRight);
 
@@ -2487,7 +2474,7 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
    while (continueOn)
    {
       // Get a keypress from the user
-      userInput = getUserKey(K_UPPER|K_NOCRLF|K_NOSPIN, gConfigSettings);
+      userInput = getKeyWithESCChars(K_UPPER|K_NOCRLF|K_NOSPIN|K_NOECHO, gConfigSettings);
       if (userInput == "")
       {
          // The input timeout was reached.  Abort.
@@ -2549,6 +2536,93 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
             screenLine = downRetObj.screenLine;
             quoteLine = downRetObj.quoteLine;
             break;
+         case KEY_HOME: // Select the first quote line on the current page
+            if (gQuoteLinesIndex != gQuoteLinesTopIndex)
+            {
+               gQuoteLinesIndex = gQuoteLinesTopIndex;
+               // Write the current quote line with unhighlighted colors
+               console.gotoxy(gEditLeft, screenLine);
+               printf(gFormatStrWithAttr, gQuoteWinTextColor, quoteLine);
+               // Calculate the new screen line and draw the new quote line with
+               // highlighted colors
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               console.gotoxy(gEditLeft, screenLine);
+               printf(gFormatStrWithAttr, gQuoteLineHighlightColor, quoteLine);
+               console.gotoxy(gEditLeft, screenLine);
+            }
+            break;
+         case KEY_END: // Select the last quote line on the current page
+            var lastIndexForCurrentPage = gQuoteLinesTopIndex + quoteWinInnerHeight - 1;
+            if (gQuoteLinesIndex != lastIndexForCurrentPage)
+            {
+               gQuoteLinesIndex = lastIndexForCurrentPage;
+               // Write the current quote line with unhighlighted colors
+               console.gotoxy(gEditLeft, screenLine);
+               printf(gFormatStrWithAttr, gQuoteWinTextColor, quoteLine);
+               // Calculate the new screen line and draw the new quote line with
+               // highlighted colors
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               console.gotoxy(gEditLeft, screenLine);
+               printf(gFormatStrWithAttr, gQuoteLineHighlightColor, quoteLine);
+               console.gotoxy(gEditLeft, screenLine);
+            }
+            break;
+         case KEY_PAGE_UP: // Go up 1 page in the quote lines
+            // If the current top quote line index is greater than 0, then go to
+            // the previous page of quote lines and select the top index on that
+            // page as the current selected quote line.
+            if (gQuoteLinesTopIndex > 0)
+            {
+               gQuoteLinesTopIndex -= quoteWinInnerHeight;
+               if (gQuoteLinesTopIndex < 0)
+                  gQuoteLinesTopIndex = 0;
+               gQuoteLinesIndex = gQuoteLinesTopIndex;
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               displayQuoteWindowLines(gQuoteLinesTopIndex, quoteWinHeight, quoteWinWidth, true,
+                                       gQuoteLinesIndex);
+            }
+            break;
+         case KEY_PAGE_DOWN: // Go down 1 page in the quote lines
+            // If the current top quote line index is below the top index for the
+            // last page, then go to the next page of quote lines and select the
+            // top index on that page as the current selected quote line.
+            if (gQuoteLinesTopIndex < topIndexForLastPage)
+            {
+               gQuoteLinesTopIndex += quoteWinInnerHeight;
+               if (gQuoteLinesTopIndex > topIndexForLastPage)
+                  gQuoteLinesTopIndex = topIndexForLastPage;
+               gQuoteLinesIndex = gQuoteLinesTopIndex;
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               displayQuoteWindowLines(gQuoteLinesTopIndex, quoteWinHeight, quoteWinWidth, true,
+                                       gQuoteLinesIndex);
+            }
+            break;
+         case "F": // Go to the first page
+            if (gQuoteLinesTopIndex > 0)
+            {
+               gQuoteLinesTopIndex = 0;
+               gQuoteLinesIndex = gQuoteLinesTopIndex;
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               displayQuoteWindowLines(gQuoteLinesTopIndex, quoteWinHeight, quoteWinWidth, true,
+                                       gQuoteLinesIndex);
+            }
+            break;
+         case "L": // Go to the last page
+            if (gQuoteLinesTopIndex < topIndexForLastPage)
+            {
+               gQuoteLinesTopIndex = topIndexForLastPage;
+               gQuoteLinesIndex = gQuoteLinesTopIndex;
+               quoteLine = getQuoteTextLine(gQuoteLinesIndex, quoteWinWidth);
+               screenLine = quoteTopScreenRow + (gQuoteLinesIndex - gQuoteLinesTopIndex);
+               displayQuoteWindowLines(gQuoteLinesTopIndex, quoteWinHeight, quoteWinWidth, true,
+                                       gQuoteLinesIndex);
+            }
+            break;
          case KEY_ENTER:
             // numTimesToMoveDown specifies how many times to move the cursor
             // down after inserting the quote line into the message.
@@ -2648,8 +2722,8 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
 //  pQuoteWinHeight: The height of the quote window
 //  pQuoteWinWidth: The width of the quote window
 //  pQuoteBottomScreenLine: The bottommost screen line where quote lines are displayed
-function moveDownOneQuoteLine(pQuoteLinesIndex, pScreenLine, pQuoteWinHeight, pQuoteWinWidth,
-                               pQuoteBottomScreenLine)
+function moveDownOneQuoteLine(pQuoteLinesIndex, pScreenLine, pQuoteWinHeight,
+                               pQuoteWinWidth, pQuoteBottomScreenLine)
 {
    // Create the return object
    var returnObj = new Object();
diff --git a/exec/SlyEdit_DCTStuff.js b/exec/SlyEdit_DCTStuff.js
index 0fb324b3b8ce677af944c9f8ec2d59a71bb69a8b..c9ae30ebb5fc07066a5519439e6570b70be770e0 100644
--- a/exec/SlyEdit_DCTStuff.js
+++ b/exec/SlyEdit_DCTStuff.js
@@ -58,6 +58,10 @@
  *                              of different widths.
  * 2013-09-16 Eric Oulashin     Fixed off-by-one bug for the horizontal position in
  *                              Updated updateInsertModeOnScreen_DCTStyle().
+ * 2014-11-04 Eric Oulashin     Fixed the quote window top border length in
+ *                              DrawQuoteWindowTopBorder_DCTStyle().  Updated the
+ *                              quote window bottom border to display the new
+ *                              scroll keys in DrawQuoteWindowBottomBorder_DCTStyle().
  */
 
 load("sbbsdefs.js");
@@ -453,8 +457,8 @@ function DrawQuoteWindowTopBorder_DCTStyle(pQuoteWinHeight, pEditLeft, pEditRigh
                                 + gConfigSettings.DCTColors.QuoteWinBorderTextColor
                                 + "Quote Window " + gConfigSettings.DCTColors.QuoteWinBorderColor;
       var curLength = strip_ctrl(DrawQuoteWindowTopBorder_DCTStyle.border).length;
-      var endCol = console.screen_columns-1;
-      for (var i = curLength; i < endCol; ++i)
+      var borderWidth = pEditRight - pEditLeft;
+      for (var i = curLength; i < borderWidth; ++i)
          DrawQuoteWindowTopBorder_DCTStyle.border += HORIZONTAL_SINGLE;
       DrawQuoteWindowTopBorder_DCTStyle.border += UPPER_RIGHT_SINGLE;
    }
@@ -478,22 +482,20 @@ function DrawQuoteWindowBottomBorder_DCTStyle(pEditLeft, pEditRight)
    if (typeof(DrawQuoteWindowBottomBorder_DCTStyle.border) == "undefined")
    {
       // Create a string containing the quote help text.
-      var quoteHelpText = " " + gConfigSettings.DCTColors.QuoteWinBorderTextColor
-                         + "[Enter] Quote Line " + gConfigSettings.DCTColors.QuoteWinBorderColor
-                         + " ";
-      for (var i = 0; i < 3; ++i)
-         quoteHelpText += HORIZONTAL_SINGLE;
-      quoteHelpText += " " +  gConfigSettings.DCTColors.QuoteWinBorderTextColor
-                     + "[ESC] Stop Quoting " + gConfigSettings.DCTColors.QuoteWinBorderColor
-                     + " ";
-      for (var i = 0; i < 3; ++i)
-         quoteHelpText += HORIZONTAL_SINGLE;
-      quoteHelpText += " " + gConfigSettings.DCTColors.QuoteWinBorderTextColor
-                     + "[Up/Down] Scroll Lines ";
+      var quoteHelpText = gConfigSettings.DCTColors.QuoteWinBorderTextColor
+                         + "[Enter] Accept" + gConfigSettings.DCTColors.QuoteWinBorderColor
+                         + HORIZONTAL_SINGLE + HORIZONTAL_SINGLE + gConfigSettings.DCTColors.QuoteWinBorderTextColor
+                         + "[^Q/ESC] End" + gConfigSettings.DCTColors.QuoteWinBorderColor
+                         + HORIZONTAL_SINGLE + HORIZONTAL_SINGLE + gConfigSettings.DCTColors.QuoteWinBorderTextColor
+                         + "[" + UP_ARROW + "/" + DOWN_ARROW + "/PgUp/PgDn] Scroll"
+                         + gConfigSettings.DCTColors.QuoteWinBorderColor + HORIZONTAL_SINGLE
+                         + HORIZONTAL_SINGLE + gConfigSettings.DCTColors.QuoteWinBorderTextColor
+                         + "[F/L] First/last page";
+      var helpTextLen = strip_ctrl(quoteHelpText).length;
 
       // Figure out the starting horizontal position on the screen so that
       // the quote help text line can be centered.
-      var helpTextStartX = ((console.screen_columns/2) - (strip_ctrl(quoteHelpText).length/2)).toFixed(0);
+      var helpTextStartX = Math.floor((console.screen_columns/2) - (helpTextLen/2));
 
       // Start creating DrawQuoteWindowBottomBorder_DCTStyle.border with the
       // bottom border lines, up until helpTextStartX.
@@ -504,7 +506,7 @@ function DrawQuoteWindowBottomBorder_DCTStyle(pEditLeft, pEditRight)
       // Add the help text, then display the rest of the bottom border characters.
       DrawQuoteWindowBottomBorder_DCTStyle.border += quoteHelpText
                                                    + gConfigSettings.DCTColors.QuoteWinBorderColor;
-      for (var XPos = pEditLeft+2+strip_ctrl(quoteHelpText).length; XPos <= pEditRight-1; ++XPos)
+      for (var XPos = helpTextStartX + helpTextLen; XPos <= pEditRight-2; ++XPos)
          DrawQuoteWindowBottomBorder_DCTStyle.border += HORIZONTAL_SINGLE;
       DrawQuoteWindowBottomBorder_DCTStyle.border += LOWER_RIGHT_SINGLE;
    }
diff --git a/exec/SlyEdit_IceStuff.js b/exec/SlyEdit_IceStuff.js
index 5e8c5f24bd0ba1336a98bfa488037ae28bd0109f..7ef827193dba9358882b769dc4c9728fb5b417f8 100644
--- a/exec/SlyEdit_IceStuff.js
+++ b/exec/SlyEdit_IceStuff.js
@@ -399,7 +399,7 @@ function DisplayBottomHelpLine_IceStyle(pLineNum, pUsingQuotes)
       // This line contains the copyright mesage & ESC key help
       var screenText = iceText(EDITOR_PROGRAM_NAME + " v", "w") + "ch"
                       + EDITOR_VERSION.toString() + "   "
-                      + iceText("Copyright", "w") + " ch2013 "
+                      + iceText("Copyright", "w") + " ch2014 "
                       + iceText("Eric Oulashin", "w") + " nb" + DOT_CHAR + " "
                       + iceText("Press ESCape For Help", "w");
       // Calculate the starting position to center the help text, and front-pad
@@ -491,19 +491,23 @@ function DrawQuoteWindowBottomBorder_IceStyle(pEditLeft, pEditRight)
                                                              gConfigSettings.iceColors.BorderColor1,
                                                              gConfigSettings.iceColors.BorderColor2)
                 + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_LEFT
-                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "^Q/ESC-End"
+                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "^Q/ESC=End"
                 + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_RIGHT
                 + gConfigSettings.iceColors.BorderColor1 + HORIZONTAL_DOUBLE
                 + gConfigSettings.iceColors.BorderColor2  + THIN_RECTANGLE_LEFT
-                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "CR-Accept"
+                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "CR=Accept"
                 + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_RIGHT
                 + gConfigSettings.iceColors.BorderColor1 + HORIZONTAL_DOUBLE
                 + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_LEFT
-                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "Up/Down-Scroll"
+                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "Up/Down/PgUp/PgDn=Scroll"
+                + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_RIGHT
+                + gConfigSettings.iceColors.BorderColor1 + HORIZONTAL_DOUBLE
+                + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_LEFT
+                + gConfigSettings.iceColors.QuoteWinBorderTextColor + "F/L=First/Last pg"
                 + gConfigSettings.iceColors.BorderColor2 + THIN_RECTANGLE_RIGHT;
       // The border from here to the end of the line: Random high/low blue
       var screenText = "";
-      for (var posX = pEditLeft + 43; posX <= pEditRight; ++posX)
+      for (var posX = pEditLeft + 73; posX <= pEditRight; ++posX)
          screenText += HORIZONTAL_DOUBLE;
       screenText += LOWER_RIGHT_VSINGLE_HDOUBLE;
       DrawQuoteWindowBottomBorder_IceStyle.border += randomTwoColorString(screenText,
diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js
index 12e02c9624d7bc15ca0da08d22f43703cba323fe..ade4bf7b1471159bc3e18539d7e4ee2002dca181 100644
--- a/exec/SlyEdit_Misc.js
+++ b/exec/SlyEdit_Misc.js
@@ -12,86 +12,28 @@
  * 2009-08-22 Eric Oulashin     Version 1.00
  *                              Initial public release
  * ....Removed some comments...
- * 2013-08-24 Eric Oulashin     Bug fix in wrapQuoteLines(): Off-by-one bug toward
- *                              the end where there might be more quote lines
- *                              than lineInfo objects, so it wouldn't quote the
- *                              last line when using author initials.
- * 2013-08-28 Eric Oulashin     Updated ReadSlyEditConfigFile() to read and
- *                              set the enableTextReplacements setting.  It
- *                              defaults to false.  Also added populateTxtReplacements().
- *                              Added moveGenColorsToGenSettings(), which
- *                              can be called by JavaScripts for different
- *                              UI styles to move the general color settings
- *                              from their own color array into the genColors
- *                              array in the configuration object.
- * 2013-08-31 Eric Oulashin     Added the function getWordFromEditLine().
- * 2013-09-02 Eric Oulashin     Worked on the new function doMacroTxtReplacementInEditLine(),
- *                              which performs text replacement (AKA macros) on
- *                              one of the message edit lines.  Added
- *                              genFullPathCfgFilename() so that the logic for finding
- *                              the configuration files is all in one place.  Added
- *                              getFirstLetterFromStr() and firstLetterIsUppercase(),
- *                              which are helpers for doMacroTxtReplacementInEditLine()
- *                              for checking & fixing first-letter capitalization
- *                              after doing a regex replace.
- * 2013-09-03 Eric Oulashin     Updated populateTxtReplacements() so that it won't
- *                              force the replacement text strings to lowercase
- *                              when not using regular expressions.  Also made
- *                              use of strip_ctrl() with the replacement text to
- *                              prevent the use of color codes, which might mess
- *                              up SlyEdit's tracking of string indexes, etc.
- *                              Updated doMacroTxtReplacementInEditLine() so
- *                              that macro text replacements won't lowercase the
- *                              replacement text when in literal match & replace
- *                              mode.
- * 2013-09-07 Eric Oulashin     Bug fix: Updated ReadSlyEditConfigFile() to
- *                              default cfgObj.genColors.listBoxItemText to
- *                              ensure that it gets defined.
- *                              Code refactor: Moved doMacroTxtReplacementInEditLine()
- *                              and getWordFromEditLine() to TextLine member
- *                              methods TextLine_doMacroTxtReplacement() and
- *                              TextLine_getWord().
- * 2013-09-13
- * 2013-09-14 Eric Oulashin     Added functions for a new ChoiceScrollbox object
- *                              type, which is a generic scrollable list box that
- *                              allows a user to select an item.
- *                              Added the functions readTxtFileIntoArray() and
- *                              txtFileContainsLines().  Updated displayCommandList()
- *                              to display the hotkey Ctrl-U for user settings.
- *                              Moved the options for author initials in quote
- *                              lines to user settings.
- * 2013-09-19 Eric Oulashin     Added the shuffleArray() function.  Added 3
- *                              more options to the config file, to be read by
- *                              ReadSlyEditConfigFile(): taglinePrefix, quoteTaglines,
- *                              and shuffleTaglines.
- * 2013-10-22 Eric Oulashin     Worked on the wrapQuoteLines() function to improve
- *                              quoting with author initials to fix a bug where
- *                              a large section in certain messages wasn't getting
- *                              quoted.
- * 2013-10-22 to
- * 2013-10-27 Eric Oulashin     Worked on quote line wrapping to fix issues when
- *                              quoting messages with author initials.
- * 2013-11-09 Eric Oulashin     Added an optional parameter to wrapTextLines() as
- *                              an array to return indexes of lines that needed a
- *                              new line inserted after it.  This was done to help
- *                              wrapQuoteLinesUsingAuthorInitials() move its line
- *                              info objects down when a new line is added.
- * 2013-11-10 Eric Oulashin     Made some more refinements, mainly for
- *                              wrapQuoteLinesUsingAuthorInitials().
- * 2013-11-25 Eric Oulashin     Minor bug fix in wrapQuoteLinesUsingAuthorInitials()
- *                              starting on line 2739: Added more checks to ensure
- *                              that the gQuoteLines object it references is valid.
- *                              Bug fix in DisplayTextAreaBottomBorder_IceStyle() in
- *                              SlyEdit_IceStuff.js to ensure that the parenthesis in the
- *                              CTRL key help text at the right in the bottom border are
- *                              correctly displayed with a high blue color, regardless of
- *                              what is specified in the color theme file.
- * 2014-05-12 Eric Oulashin     Added a check in wrapQuoteLinesUsingAuthorInitials(): When
- *                              building the last section info object, added a check to
- *                              the while loop that makes sure sectionInfo.endArrIndex is
- *                              greater than 0 to avoid an index out-of-bounds issue with
- *                              the check that references gQuoteLines[sectionInfo.endArrIndex-1].
- *                              This should hopefully fix a bug with SlyEdit crashing at that point.
+ * 2014-11-01 Eric Oulashin     Added getKeyWithESCChars(), along with the key definitions
+ *                              KEY_PAGE_UP and KEY_PAGE_DOWN, to support inputting the
+ *                              PageUp & PageDown keys from the user.
+ * 2014-11-08 Eric Oulashin     Updated wrapQuoteLinesUsingAuthorInitials() and
+ *                              wrapQuoteLines_NoAuthorInitials() so that if the
+ *                              current line's indentation differs from the previous
+ *                              line's indentation, it will mark a new section for
+ *                              the quote lines so that lines of different paragraphs
+ *                              don't get wrapped together.
+ * 2014-11-09 Eric Oulashin     Bug fix in wrapTextLines(): For the edge case when
+ *                              text is trimmed from the end of the last line in
+ *                              the paragraph, it will insert a new line in the
+ *                              array at the end of the paragraph for the trimmed
+ *                              text.  For lines before the last line in the
+ *                              paragraph, it will just prepend the text to the
+ *                              next line in the array.  Also, updated
+ *                              wrapQuoteLinesUsingAuthorInitials() to trim leading
+ *                              spaces from non-quote text sections to leave more
+ *                              room for wrapping the lines and to avoid having
+ *                              whole sections of quote lines that start with
+ *                              several spaces.  Also made a similar update to
+ *                              wrapQuoteLines_NoAuthorInitials().
  */
 
 // Note: These variables are declared with "var" instead of "const" to avoid
@@ -185,6 +127,15 @@ var CTRL_X = "\x18";
 var CTRL_Y = "\x19";
 var CTRL_Z = "\x1a";
 var KEY_ESC = "\x1b";
+// Key code strings returned by getKeyWithESCChars() - Not real key codes, as
+// the keys they represent are returned as multiple key captures.
+var KEY_PAGE_UP = "\1PgUp";
+var KEY_PAGE_DOWN = "\1PgDn";
+var KEY_F1 = "\1F1";
+var KEY_F2 = "\1F2";
+var KEY_F3 = "\1F3";
+var KEY_F4 = "\1F4";
+var KEY_F5 = "\1F5";
 
 // Store the full path & filename of the Digital Distortion Message
 // Lister, since it will be used more than once.
@@ -1226,7 +1177,7 @@ function isPrintableChar(pText)
 // Removes multiple, leading, and/or trailing spaces
 // The search & replace regular expressions used in this
 // function came from the following URL:
-//  http://qodo.co.uk/blog/javascript-trim-leading-and-trailing-spaces
+// http://qodo.co.uk/blog/javascript-trim-leading-and-trailing-spaces
 //
 // Parameters:
 //  pString: The string to trim
@@ -1348,7 +1299,7 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy
       if ((pKey2.length == 0) && (pDesc2.length == 0))
          sepChar2 = " ";
       printf("ch%-13sg" + sepChar1 + " nc%-28s kh" + VERTICAL_SINGLE +
-             " ch%-7sg" + sepChar2 + " nc%s", pKey, pDesc, pKey2, pDesc2);
+             " ch%-8sg" + sepChar2 + " nc%s", pKey, pDesc, pKey2, pDesc2);
       if (pCR)
          console.crlf();
    }
@@ -1369,8 +1320,8 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy
    console.crlf();
    // Command/edit keys
    console.print("ngCommand/edit keys\r\nkh�����������������\r\n");
-   displayCmdKeyFormattedDouble("Ctrl-A", "Abort message", "Ctrl-W", "Page up", true);
-   displayCmdKeyFormattedDouble("Ctrl-Z", "Save message", "Ctrl-S", "Page down", true);
+   displayCmdKeyFormattedDouble("Ctrl-A", "Abort message", "PageUp", "Page up", true);
+   displayCmdKeyFormattedDouble("Ctrl-Z", "Save message", "PageDown", "Page down", true);
    displayCmdKeyFormattedDouble("Ctrl-Q", "Quote message", "Ctrl-N", "Find text", true);
    displayCmdKeyFormattedDouble("Insert/Ctrl-I", "Toggle insert/overwrite mode",
                                 "Ctrl-D", "Delete line", true);
@@ -1385,7 +1336,7 @@ function displayCommandList(pDisplayHeader, pClear, pPause, pCanCrossPost, pIsSy
       displayCmdKeyFormatted("Ctrl-U", "Your settings", true);
 
    if (pPause)
-      console.pause();
+      consolePauseWithESCChars(isSysop);
 }
 
 // Displays the general help screen.
@@ -2422,8 +2373,28 @@ function wrapTextLines(pLineArr, pStartLineIndex, pEndIndex, pLineWidth, pIdxesR
           if (trimmedText.charAt(trimmedText.length-1) != " ")
             trimmedText += " "
         }
-        // Prepend the trimmed text to the next line.
-        pLineArr[i+1] = trimmedText + pLineArr[i+1];
+        // Prepend the trimmed text to the next line.  If the next line's index
+        // is within the paragraph we're wrapping, then go ahead and prepend the
+        // text to the next line.  Otherwise, add a new line to the array and
+        // add the text to the new line.
+        if (i+1 < pEndIndex)
+          pLineArr[i+1] = trimmedText + pLineArr[i+1];
+        else
+        {
+          // Add the trimmed text on a new line in the array.  Then, if the
+          // trimmed text's length is longer then the allowed line width, then
+          // we'll want to extend the end index so we can continue wrapping the
+          // lines in the current paragraph.  Otherwise, add the current line's
+          // index to the array of lines requiring a newline.
+          pLineArr.splice(i+1, 0, trimmedText);
+          if (trimmedText.length > pLineWidth)
+            ++pEndIndex;
+          else
+          {
+            if (pNewLineIndexesIsArray)
+              pIdxesRequiringNL.push(i);
+          }
+        }
       }
       else
       {
@@ -2738,6 +2709,8 @@ function wrapQuoteLinesUsingAuthorInitials(pIndentQuoteLines)
       if (gQuoteLines[quoteLineIndex].length == 0)
          continue;
 
+      // If this line has a different quote level than the previous line, then
+      // it marks a new section.
       if (lineInfos[quoteLineIndex].quoteLevel != lastQuoteLevel)
       {
          endArrIndex = quoteLineIndex;
@@ -2758,10 +2731,34 @@ function wrapQuoteLinesUsingAuthorInitials(pIndentQuoteLines)
             ++sectionInfo.endArrIndex;
 
          quoteSections.push(sectionInfo);
-
          startArrIndex = quoteLineIndex;
          lastQuoteLevel = lineInfos[quoteLineIndex].quoteLevel;
       }
+      // For lines with a quote level of 0, if this line's indentation differs from
+      // the previous line's indentation, then that marks a new section.
+      else if ((lineInfos[quoteLineIndex].quoteLevel == 0) && (lastQuoteLevel == 0) &&
+                (lineInfos[quoteLineIndex].startIndex > lineInfos[quoteLineIndex-1].startIndex))
+      {
+         endArrIndex = quoteLineIndex; // One past the last index of the current paragraph
+         var sectionInfo = new Object();
+         sectionInfo.startArrIndex = startArrIndex;
+         sectionInfo.endArrIndex = endArrIndex;
+         sectionInfo.quoteLevel = 0;
+         // If the end array index is for a blank quote line, then
+         // adjust it to the first non-blank quote line before it.
+         while ((sectionInfo.endArrIndex-1 >= 0) &&
+                (typeof(gQuoteLines[sectionInfo.endArrIndex-1]) == "string") &&
+                gQuoteLines[sectionInfo.endArrIndex-1].length == 0)
+         {
+            --sectionInfo.endArrIndex;
+         }
+         // If we moved sectionInfo.endArrIndex back too far, then increment it.
+         while (typeof(gQuoteLines[sectionInfo.endArrIndex]) != "string")
+            ++sectionInfo.endArrIndex;
+
+         quoteSections.push(sectionInfo);
+         startArrIndex = quoteLineIndex;
+      }
    }
    // If we only found one section or we're at the last section, then add it to
    // quoteSections.
@@ -2778,9 +2775,24 @@ function wrapQuoteLinesUsingAuthorInitials(pIndentQuoteLines)
       quoteSections.push(sectionInfo);
    }
 
-   // 3. Go through each section of the quote lines and quote appropriately
+   // 3. Go through each section of the quote lines and wrap & quote appropriately
    for (var sIndex = 0; sIndex < quoteSections.length; ++sIndex)
    {
+      // If the section is not quoted text (in other words, it was written by
+      // author of the message), then remove leading whitespace from the text
+      // lines in this section to leave more room for wrapping and so that we
+      // don't end up with a section of quote lines that all start with several
+      // spaces.
+      if (quoteSections[sIndex].quoteLevel == 0)
+      {
+         for (var i = quoteSections[sIndex].startArrIndex; i < quoteSections[sIndex].endArrIndex; ++i)
+         {
+            gQuoteLines[i] = trimSpaces(gQuoteLines[i], true, true, false);
+            lineInfos[i].startIndex = 0;
+            lineInfos[i].begOfLine = "";
+         }
+      }
+
       // Remove the quote strings from the lines we're about to wrap
       var maxBegOfLineLen = 0;
       for (var i = quoteSections[sIndex].startArrIndex; i < quoteSections[sIndex].endArrIndex; ++i)
@@ -2914,34 +2926,29 @@ function wrapQuoteLines_NoAuthorInitials()
   if (gQuoteLines.length == 0)
     return;
 
-  // Create an array for line information objects, and append the
-  // first line's info to it.  Also, store the first line's quote
-  // level in the lastQuoteLevel variable.
+  // Create an array for line information objects.
   var lineInfos = new Array();
-  var retObj = firstNonQuoteTxtIndex(gQuoteLines[0], false, false);
-  lineInfos.push(retObj);
-  var lastQuoteLevel = retObj.quoteLevel;
+  for (var quoteLineIndex = 0; quoteLineIndex < gQuoteLines.length; ++quoteLineIndex)
+    lineInfos.push(firstNonQuoteTxtIndex(gQuoteLines[quoteLineIndex], false, false));
+
+  // Set an initial value for lastQuoteLevel, which will be used to compare the
+  // quote levels of each line.
+  var lastQuoteLevel = lineInfos[0].quoteLevel;
 
   // Loop through the array starting at the 2nd line and wrap the lines
   var startArrIndex = 0;
   var endArrIndex = 0;
   var quoteStr = "";
   var quoteLevel = 0;
-  var retObj = null;
   var i = 0; // Index variable
   for (var quoteLineIndex = 1; quoteLineIndex < gQuoteLines.length; ++quoteLineIndex)
   {
-    retObj = firstNonQuoteTxtIndex(gQuoteLines[quoteLineIndex], false, false);
-    lineInfos.push(retObj);
-    if (retObj.quoteLevel != lastQuoteLevel)
+    if (lineInfos[quoteLineIndex].quoteLevel != lastQuoteLevel)
     {
       endArrIndex = quoteLineIndex;
       // Remove the quote strings from the lines we're about to wrap
       for (i = startArrIndex; i < endArrIndex; ++i)
       {
-        // TODO
-        // Error on next line: !JavaScript  TypeError: lineInfos[i] is undefined
-        // Fixed by checking that lineInfos[i] is not null..  but why would it be?
         if (lineInfos[i] != null)
         {
           if (lineInfos[i].startIndex > -1)
@@ -2953,10 +2960,10 @@ function wrapQuoteLines_NoAuthorInitials()
           if (/^ +$/.test(gQuoteLines[i])) gQuoteLines[i] = "";
         }
       }
-      // Wrap the text lines in the range we've seen
+      // Wrap the text lines in the range we've seen.
       // Note: 79 is assumed as the maximum line length because
       // that seems to be a commonly-accepted message width for
-      // BBSs.  Also, the following length is subtracted from it:
+      // BBSes.  Also, the following length is subtracted from it:
       // (2*(lastQuoteLevel+1) + gQuotePrefix.length)
       // That is because we'll be prepending "> " to the quote lines,
       // and then SlyEdit will prepend gQuotePrefix to them during quoting.
@@ -2969,6 +2976,10 @@ function wrapQuoteLines_NoAuthorInitials()
       {
         endArrIndex += numLinesAdded;
         quoteLineIndex += (numLinesAdded-1); // - 1 because quoteLineIndex will be incremented by the for loop
+        // Splice new lineInfo objects into the lineInfos array at the end of this
+        // section for each new line added in this section.
+        for (var counter = 0; counter < numLinesAdded; ++counter)
+          lineInfos.splice(endArrIndex, 0, getDefaultQuoteStrObj());
       }
       // Put quote strings ("> ") back into the lines we just wrapped
       if ((quoteLineIndex > 0) && (lastQuoteLevel > 0))
@@ -2979,7 +2990,43 @@ function wrapQuoteLines_NoAuthorInitials()
         for (i = startArrIndex; i < endArrIndex; ++i)
           gQuoteLines[i] = quoteStr + gQuoteLines[i].replace(/^\s*>/, ">");
       }
-      lastQuoteLevel = retObj.quoteLevel;
+      lastQuoteLevel = lineInfos[quoteLineIndex].quoteLevel;
+      startArrIndex = quoteLineIndex;
+    }
+    // For lines with a quote level of 0, if this line's indentation differs from
+    // the previous line's indentation, then that marks a new section.
+    else if ((lineInfos[quoteLineIndex].quoteLevel == 0) && (lastQuoteLevel == 0) &&
+             (lineInfos[quoteLineIndex].startIndex > lineInfos[quoteLineIndex-1].startIndex))
+    {
+      endArrIndex = quoteLineIndex;
+
+      // Remove leading whitespace from the text lines in this section to leave
+      // more room for wrapping and so that we don't end up with a section of
+      // quote lines that all start with several spaces.
+      for (var i = startArrIndex; i < endArrIndex; ++i)
+      {
+         gQuoteLines[i] = trimSpaces(gQuoteLines[i], true, true, false);
+         lineInfos[i].startIndex = 0;
+         lineInfos[i].begOfLine = "";
+      }
+
+      // Wrap the text lines in the range we've seen.
+      // Note: 79 is assumed as the maximum line length because
+      // that seems to be a commonly-accepted message width for
+      // BBSes.
+      var numLinesAdded =  wrapTextLines(gQuoteLines, startArrIndex, endArrIndex, 79);
+      // If quote lines were added as a result of wrapping, then
+      // determine the number of lines added, and update endArrIndex
+      // and quoteLineIndex accordingly.
+      if (numLinesAdded > 0)
+      {
+        endArrIndex += numLinesAdded;
+        quoteLineIndex += (numLinesAdded-1); // - 1 because quoteLineIndex will be incremented by the for loop
+        // Splice new lineInfo objects into the lineInfos array at the end of this
+        // section for each new line added in this section.
+        for (var counter = 0; counter < numLinesAdded; ++counter)
+          lineInfos.splice(endArrIndex, 0, getDefaultQuoteStrObj());
+      }
       startArrIndex = quoteLineIndex;
     }
   }
@@ -3626,17 +3673,38 @@ function firstLetterIsUppercase(pString)
 //
 // Parameters:
 //  pMode: The input mode flag(s)
-//  pCfgObj: The configuration object
+//  pCfgObj: The configuration object (stores the input timeout setting)
 //
 // Return value: The user's keypress (the return value of console.getkey()
 //               or console.inkey()).
 function getUserKey(pMode, pCfgObj)
 {
+   var defaultTimeoutMS = 300000;
    var userKey = "";
-   if (!pCfgObj.userInputTimeout || pCfgObj.userIsSysop)
-      userKey = console.getkey(pMode);
-   else
-      userKey = console.inkey(pMode, pCfgObj.inputTimeoutMS);
+
+   if (typeof(pCfgObj) == "object")
+   {
+      // If the user is a sysop, don't use an input timeout.
+      if ((typeof(pCfgObj.userIsSysop) == "boolean") && pCfgObj.userIsSysop)
+         userKey = console.getkey(pMode);
+      else if (typeof(pCfgObj.userInputTimeout) == "number")
+         userKey = console.inkey(pMode, pCfgObj.inputTimeoutMS);
+      else
+         userKey = console.inkey(pMode, defaultTimeoutMS);
+   }
+   else if (typeof(pCfgObj) == "boolean")
+   {
+      // pCfgObj is a boolean that specifies whether or not the user is a sysop.
+      // If so, then use console.getkey().  If the user isn't a sysop, use a
+      // timeout of 5 minutes.
+      if (pCfgObj)
+         userKey = console.getkey(pMode);
+      else
+         userKey = console.inkey(pMode, defaultTimeoutMS);
+   }
+   else // pCfgObj is not a known type, so use the default input timeout.
+      userKey = console.inkey(pMode, defaultTimeoutMS);
+
    return userKey;
 }
 
@@ -4045,6 +4113,78 @@ function shuffleArray(pArray)
     return pArray;
 }
 
+// Performs the same function as console.pause(), but also allows input of multi-key
+// sequences such as PageUp, PageDown, F1, etc. without writing extra characters on
+// the screen.
+//
+// Parameters:
+//  pCfgObj: Optional - The configuration object, which specifies the input timeout.
+function consolePauseWithESCChars(pCfgObj)
+{
+   console.print("\1n" + bbs.text(563)); // 563 is the "Press a key" text in text.dat
+   getKeyWithESCChars(K_NOSPIN|K_NOCRLF|K_NOECHO, pCfgObj);
+}
+
+// Inputs a keypress from the user and handles some ESC-based
+// characters such as PageUp, PageDown, and ESC.  If PageUp
+// or PageDown are pressed, this function will return the
+// string "\1PgUp" (KEY_PAGE_UP) or "\1Pgdn" (KEY_PAGE_DOWN),
+// respectively.  Also, F1-F5 will be returned as "\1F1"
+// through "\1F5", respectively.
+// Thanks goes to Psi-Jack for the original impementation
+// of this function.
+//
+// Parameters:
+//  pGetKeyMode: Optional - The mode bits for console.getkey().
+//               If not specified, K_NONE will be used.
+//  pCfgObj: The configuration object (stores the input timeout setting)
+//
+// Return value: The user's keypress
+function getKeyWithESCChars(pGetKeyMode, pCfgObj)
+{
+   var getKeyMode = K_NONE;
+   if (typeof(pGetKeyMode) == "number")
+      getKeyMode = pGetKeyMode;
+
+   var userInput = getUserKey(getKeyMode, pCfgObj);
+   if (userInput == KEY_ESC) {
+      switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) {
+         case '[':
+            switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) {
+               case 'V':
+                  userInput = KEY_PAGE_UP;
+                  break;
+               case 'U':
+                  userInput = KEY_PAGE_DOWN;
+                  break;
+           }
+           break;
+         case 'O':
+           switch (console.inkey(K_NOECHO|K_NOSPIN, 2)) {
+              case 'P':
+                 userInput = KEY_F1;
+                 break;
+              case 'Q':
+                 userInput = KEY_F2;
+                 break;
+              case 'R':
+                 userInput = KEY_F3;
+                 break;
+              case 'S':
+                 userInput = KEY_F4;
+                 break;
+              case 't':
+                 userInput = KEY_F5;
+                 break;
+           }
+         default:
+           break;
+      }
+   }
+
+   return userInput;
+}
+
 // This function displays debug text at a given location on the screen, then
 // moves the cursor back to a given location.
 //