[CONSRV]
[reactos.git] / win32ss / user / winsrv / consrv / frontends / gui / conwnd.c
index 0b6b2f5..c92593d 100644 (file)
@@ -12,7 +12,7 @@
 /* INCLUDES *******************************************************************/
 
 #include <consrv.h>
-
+#include <intrin.h>
 #include <windowsx.h>
 
 #define NDEBUG
@@ -250,7 +250,8 @@ AppendMenuItems(HMENU hMenu,
     } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
 }
 
-static VOID
+//static
+VOID
 CreateSysMenu(HWND hWnd)
 {
     MENUITEMINFOW mii;
@@ -301,7 +302,9 @@ Copy(PGUI_CONSOLE_DATA GuiData);
 static VOID
 Paste(PGUI_CONSOLE_DATA GuiData);
 static VOID
-UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord);
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+                PCOORD SelectionAnchor OPTIONAL,
+                PCOORD coord);
 
 static VOID
 Mark(PGUI_CONSOLE_DATA GuiData)
@@ -309,30 +312,28 @@ Mark(PGUI_CONSOLE_DATA GuiData)
     PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
 
     /* Clear the old selection */
-    // UpdateSelection(GuiData, NULL);
     GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
 
     /* Restart a new selection */
-    GuiData->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
-    GuiData->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
-    GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
-    UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
+    GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
+    UpdateSelection(GuiData,
+                    &GuiData->dwSelectionCursor,
+                    &GuiData->dwSelectionCursor);
 }
 
 static VOID
 SelectAll(PGUI_CONSOLE_DATA GuiData)
 {
     PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+    COORD SelectionAnchor;
 
     /* Clear the old selection */
-    // UpdateSelection(GuiData, NULL);
     GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
 
     /*
      * The selection area extends to the whole screen buffer's width.
      */
-    GuiData->Selection.dwSelectionAnchor.X = 0;
-    GuiData->Selection.dwSelectionAnchor.Y = 0;
+    SelectionAnchor.X = SelectionAnchor.Y = 0;
     GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
 
     /*
@@ -358,7 +359,7 @@ SelectAll(PGUI_CONSOLE_DATA GuiData)
 
     /* Restart a new selection */
     GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
-    UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+    UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
 }
 
 static LRESULT
@@ -587,7 +588,8 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
     SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
 
     SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
-    CreateSysMenu(GuiData->hWindow);
+    // FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
+    //CreateSysMenu(GuiData->hWindow);
 
     DPRINT("OnNcCreate - setting start event\n");
     SetEvent(GuiData->hGuiInitEvent);
@@ -608,7 +610,6 @@ GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData);
 static VOID
 OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
 {
-    PCONSOLE Console = GuiData->Console;
     WORD ActivationState = LOWORD(wParam);
 
     DPRINT1("WM_ACTIVATE - ActivationState = %d\n");
@@ -635,12 +636,11 @@ OnActivate(PGUI_CONSOLE_DATA GuiData, WPARAM wParam)
     }
 
     /*
-     * When we are in QuickEdit mode, ignore the next mouse signal
-     * when we are going to be enabled again via the mouse, in order
-     * to prevent e.g. an erroneous right-click from the user which
-     * would have as an effect to paste some unwanted text...
+     * Ignore the next mouse signal when we are going to be enabled again via
+     * the mouse, in order to prevent, e.g. when we are in Edit mode, erroneous
+     * mouse actions from the user that could spoil text selection or copy/pastes.
      */
-    if (Console->QuickEdit && (ActivationState == WA_CLICKACTIVE))
+    if (ActivationState == WA_CLICKACTIVE)
         GuiData->IgnoreNextMouseSignal = TRUE;
 }
 
@@ -678,18 +678,162 @@ SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
     Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
 }
 
+VOID
+GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
+                     PCOORD SelectionAnchor,
+                     PSMALL_RECT SmallRect)
+{
+    if (Begin == NULL || End == NULL) return;
+
+    *Begin = *SelectionAnchor;
+    End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right
+              /* Case X != Left, must be == Right */ : SmallRect->Left;
+    End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom
+              /* Case Y != Top, must be == Bottom */ : SmallRect->Top;
+
+    /* Exchange Begin / End if Begin > End lexicographically */
+    if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X))
+    {
+        End->X = _InterlockedExchange16(&Begin->X, End->X);
+        End->Y = _InterlockedExchange16(&Begin->Y, End->Y);
+    }
+}
+
+static HRGN
+CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData,
+                   BOOL LineSelection,
+                   PCOORD SelectionAnchor,
+                   PSMALL_RECT SmallRect)
+{
+    if (!LineSelection)
+    {
+        RECT rect;
+        SmallRectToRect(GuiData, &rect, SmallRect);
+        return CreateRectRgnIndirect(&rect);
+    }
+    else
+    {
+        HRGN SelRgn;
+        COORD Begin, End;
+
+        GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect);
+
+        if (Begin.Y == End.Y)
+        {
+            SMALL_RECT sr;
+            RECT       r ;
+
+            sr.Left   = Begin.X;
+            sr.Top    = Begin.Y;
+            sr.Right  = End.X;
+            sr.Bottom = End.Y;
+
+            // Debug thingie to see whether I can put this corner case
+            // together with the previous one.
+            if (SmallRect->Left   != sr.Left  ||
+                SmallRect->Top    != sr.Top   ||
+                SmallRect->Right  != sr.Right ||
+                SmallRect->Bottom != sr.Bottom)
+            {
+                DPRINT1("\n"
+                        "SmallRect = (%d, %d, %d, %d)\n"
+                        "sr = (%d, %d, %d, %d)\n"
+                        "\n",
+                        SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom,
+                        sr.Left, sr.Top, sr.Right, sr.Bottom);
+            }
+
+            SmallRectToRect(GuiData, &r, &sr);
+            SelRgn = CreateRectRgnIndirect(&r);
+        }
+        else
+        {
+            PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
+
+            HRGN       rg1, rg2, rg3;
+            SMALL_RECT sr1, sr2, sr3;
+            RECT       r1 , r2 , r3 ;
+
+            sr1.Left   = Begin.X;
+            sr1.Top    = Begin.Y;
+            sr1.Right  = ActiveBuffer->ScreenBufferSize.X - 1;
+            sr1.Bottom = Begin.Y;
+
+            sr2.Left   = 0;
+            sr2.Top    = Begin.Y + 1;
+            sr2.Right  = ActiveBuffer->ScreenBufferSize.X - 1;
+            sr2.Bottom = End.Y - 1;
+
+            sr3.Left   = 0;
+            sr3.Top    = End.Y;
+            sr3.Right  = End.X;
+            sr3.Bottom = End.Y;
+
+            SmallRectToRect(GuiData, &r1, &sr1);
+            SmallRectToRect(GuiData, &r2, &sr2);
+            SmallRectToRect(GuiData, &r3, &sr3);
+
+            rg1 = CreateRectRgnIndirect(&r1);
+            rg2 = CreateRectRgnIndirect(&r2);
+            rg3 = CreateRectRgnIndirect(&r3);
+
+            CombineRgn(rg1, rg1, rg2, RGN_XOR);
+            CombineRgn(rg1, rg1, rg3, RGN_XOR);
+            DeleteObject(rg3);
+            DeleteObject(rg2);
+
+            SelRgn = rg1;
+        }
+
+        return SelRgn;
+    }
+}
+
+static VOID
+PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps)
+{
+    HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint);
+    HRGN rgnSel   = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                       &GuiData->Selection.dwSelectionAnchor,
+                                       &GuiData->Selection.srSelection);
+
+    /* Invert the selection */
+
+    int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND);
+    if (ErrorCode != ERROR && ErrorCode != NULLREGION)
+    {
+        InvertRgn(pps->hdc, rgnPaint);
+    }
+
+    DeleteObject(rgnSel);
+    DeleteObject(rgnPaint);
+}
+
 static VOID
-UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
+UpdateSelection(PGUI_CONSOLE_DATA GuiData,
+                PCOORD SelectionAnchor OPTIONAL,
+                PCOORD coord)
 {
     PCONSOLE Console = GuiData->Console;
-    RECT oldRect;
+    HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                     &GuiData->Selection.dwSelectionAnchor,
+                                     &GuiData->Selection.srSelection);
 
-    SmallRectToRect(GuiData, &oldRect, &GuiData->Selection.srSelection);
+    /* Update the anchor if needed (use the old one if NULL) */
+    if (SelectionAnchor)
+        GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
 
     if (coord != NULL)
     {
-        RECT newRect;
         SMALL_RECT rc;
+        HRGN newRgn;
+
+        /*
+         * Pressing the Control key while selecting text, allows us to enter
+         * into line-selection mode, the selection mode of *nix terminals.
+         */
+        BOOL OldLineSel = GuiData->LineSelection;
+        GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
 
         /* Exchange left/top with right/bottom if required */
         rc.Left   = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
@@ -697,64 +841,72 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
         rc.Right  = max(GuiData->Selection.dwSelectionAnchor.X, coord->X);
         rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
 
-        SmallRectToRect(GuiData, &newRect, &rc);
+        newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
+                                    &GuiData->Selection.dwSelectionAnchor,
+                                    &rc);
 
         if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            if (memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
+            if (OldLineSel != GuiData->LineSelection ||
+                memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
             {
-                HRGN rgn1, rgn2;
-
                 /* Calculate the region that needs to be updated */
-                if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
+                if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR)
                 {
-                    if ((rgn2 = CreateRectRgnIndirect(&newRect)))
-                    {
-                        if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
-                        {
-                            InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
-                        }
-                        DeleteObject(rgn2);
-                    }
-                    DeleteObject(rgn1);
+                    InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
                 }
             }
         }
         else
         {
-            InvalidateRect(GuiData->hWindow, &newRect, FALSE);
+            InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
         }
 
+        DeleteObject(newRgn);
+
         GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
         GuiData->Selection.srSelection = rc;
         GuiData->dwSelectionCursor = *coord;
 
         if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
         {
-            LPWSTR SelectionType, WindowTitle = NULL;
-            SIZE_T Length = 0;
+            LPWSTR SelTypeStr = NULL   , WindowTitle = NULL;
+            SIZE_T SelTypeStrLength = 0, Length = 0;
 
             /* Clear the old selection */
             if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
             {
-                InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+                InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
             }
 
-            if (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
-            {
-                SelectionType = L"Selection - ";
-            }
-            else
+            /*
+             * When passing a zero-length buffer size, LoadString(...) returns
+             * a read-only pointer buffer to the program's resource string.
+             */
+            SelTypeStrLength =
+                LoadStringW(ConSrvDllInstance,
+                            (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
+                                ? IDS_SELECT_TITLE : IDS_MARK_TITLE,
+                            (LPWSTR)&SelTypeStr, 0);
+
+            /*
+             * Prepend the selection type string to the current console title
+             * if we succeeded in retrieving a valid localized string.
+             */
+            if (SelTypeStr)
             {
-                SelectionType = L"Mark - ";
-            }
+                // 3 for " - " and 1 for NULL
+                Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR);
+                WindowTitle = ConsoleAllocHeap(0, Length);
 
-            Length = Console->Title.Length + wcslen(SelectionType) + 1;
-            WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
-            wcscpy(WindowTitle, SelectionType);
-            wcscat(WindowTitle, Console->Title.Buffer);
-            SetWindowText(GuiData->hWindow, WindowTitle);
-            ConsoleFreeHeap(WindowTitle);
+                wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
+                WindowTitle[SelTypeStrLength] = L'\0';
+                wcscat(WindowTitle, L" - ");
+                wcscat(WindowTitle, Console->Title.Buffer);
+
+                SetWindowText(GuiData->hWindow, WindowTitle);
+                ConsoleFreeHeap(WindowTitle);
+            }
 
             GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
             ConioPause(Console, PAUSED_FROM_SELECTION);
@@ -765,14 +917,17 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
         /* Clear the selection */
         if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
+            InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
         }
 
         GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
         ConioUnpause(Console, PAUSED_FROM_SELECTION);
 
+        /* Restore the console title */
         SetWindowText(GuiData->hWindow, Console->Title.Buffer);
     }
+
+    DeleteObject(oldRgn);
 }
 
 
@@ -826,15 +981,10 @@ OnPaint(PGUI_CONSOLE_DATA GuiData)
                rcPaint.top,
                SRCCOPY);
 
+        /* Draw the selection region if needed */
         if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
         {
-            SmallRectToRect(GuiData, &rcPaint, &GuiData->Selection.srSelection);
-
-            /* Invert the selection */
-            if (IntersectRect(&rcPaint, &ps.rcPaint, &rcPaint))
-            {
-                InvertRect(ps.hdc, &rcPaint);
-            }
+            PaintSelectionRect(GuiData, &ps);
         }
 
         LeaveCriticalSection(&GuiData->Lock);
@@ -911,10 +1061,10 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
             goto Quit;
         }
         else if ( VirtualKeyCode == VK_ESCAPE ||
-                 (VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
+                 (VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
         {
             /* Cancel selection if ESC or Ctrl-C are pressed */
-            UpdateSelection(GuiData, NULL);
+            UpdateSelection(GuiData, NULL, NULL);
             goto Quit;
         }
 
@@ -922,7 +1072,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
         {
             /* Keyboard selection mode */
             BOOL Interpreted = FALSE;
-            BOOL MajPressed  = (GetKeyState(VK_SHIFT) & 0x8000);
+            BOOL MajPressed  = !!(GetKeyState(VK_SHIFT) & 0x8000);
 
             switch (VirtualKeyCode)
             {
@@ -1003,10 +1153,9 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 
             if (Interpreted)
             {
-                if (!MajPressed)
-                    GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
-
-                UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+                UpdateSelection(GuiData,
+                                !MajPressed ? &GuiData->dwSelectionCursor : NULL,
+                                &GuiData->dwSelectionCursor);
             }
             else if (!IsSystemKey(VirtualKeyCode))
             {
@@ -1023,7 +1172,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
             if (!IsSystemKey(VirtualKeyCode))
             {
                 /* Clear the selection and send the key into the input buffer */
-                UpdateSelection(GuiData, NULL);
+                UpdateSelection(GuiData, NULL, NULL);
             }
             else
             {
@@ -1235,15 +1384,18 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
     BOOL Err = FALSE;
     PCONSOLE Console = GuiData->Console;
 
+    // FIXME: It's here that we need to check whether we has focus or not
+    // and whether we are in edit mode or not, to know if we need to deal
+    // with the mouse, or not.
+
     if (GuiData->IgnoreNextMouseSignal)
     {
         if (msg != WM_LBUTTONDOWN &&
             msg != WM_MBUTTONDOWN &&
-            msg != WM_RBUTTONDOWN &&
-            msg != WM_MOUSEMOVE)
+            msg != WM_RBUTTONDOWN)
         {
             /*
-             * If this mouse signal is not a button-down action or a move,
+             * If this mouse signal is not a button-down action
              * then it is the last signal being ignored.
              */
             GuiData->IgnoreNextMouseSignal = FALSE;
@@ -1251,7 +1403,7 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
         else
         {
             /*
-             * This mouse signal is a button-down action or a move.
+             * This mouse signal is a button-down action.
              * Ignore it and perform default action.
              */
             Err = TRUE;
@@ -1273,27 +1425,26 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
             case WM_LBUTTONDOWN:
             {
                 /* Clear the old selection */
-                // UpdateSelection(GuiData, NULL);
                 GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
 
                 /* Restart a new selection */
-                GuiData->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
+                GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
                 SetCapture(GuiData->hWindow);
                 GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-                UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
+                UpdateSelection(GuiData,
+                                &GuiData->dwSelectionCursor,
+                                &GuiData->dwSelectionCursor);
 
                 break;
             }
 
             case WM_LBUTTONUP:
             {
-                // COORD c;
-
                 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-                // c = PointToCoord(GuiData, lParam);
+                // GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
                 GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
-                // UpdateSelection(GuiData, &c);
+                // UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
                 ReleaseCapture();
 
                 break;
@@ -1305,10 +1456,7 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 
                 if (GetType(Buffer) == TEXTMODE_BUFFER)
                 {
-#ifdef IS_WHITESPACE
-#undef IS_WHITESPACE
-#endif
-#define IS_WHITESPACE(c)    \
+#define IS_WORD_SEP(c)  \
     ((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
 
                     PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
@@ -1320,15 +1468,15 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                     ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y);
 
                     /* Enlarge the selection by checking for whitespace */
-                    while ((0 < cL.X) && !IS_WHITESPACE(ptrL->Char.UnicodeChar)
-                                      && !IS_WHITESPACE((ptrL-1)->Char.UnicodeChar))
+                    while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar)
+                                      && !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar))
                     {
                         --cL.X;
                         --ptrL;
                     }
                     while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) &&
-                           !IS_WHITESPACE(ptrR->Char.UnicodeChar)      &&
-                           !IS_WHITESPACE((ptrR+1)->Char.UnicodeChar))
+                           !IS_WORD_SEP(ptrR->Char.UnicodeChar)        &&
+                           !IS_WORD_SEP((ptrR+1)->Char.UnicodeChar))
                     {
                         ++cR.X;
                         ++ptrR;
@@ -1338,11 +1486,8 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                      * Update the selection started with the single
                      * left-click that preceded this double-click.
                      */
-                    GuiData->Selection.dwSelectionAnchor = cL;
-                    GuiData->dwSelectionCursor           = cR;
-
                     GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
-                    UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
+                    UpdateSelection(GuiData, &cL, &cR);
 
                     /* Ignore the next mouse move signal */
                     GuiData->IgnoreNextMouseSignal = TRUE;
@@ -1370,13 +1515,12 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
 
             case WM_MOUSEMOVE:
             {
-                COORD c;
-
                 if (!(wParam & MK_LBUTTON)) break;
                 if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
 
-                c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
-                UpdateSelection(GuiData, &c);
+                // TODO: Scroll buffer to bring SelectionCursor into view
+                GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
+                UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
 
                 break;
             }
@@ -1467,6 +1611,20 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
                 break;
         }
 
+        /*
+         * HACK FOR CORE-8394: Ignore the next mouse move signal
+         * just after mouse down click actions.
+         */
+        switch (msg)
+        {
+            case WM_LBUTTONDOWN:
+            case WM_MBUTTONDOWN:
+            case WM_RBUTTONDOWN:
+                GuiData->IgnoreNextMouseSignal = TRUE;
+            default:
+                break;
+        }
+
         if (!Err)
         {
             if (wKeyState & MK_LBUTTON)
@@ -1546,7 +1704,7 @@ Copy(PGUI_CONSOLE_DATA GuiData)
     }
 
     /* Clear the selection */
-    UpdateSelection(GuiData, NULL);
+    UpdateSelection(GuiData, NULL, NULL);
 }
 
 VOID