From 5ef8871c62465f28af6c9105cdcb0e2073acedd2 Mon Sep 17 00:00:00 2001
From: Eric Pouech <eric.pouech@wanadoo.fr>
Date: Mon, 4 Feb 2002 18:41:32 +0000
Subject: [PATCH] - wineconsole now exits if the started program inside it
 terminates   before the console actually starts up. - Removed the last Ansi
 imported APIs since now Propsheet has a decent   Unicode interface. - Fixed a
 couple of menu related bugs (states were wrong). - Finished input selection
 code (mark and key for selection moving are   operational, generating mouse
 events to programs attached to the   console).

---
 programs/wineconsole/dialog.c          |  59 ++--
 programs/wineconsole/registry.c        |   9 +
 programs/wineconsole/user.c            | 373 ++++++++++++++++++-------
 programs/wineconsole/winecon_private.h |   1 +
 programs/wineconsole/winecon_user.h    |   2 +-
 programs/wineconsole/wineconsole_En.rc |  12 +-
 programs/wineconsole/wineconsole_Fr.rc |   8 +-
 programs/wineconsole/wineconsole_res.h |   1 +
 8 files changed, 339 insertions(+), 126 deletions(-)

diff --git a/programs/wineconsole/dialog.c b/programs/wineconsole/dialog.c
index a52918c904d..7c46ea9f919 100644
--- a/programs/wineconsole/dialog.c
+++ b/programs/wineconsole/dialog.c
@@ -9,14 +9,11 @@
 #include "prsht.h"
 #include "winecon_user.h"
 
-/* FIXME: so far, part of the code is made in ASCII because the Uncode property sheet functions
- * are not implemented yet
- */
-
 enum WCUSER_ApplyTo {
     /* Prop sheet CFG */
     WCUSER_ApplyToCursorSize, 
     WCUSER_ApplyToHistorySize, WCUSER_ApplyToHistoryMode, WCUSER_ApplyToMenuMask,
+    WCUSER_ApplyToEditMode,
     /* Prop sheet FNT */
     WCUSER_ApplyToFont, WCUSER_ApplyToAttribute,
     /* Prop sheep CNF */
@@ -56,6 +53,9 @@ static void WCUSER_ApplyDefault(struct dialog_info* di, HWND hDlg, enum WCUSER_A
     case WCUSER_ApplyToMenuMask:
         di->config->menu_mask = val;
         break;
+    case WCUSER_ApplyToEditMode:
+        di->config->quick_edit = val;
+        break;
     case WCUSER_ApplyToFont:
         WCUSER_CopyFont(di->config, &di->font[val].lf);
         break;
@@ -94,6 +94,9 @@ static void WCUSER_ApplyCurrent(struct dialog_info* di, HWND hDlg, enum WCUSER_A
     case WCUSER_ApplyToMenuMask:
         di->config->menu_mask = val;
         break;
+    case WCUSER_ApplyToEditMode:
+        di->config->quick_edit = val;
+        break;
     case WCUSER_ApplyToFont:
         WCUSER_SetFont(di->data, &di->font[val].lf);
         break;
@@ -127,7 +130,8 @@ static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
     case WM_INITDIALOG:
 	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
 	di->hDlg = hDlg;
-	SetWindowLongA(hDlg, DWL_USER, (DWORD)di);
+	SetWindowLong(hDlg, DWL_USER, (DWORD)di);
+
 	if (di->config->cursor_size <= 25)	idc = IDC_OPT_CURSOR_SMALL;
 	else if (di->config->cursor_size <= 50)	idc = IDC_OPT_CURSOR_MEDIUM;
 	else				        idc = IDC_OPT_CURSOR_LARGE;
@@ -139,6 +143,8 @@ static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
                            (di->config->menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0L);
         SendDlgItemMessage(hDlg, IDC_OPT_CONF_SHIFT, BM_SETCHECK, 
                            (di->config->menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0L);
+        SendDlgItemMessage(hDlg, IDC_OPT_QUICK_EDIT, BM_SETCHECK, 
+                           (di->config->quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0L);
 	return FALSE; /* because we set the focus */
     case WM_COMMAND:
 	break;
@@ -148,7 +154,8 @@ static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
         DWORD   val;
         BOOL	done;
 
-	di = (struct dialog_info*)GetWindowLongA(hDlg, DWL_USER);
+	di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
+
 	switch (nmhdr->code) 
 	{
 	case PSN_SETACTIVE:
@@ -181,6 +188,10 @@ static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
             if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_CTRL) & BST_CHECKED)  val |= MK_CONTROL;
             if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_SHIFT) & BST_CHECKED) val |= MK_SHIFT;
             (di->apply)(di, hDlg, WCUSER_ApplyToMenuMask, val);
+
+            val = (IsDlgButtonChecked(hDlg, IDC_OPT_QUICK_EDIT) & BST_CHECKED) ? TRUE : FALSE;
+            (di->apply)(di, hDlg, WCUSER_ApplyToEditMode, val);
+
             SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
 	    return TRUE;
 	default:
@@ -652,13 +663,13 @@ static BOOL WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
 BOOL WCUSER_GetProperties(struct inner_data* data, BOOL current)
 {
     HPROPSHEETPAGE	psPage[3];
-    PROPSHEETPAGEA	psp;
-    PROPSHEETHEADERA	psHead;
+    PROPSHEETPAGE	psp;
+    PROPSHEETHEADER	psHead;
+    WCHAR		buff[256];
     WNDCLASS		wndclass;
     static const WCHAR szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
     static const WCHAR szColorPreview[] = {'W','i','n','e','C','o','n','C','o','l','o','r','P','r','e','v','i','e','w',0};
     struct dialog_info	di;
-    CHAR		buff[256];
 
     InitCommonControls();
 
@@ -706,31 +717,39 @@ BOOL WCUSER_GetProperties(struct inner_data* data, BOOL current)
     psp.hInstance = wndclass.hInstance;
     psp.lParam = (LPARAM)&di;
 
-    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_OPTION);
+    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_OPTION);
     psp.pfnDlgProc = WCUSER_OptionDlgProc;
-    psPage[0] = CreatePropertySheetPageA(&psp);
+    psPage[0] = CreatePropertySheetPage(&psp);
 
-    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_FONT);
+    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_FONT);
     psp.pfnDlgProc = WCUSER_FontDlgProc;
-    psPage[1] = CreatePropertySheetPageA(&psp);
+    psPage[1] = CreatePropertySheetPage(&psp);
 
-    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_CONFIG);
+    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_CONFIG);
     psp.pfnDlgProc = WCUSER_ConfigDlgProc;
-    psPage[2] = CreatePropertySheetPageA(&psp);
+    psPage[2] = CreatePropertySheetPage(&psp);
 
     memset(&psHead, 0, sizeof(psHead));
     psHead.dwSize = sizeof(psHead);
 
-    if (!LoadStringA(GetModuleHandle(NULL), 
-                     (current) ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT, 
-                     buff, sizeof(buff)))
-        strcpy(buff, "Setup");
+    if (!LoadString(GetModuleHandle(NULL), 
+                    (current) ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT, 
+                    buff, sizeof(buff) / sizeof(buff[0])))
+    {
+        buff[0] = 'S';
+        buff[1] = 'e';
+        buff[2] = 't';
+        buff[3] = 'u';
+        buff[4] = 'p';
+        buff[5] = '\0';
+    }
+
     psHead.pszCaption = buff;
     psHead.nPages = 3;
     psHead.hwndParent = PRIVATE(data)->hWnd;
     psHead.u3.phpage = psPage;
  
-    PropertySheetA(&psHead);
+    PropertySheet(&psHead);
 
     return TRUE;
 }
diff --git a/programs/wineconsole/registry.c b/programs/wineconsole/registry.c
index c81b632b410..45b4d6e32ee 100644
--- a/programs/wineconsole/registry.c
+++ b/programs/wineconsole/registry.c
@@ -17,6 +17,7 @@ static const WCHAR wszFontSize[]          = {'F','o','n','t','S','i','z','e',0};
 static const WCHAR wszFontWeight[]        = {'F','o','n','t','W','e','i','g','h','t',0};
 static const WCHAR wszHistoryBufferSize[] = {'H','i','s','t','o','r','y','B','u','f','f','e','r','S','i','z','e',0};
 static const WCHAR wszMenuMask[]          = {'M','e','n','u','M','a','s','k',0};
+static const WCHAR wszQuickEdit[]         = {'Q','u','i','c','k','E','d','i','t',0};
 static const WCHAR wszScreenBufferSize[]  = {'S','c','r','e','e','n','B','u','f','f','e','r','S','i','z','e',0};
 static const WCHAR wszScreenColors[]      = {'S','c','r','e','e','n','C','o','l','o','r','s',0};
 static const WCHAR wszWindowSize[]        = {'W','i','n','d','o','w','S','i','z','e',0};
@@ -70,6 +71,11 @@ BOOL WINECON_RegLoad(struct config_data* cfg)
         val = 0;
     cfg->menu_mask = val;
 
+    count = sizeof(val);
+    if (!hConKey || RegQueryValueEx(hConKey, wszQuickEdit, 0, &type, (char*)&val, &count)) 
+        val = 0;
+    cfg->quick_edit = val;
+
     count = sizeof(val);
     if (!hConKey || RegQueryValueEx(hConKey, wszScreenBufferSize, 0, &type, (char*)&val, &count)) 
         val = 0x00190050;
@@ -129,6 +135,9 @@ BOOL WINECON_RegSave(const struct config_data* cfg)
     val = cfg->menu_mask;
     RegSetValueEx(hConKey, wszMenuMask, 0, REG_DWORD, (char*)&val, sizeof(val));
 
+    val = cfg->quick_edit;
+    RegSetValueEx(hConKey, wszQuickEdit, 0, REG_DWORD, (char*)&val, sizeof(val));
+
     val = MAKELONG(cfg->sb_width, cfg->sb_height);
     RegSetValueEx(hConKey, wszScreenBufferSize, 0, REG_DWORD, (char*)&val, sizeof(val));
 
diff --git a/programs/wineconsole/user.c b/programs/wineconsole/user.c
index fc1d453266f..61e6ef09f78 100644
--- a/programs/wineconsole/user.c
+++ b/programs/wineconsole/user.c
@@ -375,7 +375,7 @@ static void	WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
  *
  *
  */
-static void	WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
+static void	WCUSER_MoveSelection(struct inner_data* data, COORD c1, COORD c2, BOOL final)
 {
     RECT	r;
     HDC		hDC;
@@ -388,7 +388,8 @@ static void	WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
 	    HideCaret(PRIVATE(data)->hWnd);
 	InvertRect(hDC, &r);
     }
-    PRIVATE(data)->selectPt2 = dst;
+    PRIVATE(data)->selectPt1 = c1;
+    PRIVATE(data)->selectPt2 = c2;
     if (hDC)
     {
 	WCUSER_GetSelectionRect(data, &r);
@@ -400,7 +401,7 @@ static void	WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
     if (final)
     {
 	ReleaseCapture();
-	PRIVATE(data)->hasSelection = TRUE;
+	PRIVATE(data)->has_selection = TRUE;
     }
 }
 
@@ -522,7 +523,7 @@ static void	WCUSER_Paint(const struct inner_data* data)
            data->curcfg.win_pos.X * data->curcfg.cell_width, 
            data->curcfg.win_pos.Y * data->curcfg.cell_height,
 	   SRCCOPY);
-    if (PRIVATE(data)->hasSelection)
+    if (PRIVATE(data)->has_selection)
 	WCUSER_SetSelection(data, ps.hdc);
     EndPaint(PRIVATE(data)->hWnd, &ps);
 }
@@ -678,6 +679,7 @@ static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
     PRIVATE(data)->hMemDC = CreateCompatibleDC(0);
     if (!PRIVATE(data)->hMemDC) {Trace(0, "no mem dc\n");return 0;}
 
+    data->curcfg.quick_edit = FALSE;
     return 0;
 }
 
@@ -686,25 +688,148 @@ static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
  *
  * Grays / ungrays the menu items according to their state
  */
-static void	WCUSER_SetMenuDetails(const struct inner_data* data)
+static void	WCUSER_SetMenuDetails(const struct inner_data* data, HMENU hMenu)
 {
-    HMENU		hMenu = GetSystemMenu(PRIVATE(data)->hWnd, FALSE);
-
     if (!hMenu) {Trace(0, "Issue in getting menu bits\n");return;}
 
-    /* FIXME: set the various menu items to their state (if known) */
-    EnableMenuItem(hMenu, IDS_DEFAULT, MF_BYCOMMAND|MF_GRAYED);
-
-    EnableMenuItem(hMenu, IDS_MARK, MF_BYCOMMAND|MF_GRAYED);
-    EnableMenuItem(hMenu, IDS_COPY, MF_BYCOMMAND|(PRIVATE(data)->hasSelection ? MF_ENABLED : MF_GRAYED));
+    EnableMenuItem(hMenu, IDS_COPY, 
+                   MF_BYCOMMAND|(PRIVATE(data)->has_selection ? MF_ENABLED : MF_GRAYED));
     EnableMenuItem(hMenu, IDS_PASTE, 
 		   MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT) 
 				 ? MF_ENABLED : MF_GRAYED));
-    /* Select all: always active */
     EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
     EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
 }
 
+/******************************************************************
+ *		CUSER_GetCtrlKeyState
+ *
+ * Get the console bit mask equivalent to the VK_ status in keyState
+ */
+static DWORD    WCUSER_GetCtrlKeyState(BYTE* keyState)
+{
+    DWORD               ret = 0;
+
+    GetKeyboardState(keyState);
+    if (keyState[VK_SHIFT]    & 0x80)	ret |= SHIFT_PRESSED;
+    if (keyState[VK_CONTROL]  & 0x80)	ret |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
+    if (keyState[VK_LCONTROL] & 0x80)	ret |= LEFT_CTRL_PRESSED;
+    if (keyState[VK_RCONTROL] & 0x80)	ret |= RIGHT_CTRL_PRESSED;
+    if (keyState[VK_LMENU]    & 0x80)	ret |= LEFT_ALT_PRESSED;
+    if (keyState[VK_RMENU]    & 0x80)	ret |= RIGHT_ALT_PRESSED;
+    if (keyState[VK_CAPITAL]  & 0x01)	ret |= CAPSLOCK_ON;	    
+    if (keyState[VK_NUMLOCK]  & 0x01)	ret |= NUMLOCK_ON;
+    if (keyState[VK_SCROLL]   & 0x01)	ret |= SCROLLLOCK_ON;
+    
+    return ret;
+}
+
+/******************************************************************
+ *		WCUSER_HandleSelectionKey
+ *
+ * Handles keys while selecting an area
+ */
+static void WCUSER_HandleSelectionKey(struct inner_data* data, BOOL down, 
+                                      WPARAM wParam, LPARAM lParam)
+{
+    BYTE	keyState[256];
+    DWORD       state = WCUSER_GetCtrlKeyState(keyState) & ~(CAPSLOCK_ON|NUMLOCK_ON|SCROLLLOCK_ON);
+    COORD       c1, c2;
+
+    if (down) return;
+
+    switch (state)
+    {
+    case 0:
+        switch (wParam)
+        {
+        case VK_RETURN:
+            PRIVATE(data)->has_selection = FALSE;
+            WCUSER_SetSelection(data, 0);
+            WCUSER_CopySelectionToClipboard(data);
+            break;
+        case VK_RIGHT:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c1.X++; c2.X++;
+            if (c1.X < data->curcfg.sb_width && c2.X < data->curcfg.sb_width)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_LEFT:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c1.X--; c2.X--;
+            if (c1.X >= 0 && c2.X >= 0)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_UP:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c1.Y--; c2.Y--;
+            if (c1.Y >= 0 && c2.Y >= 0)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_DOWN:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c1.Y++; c2.Y++;
+            if (c1.X < data->curcfg.sb_height && c2.X < data->curcfg.sb_height)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        }
+        break;
+    case SHIFT_PRESSED:
+        switch (wParam)
+        {
+        case VK_RIGHT:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c2.X++;
+            if (c2.X < data->curcfg.sb_width)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_LEFT:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c2.X--;
+            if (c2.X >= c1.X)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_UP:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c2.Y--;
+            if (c2.Y >= c1.Y)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        case VK_DOWN:
+            c1 = PRIVATE(data)->selectPt1;
+            c2 = PRIVATE(data)->selectPt2;
+            c2.Y++;
+            if (c2.X < data->curcfg.sb_height)
+            {
+                WCUSER_MoveSelection(data, c1, c2, FALSE);
+            }
+            break;
+        }
+        break;
+    }
+}
+
 /******************************************************************
  *		WCUSER_GenerateKeyInputRecord
  *
@@ -716,8 +841,8 @@ static void    WCUSER_GenerateKeyInputRecord(struct inner_data* data, BOOL down,
     INPUT_RECORD	ir;
     DWORD		n;
     WCHAR		buf[2];
-    BYTE		keyState[256];
     static	WCHAR	last; /* keep last char seen as feed for key up message */
+    BYTE		keyState[256];
 
     ir.EventType = KEY_EVENT;
     ir.Event.KeyEvent.bKeyDown = down;
@@ -725,31 +850,12 @@ static void    WCUSER_GenerateKeyInputRecord(struct inner_data* data, BOOL down,
     ir.Event.KeyEvent.wVirtualKeyCode = wParam;
     
     ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
-    GetKeyboardState(keyState);
     
     ir.Event.KeyEvent.uChar.UnicodeChar = 0;
-    ir.Event.KeyEvent.dwControlKeyState = 0;
+    ir.Event.KeyEvent.dwControlKeyState = WCUSER_GetCtrlKeyState(keyState);
     if (lParam & (1L << 24))		ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
-    if (keyState[VK_SHIFT]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
-    if (keyState[VK_CONTROL]  & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
-    if (keyState[VK_LCONTROL] & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
-    if (keyState[VK_RCONTROL] & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
     if (sys)				ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; /* FIXME: gotta choose one */
-    if (keyState[VK_LMENU]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
-    if (keyState[VK_RMENU]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
-    if (keyState[VK_CAPITAL]  & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= CAPSLOCK_ON;	    
-    if (keyState[VK_NUMLOCK]  & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= NUMLOCK_ON;
-    if (keyState[VK_SCROLL]   & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= SCROLLLOCK_ON;
-
-    if (PRIVATE(data)->hasSelection && ir.Event.KeyEvent.dwControlKeyState == 0 && 
-	ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)
-    {
-	PRIVATE(data)->hasSelection = FALSE;
-	WCUSER_SetSelection(data, 0);
-	WCUSER_CopySelectionToClipboard(data);
-	return;
-    }
-    
+
     if (!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
     {
 	if (down)
@@ -774,6 +880,34 @@ static void    WCUSER_GenerateKeyInputRecord(struct inner_data* data, BOOL down,
     WriteConsoleInput(data->hConIn, &ir, 1, &n);
 }
 
+/******************************************************************
+ *		WCUSER_GenerateMouseInputRecord
+ *
+ *
+ */
+static void    WCUSER_GenerateMouseInputRecord(struct inner_data* data, COORD c, 
+                                               WPARAM wParam, DWORD event)
+{
+    INPUT_RECORD	ir;
+    BYTE		keyState[256];
+    DWORD               mode, n;
+
+    /* MOUSE_EVENTs shouldn't be sent unless ENABLE_MOUSE_INPUT is active */
+    if (!GetConsoleMode(data->hConIn, &mode) || !(mode & ENABLE_MOUSE_INPUT))
+        return;
+
+    ir.EventType = MOUSE_EVENT;
+    ir.Event.MouseEvent.dwMousePosition = c;
+    ir.Event.MouseEvent.dwButtonState = 0;
+    if (wParam & MK_LBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_1ST_BUTTON_PRESSED;
+    if (wParam & MK_MBUTTON) ir.Event.MouseEvent.dwButtonState |= FROM_LEFT_2ND_BUTTON_PRESSED;
+    if (wParam & MK_RBUTTON) ir.Event.MouseEvent.dwButtonState |= RIGHTMOST_BUTTON_PRESSED;
+    ir.Event.MouseEvent.dwControlKeyState = WCUSER_GetCtrlKeyState(keyState);
+    ir.Event.MouseEvent.dwEventFlags = event;
+
+    WriteConsoleInput(data->hConIn, &ir, 1, &n);
+}
+
 /******************************************************************
  *		WCUSER_Proc
  *
@@ -796,39 +930,88 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 	break;
     case WM_KEYDOWN:
     case WM_KEYUP:
-	WCUSER_GenerateKeyInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
+        if (PRIVATE(data)->has_selection)
+            WCUSER_HandleSelectionKey(data, uMsg == WM_KEYDOWN, wParam, lParam);
+        else
+            WCUSER_GenerateKeyInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
 	break;
     case WM_SYSKEYDOWN:
     case WM_SYSKEYUP:
 	WCUSER_GenerateKeyInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam, TRUE);
 	break;
     case WM_LBUTTONDOWN:
-	/* EPP if (wParam != MK_LBUTTON) */
-	if (PRIVATE(data)->hasSelection)
-	{
-	    PRIVATE(data)->hasSelection = FALSE;
-	}
-	else
-	{
-	    PRIVATE(data)->selectPt1 = PRIVATE(data)->selectPt2 = WCUSER_GetCell(data, lParam);
-	    SetCapture(PRIVATE(data)->hWnd);
-	}
-	WCUSER_SetSelection(data, 0);
+        if (data->curcfg.quick_edit)
+        {
+            if (PRIVATE(data)->has_selection)
+            {
+                PRIVATE(data)->has_selection = FALSE;
+                WCUSER_SetSelection(data, 0);
+            }
+            else
+            {
+                PRIVATE(data)->selectPt1 = PRIVATE(data)->selectPt2 = WCUSER_GetCell(data, lParam);
+                SetCapture(PRIVATE(data)->hWnd);
+                WCUSER_SetSelection(data, 0);
+                PRIVATE(data)->has_selection = TRUE;
+            }
+        }
+        else 
+        {
+            WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
+        }
 	break;
     case WM_MOUSEMOVE:
-	/* EPP if (wParam != MK_LBUTTON) */
-        if (GetCapture() == PRIVATE(data)->hWnd)
-	{
-	    WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), FALSE);
-	}
+        if (data->curcfg.quick_edit)
+        {
+            if (GetCapture() == PRIVATE(data)->hWnd && PRIVATE(data)->has_selection &&
+                (wParam & MK_LBUTTON))
+            {
+                WCUSER_MoveSelection(data, PRIVATE(data)->selectPt1, WCUSER_GetCell(data, lParam), FALSE);
+            }
+        }
+        else
+        {
+            WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, MOUSE_MOVED);
+        }
 	break;
     case WM_LBUTTONUP:
-	/* EPP if (wParam != MK_LBUTTON) */
-        if (GetCapture() == PRIVATE(data)->hWnd)
-	{
-	    WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), TRUE);
-	}
+        if (data->curcfg.quick_edit)
+        {
+            if (GetCapture() == PRIVATE(data)->hWnd && PRIVATE(data)->has_selection && 
+                (wParam& MK_LBUTTON))
+            {
+                WCUSER_MoveSelection(data, PRIVATE(data)->selectPt1, WCUSER_GetCell(data, lParam), TRUE);
+            }
+        }
+        else
+        {
+            WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
+        }
 	break;
+    case WM_RBUTTONDOWN:
+        if ((wParam & (MK_CONTROL|MK_SHIFT)) == data->curcfg.menu_mask)
+        {
+            RECT        r;
+
+            GetWindowRect(hWnd, &r);
+            WCUSER_SetMenuDetails(data, PRIVATE(data)->hPopMenu);
+            TrackPopupMenu(PRIVATE(data)->hPopMenu, TPM_LEFTALIGN|TPM_TOPALIGN, 
+                           r.left + LOWORD(lParam), r.top + HIWORD(lParam), 0, hWnd, NULL);
+        }
+        else
+        {
+            WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
+        }
+	break;    
+    case WM_RBUTTONUP:
+        /* no need to track for rbutton up when opening the popup... the event will be
+         * swallowed by TrackPopupMenu */
+        WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, 0);
+	break;    
+    case WM_MOUSEWHEEL:
+        /* FIXME: should we scroll too ? */
+        WCUSER_GenerateMouseInputRecord(data, WCUSER_GetCell(data, lParam), wParam, MOUSE_WHEELED);
+	break;    
     case WM_SETFOCUS:
 	if (data->curcfg.cursor_visible)
 	{
@@ -843,31 +1026,31 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 	break;
     case WM_HSCROLL: 
         {
-	    int	pos = data->curcfg.win_pos.X;
+            int	pos = data->curcfg.win_pos.X;
 
-	    switch (LOWORD(wParam)) 
-	    { 
+            switch (LOWORD(wParam)) 
+            { 
             case SB_PAGEUP: 	pos -= 8; 		break; 
             case SB_PAGEDOWN: 	pos += 8; 		break; 
             case SB_LINEUP: 	pos--;			break;
-	    case SB_LINEDOWN: 	pos++;	 		break;
+            case SB_LINEDOWN: 	pos++;	 		break;
             case SB_THUMBTRACK: pos = HIWORD(wParam);	break;
             default: 					break;
-	    } 
-	    if (pos < 0) pos = 0;
-	    if (pos > data->curcfg.sb_width - data->curcfg.win_width) 
+            } 
+            if (pos < 0) pos = 0;
+            if (pos > data->curcfg.sb_width - data->curcfg.win_width) 
                 pos = data->curcfg.sb_width - data->curcfg.win_width;
-	    if (pos != data->curcfg.win_pos.X)
-	    {
-		ScrollWindow(hWnd, (data->curcfg.win_pos.X - pos) * data->curcfg.cell_width, 0, 
+            if (pos != data->curcfg.win_pos.X)
+            {
+                ScrollWindow(hWnd, (data->curcfg.win_pos.X - pos) * data->curcfg.cell_width, 0, 
                              NULL, NULL);
-		data->curcfg.win_pos.X = pos;
-		SetScrollPos(hWnd, SB_HORZ, pos, TRUE); 
-		UpdateWindow(hWnd); 
-		WCUSER_PosCursor(data);
-		WINECON_NotifyWindowChange(data);
-	    }
-        } 
+                data->curcfg.win_pos.X = pos;
+                SetScrollPos(hWnd, SB_HORZ, pos, TRUE); 
+                UpdateWindow(hWnd); 
+                WCUSER_PosCursor(data);
+                WINECON_NotifyWindowChange(data);
+            }
+        }
 	break;
     case WM_VSCROLL: 
         {
@@ -895,8 +1078,8 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 		WCUSER_PosCursor(data);
 		WINECON_NotifyWindowChange(data);
 	    }
+
         } 
-	break;
     case WM_SYSCOMMAND:
 	switch (wParam)
 	{
@@ -910,16 +1093,6 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 	    return DefWindowProc(hWnd, uMsg, wParam, lParam);
 	}
 	break;
-    case WM_RBUTTONDOWN:
-        if ((wParam & (MK_CONTROL|MK_SHIFT)) == data->curcfg.menu_mask)
-        {
-            RECT        r;
-
-            GetWindowRect(hWnd, &r);
-            TrackPopupMenu(PRIVATE(data)->hPopMenu, TPM_LEFTALIGN|TPM_TOPALIGN, 
-                           r.left + LOWORD(lParam), r.top + HIWORD(lParam), 0, hWnd, NULL);
-        }
-	break;    
     case WM_COMMAND:
 	switch (wParam)
 	{
@@ -930,25 +1103,31 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 	    WCUSER_GetProperties(data, TRUE);
 	    break;
 	case IDS_MARK:
-	    goto niy;
+            PRIVATE(data)->selectPt1.X = PRIVATE(data)->selectPt1.Y = 0;
+            PRIVATE(data)->selectPt2.X = PRIVATE(data)->selectPt2.Y = 0;
+            WCUSER_SetSelection(data, 0);
+            PRIVATE(data)->has_selection = TRUE;
+	    break;
 	case IDS_COPY:
-	    PRIVATE(data)->hasSelection = FALSE;
-	    WCUSER_SetSelection(data, 0);
-	    WCUSER_CopySelectionToClipboard(data);
+            if (PRIVATE(data)->has_selection)
+            {
+                PRIVATE(data)->has_selection = FALSE;
+                WCUSER_SetSelection(data, 0);
+                WCUSER_CopySelectionToClipboard(data);
+            }
 	    break;
 	case IDS_PASTE:
 	    WCUSER_PasteFromClipboard(data);
 	    break;
 	case IDS_SELECTALL:
-	    PRIVATE(data)->selectPt1.X = PRIVATE(data)->selectPt1.Y = 0;
-	    PRIVATE(data)->selectPt2.X = (data->curcfg.sb_width - 1) * data->curcfg.cell_width;
-	    PRIVATE(data)->selectPt2.Y = (data->curcfg.sb_height - 1) * data->curcfg.cell_height;
-	    WCUSER_SetSelection(data, 0);
-	    PRIVATE(data)->hasSelection = TRUE;
+            PRIVATE(data)->selectPt1.X = PRIVATE(data)->selectPt1.Y = 0;
+            PRIVATE(data)->selectPt2.X = (data->curcfg.sb_width - 1) * data->curcfg.cell_width;
+            PRIVATE(data)->selectPt2.Y = (data->curcfg.sb_height - 1) * data->curcfg.cell_height;
+            WCUSER_SetSelection(data, 0);
+            PRIVATE(data)->has_selection = TRUE;
 	    break;
 	case IDS_SCROLL:
 	case IDS_SEARCH:
-	niy:
 	    Trace(0, "unhandled yet command: %x\n", wParam);
 	    break;
 	default: 
@@ -957,7 +1136,7 @@ static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 	break;
     case WM_INITMENUPOPUP:
 	if (!HIWORD(lParam))	return DefWindowProc(hWnd, uMsg, wParam, lParam);
-	WCUSER_SetMenuDetails(data);
+	WCUSER_SetMenuDetails(data, GetSystemMenu(PRIVATE(data)->hWnd, FALSE));
 	break;
     default:
 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
@@ -1062,7 +1241,7 @@ BOOL WCUSER_InitBackend(struct inner_data* data)
     if (!PRIVATE(data)->hWnd) return FALSE;
 
     /* force update of current data */
-    WINECON_GrabChanges(data);
+    if (!WINECON_GrabChanges(data)) return FALSE;
 
     if (!WCUSER_InitFont(data))
     {
diff --git a/programs/wineconsole/winecon_private.h b/programs/wineconsole/winecon_private.h
index ebb712bd84b..90299f35587 100644
--- a/programs/wineconsole/winecon_private.h
+++ b/programs/wineconsole/winecon_private.h
@@ -20,6 +20,7 @@ struct config_data {
     DWORD       font_weight;
     DWORD       history_size;
     DWORD       menu_mask;      /* MK_CONTROL MK_SHIFT mask to drive submenu opening */
+    DWORD       quick_edit;     /* whether mouse ops are sent to app (false) or used for content selection (true) */
     unsigned	sb_width;	/* active screen buffer width */
     unsigned	sb_height;	/* active screen buffer height */
     unsigned	win_width;	/* size (in cells) of visible part of window (width & height) */
diff --git a/programs/wineconsole/winecon_user.h b/programs/wineconsole/winecon_user.h
index 944ec571c2e..bf8d90b468f 100644
--- a/programs/wineconsole/winecon_user.h
+++ b/programs/wineconsole/winecon_user.h
@@ -19,7 +19,7 @@ struct inner_data_user {
     HMENU               hPopMenu;       /* popup menu triggered by right mouse click */
 
     HBITMAP		cursor_bitmap;  /* bitmap used for the caret */
-    BOOL		hasSelection;	/* a rectangular mouse selection has taken place */
+    BOOL                has_selection;  /* an area is being selected (selectPt[12] are edges of the rect) */
     COORD		selectPt1;	/* start (and end) point of a mouse selection */
     COORD		selectPt2;
 };
diff --git a/programs/wineconsole/wineconsole_En.rc b/programs/wineconsole/wineconsole_En.rc
index 0245d609866..fc975914f40 100644
--- a/programs/wineconsole/wineconsole_En.rc
+++ b/programs/wineconsole/wineconsole_En.rc
@@ -23,15 +23,17 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION " Options "
 FONT 8, "Helv"
 {
-	GROUPBOX "Cursor size", -1, 10, 11, 120, 44, BS_GROUPBOX
+	GROUPBOX "Cursor size", -1, 10, 11, 100, 44, BS_GROUPBOX
 	AUTORADIOBUTTON "&Small", IDC_OPT_CURSOR_SMALL, 14, 23, 84, 10, WS_TABSTOP
 	AUTORADIOBUTTON "&Medium", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
 	AUTORADIOBUTTON "&Large", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
 
-	GROUPBOX "Conf. open", -1, 140, 11, 60, 44, BS_GROUPBOX
-	AUTOCHECKBOX "&Control", IDC_OPT_CONF_CTRL, 144, 23, 50, 10, WS_TABSTOP
-	AUTOCHECKBOX "S&hift", IDC_OPT_CONF_SHIFT, 144, 33, 50, 10, WS_TABSTOP
-
+	GROUPBOX "Control", -1, 115, 11, 85, 44, BS_GROUPBOX
+	LTEXT "Popup menu", -1, 119, 23, 40, 10
+	AUTOCHECKBOX "&Control", IDC_OPT_CONF_CTRL, 159, 23, 40, 10, WS_TABSTOP
+	AUTOCHECKBOX "S&hift", IDC_OPT_CONF_SHIFT, 159, 33, 40, 10, WS_TABSTOP
+	AUTOCHECKBOX "&Quick edit", IDC_OPT_QUICK_EDIT, 119, 44, 40, 10, WS_TABSTOP|BS_MULTILINE|BS_LEFTTEXT
+	
 	GROUPBOX "Command history", -1, 10, 57, 190, 35, BS_GROUPBOX
 	LTEXT "&Numbers of recalled commands :", -1, 14, 67, 78, 18
 	EDITTEXT IDC_OPT_HIST_SIZE, 92, 69, 31, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
diff --git a/programs/wineconsole/wineconsole_Fr.rc b/programs/wineconsole/wineconsole_Fr.rc
index 67e123656a3..7c679a16964 100644
--- a/programs/wineconsole/wineconsole_Fr.rc
+++ b/programs/wineconsole/wineconsole_Fr.rc
@@ -28,9 +28,11 @@ FONT 8, "Helv"
 	AUTORADIOBUTTON "&Moyen", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
 	AUTORADIOBUTTON "&Grand", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
 
-	GROUPBOX "Ouverture conf.", -1, 140, 11, 60, 44, BS_GROUPBOX
-	AUTOCHECKBOX "&Control", IDC_OPT_CONF_CTRL, 144, 23, 50, 10, WS_TABSTOP
-	AUTOCHECKBOX "S&hift", IDC_OPT_CONF_SHIFT, 144, 33, 50, 10, WS_TABSTOP
+	GROUPBOX "Contrôle", -1, 115, 11, 85, 44, BS_GROUPBOX
+	LTEXT "Popup menu", -1, 119, 23, 40, 10
+	AUTOCHECKBOX "&Control", IDC_OPT_CONF_CTRL, 159, 23, 40, 10, WS_TABSTOP
+	AUTOCHECKBOX "S&hift", IDC_OPT_CONF_SHIFT, 159, 33, 40, 10, WS_TABSTOP
+	AUTOCHECKBOX "&Edition rapide", IDC_OPT_QUICK_EDIT, 119, 44, 40, 10, WS_TABSTOP|BS_MULTILINE|BS_LEFTTEXT
 
 	GROUPBOX "Historique des commandes", -1, 10, 57, 190, 35, BS_GROUPBOX
 	LTEXT "&Taille de la mémoire tampon :", -1, 14, 67, 78, 18
diff --git a/programs/wineconsole/wineconsole_res.h b/programs/wineconsole/wineconsole_res.h
index 66afd6b517e..c021dd5238a 100644
--- a/programs/wineconsole/wineconsole_res.h
+++ b/programs/wineconsole/wineconsole_res.h
@@ -32,6 +32,7 @@
 #define IDC_OPT_HIST_DOUBLE	0x0106
 #define IDC_OPT_CONF_CTRL       0x0107
 #define IDC_OPT_CONF_SHIFT      0x0108
+#define IDC_OPT_QUICK_EDIT      0x0109
 
 #define IDC_FNT_LIST_FONT	0x0201
 #define IDC_FNT_LIST_SIZE	0x0202
-- 
GitLab