[KSPROXY]
[reactos.git] / reactos / dll / cpl / desk / monslctl.c
index d8efe44..74390fc 100644 (file)
@@ -27,11 +27,17 @@ typedef struct _MONITORSELWND
             UINT Enabled : 1;
             UINT HasFocus : 1;
             UINT CanDisplay : 1;
+            UINT LeftBtnDown : 1;
+            UINT IsDraggingMonitor : 1;
         };
     };
     DWORD ControlExStyle;
     DWORD MonitorsCount;
     INT SelectedMonitor;
+    INT DraggingMonitor;
+    RECT rcDragging;
+    POINT ptDrag, ptDragBegin;
+    SIZE DraggingMargin;
     PMONSL_MONINFO MonitorInfo;
     PMONSL_MON Monitors;
     RECT rcExtent;
@@ -265,15 +271,34 @@ MonSelRepaintMonitor(IN PMONITORSELWND infoPtr,
                      IN DWORD Index)
 {
     RECT rc;
+    BOOL NoRepaint = FALSE;
 
     if (Index < infoPtr->MonitorsCount)
     {
-        MonSelRectToScreen(infoPtr,
-                           &infoPtr->Monitors[Index].rc,
-                           &rc);
-        InvalidateRect(infoPtr->hSelf,
-                       &rc,
-                       TRUE);
+        if (Index == (DWORD)infoPtr->DraggingMonitor)
+        {
+            if (infoPtr->IsDraggingMonitor)
+            {
+                MonSelRectToScreen(infoPtr,
+                                   &infoPtr->rcDragging,
+                                   &rc);
+            }
+            else
+                NoRepaint = TRUE;
+        }
+        else
+        {
+            MonSelRectToScreen(infoPtr,
+                               &infoPtr->Monitors[Index].rc,
+                               &rc);
+        }
+
+        if (!NoRepaint)
+        {
+            InvalidateRect(infoPtr->hSelf,
+                           &rc,
+                           TRUE);
+        }
     }
 }
 
@@ -370,6 +395,9 @@ MonSelSetMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
     DWORD Index;
     BOOL Ret = TRUE;
 
+    if (infoPtr->DraggingMonitor >= 0)
+        return FALSE;
+
     if (infoPtr->MonitorInfo != NULL)
     {
         LocalFree((HLOCAL)infoPtr->MonitorInfo);
@@ -466,7 +494,8 @@ MonSelSetMonitorInfo(IN OUT PMONITORSELWND infoPtr,
                      IN INT Index,
                      IN const MONSL_MONINFO *MonitorsInfo)
 {
-    if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
+    if (infoPtr->DraggingMonitor < 0 &&
+        Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
     {
         CopyMemory(&infoPtr->MonitorInfo[Index],
                    MonitorsInfo,
@@ -496,6 +525,32 @@ MonSelGetMonitorInfo(IN PMONITORSELWND infoPtr,
     return FALSE;
 }
 
+static INT
+MonSelGetMonitorRect(IN OUT PMONITORSELWND infoPtr,
+                     IN INT Index,
+                     OUT PRECT prc)
+{
+    RECT rc, rcClient;
+
+    if (Index < 0 || Index >= infoPtr->MonitorsCount)
+        return -1;
+
+    if (!infoPtr->CanDisplay)
+        return 0;
+
+    MonSelRectToScreen(infoPtr,
+                       &infoPtr->Monitors[Index].rc,
+                       prc);
+
+    rcClient.left = rcClient.top = 0;
+    rcClient.right = infoPtr->ClientSize.cx;
+    rcClient.bottom = infoPtr->ClientSize.cy;
+
+    return IntersectRect(&rc,
+                         &rcClient,
+                         prc) != FALSE;
+}
+
 static BOOL
 MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
                        IN INT Index,
@@ -505,7 +560,8 @@ MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
     BOOL PreventSelect = FALSE;
     BOOL Ret = FALSE;
 
-    if (Index == -1 || Index < (INT)infoPtr->MonitorsCount)
+    if (infoPtr->DraggingMonitor < 0 &&
+        (Index == -1 || Index < (INT)infoPtr->MonitorsCount))
     {
         if (Index != infoPtr->SelectedMonitor)
         {
@@ -568,7 +624,9 @@ MonSelCreate(IN OUT PMONITORSELWND infoPtr)
     infoPtr->SelectionFrame.cx = infoPtr->SelectionFrame.cy = 4;
     infoPtr->Margin.cx = infoPtr->Margin.cy = 20;
     infoPtr->SelectedMonitor = -1;
-    infoPtr->ControlExStyle = MSLM_EX_ALLOWSELECTDISABLED;
+    infoPtr->DraggingMonitor = -1;
+    infoPtr->ControlExStyle = MSLM_EX_ALLOWSELECTDISABLED | MSLM_EX_HIDENUMBERONSINGLE |
+        MSLM_EX_SELECTONRIGHTCLICK | MSLM_EX_SELECTBYARROWKEY;
     return;
 }
 
@@ -597,6 +655,9 @@ static BOOL
 MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr,
                        IN DWORD dwExtendedStyle)
 {
+    if (infoPtr->DraggingMonitor >= 0)
+        return FALSE;
+
     if (dwExtendedStyle != infoPtr->ControlExStyle)
     {
         infoPtr->ControlExStyle = dwExtendedStyle;
@@ -697,18 +758,101 @@ MonSelDrawDisabledRect(IN OUT PMONITORSELWND infoPtr,
     return Ret;
 }
 
+static VOID
+MonSelPaintMonitor(IN OUT PMONITORSELWND infoPtr,
+                   IN HDC hDC,
+                   IN DWORD Index,
+                   IN OUT PRECT prc,
+                   IN COLORREF crDefFontColor,
+                   IN BOOL bHideNumber)
+{
+    HFONT hFont, hPrevFont;
+    COLORREF crPrevText;
+
+    if ((INT)Index == infoPtr->SelectedMonitor)
+    {
+        FillRect(hDC,
+                 prc,
+                 (HBRUSH)(COLOR_HIGHLIGHT + 1));
+
+        if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
+        {
+            /* NOTE: We need to switch the text color to the default, because
+                     DrawFocusRect draws a solid line if the text is white! */
+
+            crPrevText = SetTextColor(hDC,
+                                      crDefFontColor);
+
+            DrawFocusRect(hDC,
+                          prc);
+
+            SetTextColor(hDC,
+                         crPrevText);
+        }
+    }
+
+    InflateRect(prc,
+                -infoPtr->SelectionFrame.cx,
+                -infoPtr->SelectionFrame.cy);
+
+    Rectangle(hDC,
+              prc->left,
+              prc->top,
+              prc->right,
+              prc->bottom);
+
+    InflateRect(prc,
+                -1,
+                -1);
+
+    if (!bHideNumber)
+    {
+        hFont = MonSelGetMonitorFont(infoPtr,
+                                     hDC,
+                                     Index);
+        if (hFont != NULL)
+        {
+            hPrevFont = SelectObject(hDC,
+                                     hFont);
+
+            DrawText(hDC,
+                     infoPtr->Monitors[Index].szCaption,
+                     -1,
+                     prc,
+                     DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
+
+            SelectObject(hDC,
+                         hPrevFont);
+        }
+    }
+
+    if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
+    {
+        InflateRect(prc,
+                    1,
+                    1);
+
+        MonSelDrawDisabledRect(infoPtr,
+                               hDC,
+                               prc);
+    }
+}
+
 static VOID
 MonSelPaint(IN OUT PMONITORSELWND infoPtr,
             IN HDC hDC,
             IN const RECT *prcUpdate)
 {
-    COLORREF crPrevText, crPrevText2;
-    HFONT hFont, hPrevFont;
+    COLORREF crPrevText;
     HBRUSH hbBk, hbOldBk;
     HPEN hpFg, hpOldFg;
     DWORD Index;
     RECT rc, rctmp;
     INT iPrevBkMode;
+    BOOL bHideNumber;
+
+    bHideNumber = (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERS) ||
+        ((infoPtr->MonitorsCount == 1) && (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERONSINGLE));
 
     hbBk = GetSysColorBrush(COLOR_BACKGROUND);
     hpFg = CreatePen(PS_SOLID,
@@ -726,91 +870,291 @@ MonSelPaint(IN OUT PMONITORSELWND infoPtr,
 
     for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
     {
+        if (infoPtr->IsDraggingMonitor &&
+            (DWORD)infoPtr->DraggingMonitor == Index)
+        {
+            continue;
+        }
+
         MonSelRectToScreen(infoPtr,
                            &infoPtr->Monitors[Index].rc,
                            &rc);
 
-        if (!IntersectRect(&rctmp,
-                           &rc,
-                           prcUpdate))
+        if (IntersectRect(&rctmp,
+                          &rc,
+                          prcUpdate))
         {
-            continue;
+            MonSelPaintMonitor(infoPtr,
+                               hDC,
+                               Index,
+                               &rc,
+                               crPrevText,
+                               bHideNumber);
         }
+    }
+
+    /* Paint the dragging monitor last */
+    if (infoPtr->IsDraggingMonitor &&
+        infoPtr->DraggingMonitor >= 0)
+    {
+        MonSelRectToScreen(infoPtr,
+                           &infoPtr->rcDragging,
+                           &rc);
 
-        if ((INT)Index == infoPtr->SelectedMonitor)
+        if (IntersectRect(&rctmp,
+                          &rc,
+                          prcUpdate))
         {
-            FillRect(hDC,
-                     &rc,
-                     (HBRUSH)(COLOR_HIGHLIGHT + 1));
+            MonSelPaintMonitor(infoPtr,
+                               hDC,
+                               (DWORD)infoPtr->DraggingMonitor,
+                               &rc,
+                               crPrevText,
+                               bHideNumber);
+        }
+    }
 
-            if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
+    SetTextColor(hDC,
+                 crPrevText);
+    SetBkMode(hDC,
+              iPrevBkMode);
+    SelectObject(hDC,
+                 hpOldFg);
+    SelectObject(hDC,
+                 hbOldBk);
+
+    DeleteObject(hpFg);
+}
+
+static VOID
+MonSelContextMenu(IN OUT PMONITORSELWND infoPtr,
+                  IN SHORT x,
+                  IN SHORT y)
+{
+    MONSL_MONNMBUTTONCLICKED nm;
+    INT Index;
+
+    if (!infoPtr->HasFocus)
+        SetFocus(infoPtr->hSelf);
+
+    nm.pt.x = x;
+    nm.pt.y = y;
+
+    Index = MonSelHitTest(infoPtr,
+                          &nm.pt);
+
+    MonSelNotifyMonitor(infoPtr,
+                        MSLN_RBUTTONUP,
+                        Index,
+                        (PMONSL_MONNMHDR)&nm);
+
+    /* Send a WM_CONTEXTMENU notification */
+    MapWindowPoints(infoPtr->hSelf,
+                    NULL,
+                    &nm.pt,
+                    1);
+
+    SendMessage(infoPtr->hSelf,
+                WM_CONTEXTMENU,
+                (WPARAM)infoPtr->hSelf,
+                MAKELPARAM(nm.pt.x,
+                           nm.pt.y));
+}
+
+static VOID
+MonSelApplyCursorClipping(IN PMONITORSELWND infoPtr,
+                          IN BOOL bClip)
+{
+    RECT rc;
+
+    if (bClip)
+    {
+        rc.left = rc.top = 0;
+        rc.right = infoPtr->ClientSize.cx;
+        rc.bottom = infoPtr->ClientSize.cy;
+
+        if (MapWindowPoints(infoPtr->hSelf,
+                            NULL,
+                            (LPPOINT)&rc,
+                            2))
+        {
+            ClipCursor(&rc);
+        }
+    }
+    else
+    {
+        ClipCursor(NULL);
+    }
+}
+
+static VOID
+MonSelMoveDragRect(IN OUT PMONITORSELWND infoPtr,
+                   IN PPOINT ppt)
+{
+    RECT rcPrev, rcUpdate, *prc;
+    HRGN hRgnPrev;
+    HDC hDC;
+
+    if (infoPtr->CanDisplay)
+    {
+        hDC = GetDC(infoPtr->hSelf);
+        if (hDC != NULL)
+        {
+            if (infoPtr->ptDrag.x != ppt->x ||
+                infoPtr->ptDrag.y != ppt->y)
             {
-                /* NOTE: We need to switch the text color to the default, because
-                         DrawFocusRect draws a solid line if the text is white! */
+                infoPtr->ptDrag = *ppt;
 
-                crPrevText2 = SetTextColor(hDC,
-                                           crPrevText);
+                rcPrev = infoPtr->rcDragging;
 
-                DrawFocusRect(hDC,
-                              &rc);
+                /* Calculate updated dragging rectangle */
+                prc = &infoPtr->Monitors[infoPtr->DraggingMonitor].rc;
+                infoPtr->rcDragging.left = ppt->x - infoPtr->DraggingMargin.cx;
+                infoPtr->rcDragging.top = ppt->y - infoPtr->DraggingMargin.cy;
+                infoPtr->rcDragging.right = infoPtr->rcDragging.left + (prc->right - prc->left);
+                infoPtr->rcDragging.bottom = infoPtr->rcDragging.top + (prc->bottom - prc->top);
 
-                SetTextColor(hDC,
-                             crPrevText2);
+                hRgnPrev = CreateRectRgn(rcPrev.left,
+                                         rcPrev.top,
+                                         rcPrev.right,
+                                         rcPrev.bottom);
+
+                if (hRgnPrev != NULL)
+                {
+                    if (!ScrollDC(hDC,
+                                  infoPtr->rcDragging.left - rcPrev.left,
+                                  infoPtr->rcDragging.top - rcPrev.top,
+                                  &rcPrev,
+                                  NULL,
+                                  hRgnPrev,
+                                  &rcUpdate) ||
+                        !InvalidateRgn(infoPtr->hSelf,
+                                       hRgnPrev,
+                                       TRUE))
+                    {
+                        DeleteObject(hRgnPrev);
+                        goto InvRects;
+                    }
+
+                    DeleteObject(hRgnPrev);
+                }
+                else
+                {
+InvRects:
+                    InvalidateRect(infoPtr->hSelf,
+                                   &rcPrev,
+                                   TRUE);
+                    InvalidateRect(infoPtr->hSelf,
+                                   &infoPtr->rcDragging,
+                                   TRUE);
+                }
             }
+
+            ReleaseDC(infoPtr->hSelf,
+                      hDC);
         }
+    }
+}
 
-        InflateRect(&rc,
-                    -infoPtr->SelectionFrame.cx,
-                    -infoPtr->SelectionFrame.cy);
+static VOID
+MonSelCancelDragging(IN OUT PMONITORSELWND infoPtr)
+{
+    DWORD Index;
 
-        Rectangle(hDC,
-                  rc.left,
-                  rc.top,
-                  rc.right,
-                  rc.bottom);
+    if (infoPtr->DraggingMonitor >= 0)
+    {
+        MonSelMoveDragRect(infoPtr,
+                           &infoPtr->ptDragBegin);
 
-        InflateRect(&rc,
-                    -1,
-                    -1);
+        Index = (DWORD)infoPtr->DraggingMonitor;
+        infoPtr->DraggingMonitor = -1;
 
-        hFont = MonSelGetMonitorFont(infoPtr,
-                                     hDC,
-                                     Index);
-        if (hFont != NULL)
+        if (infoPtr->CanDisplay)
         {
-            hPrevFont = SelectObject(hDC,
-                                     hFont);
+            /* Repaint the area where the monitor was last dragged */
+            MonSelRepaintMonitor(infoPtr,
+                                 Index);
 
-            DrawText(hDC,
-                     infoPtr->Monitors[Index].szCaption,
-                     -1,
-                     &rc,
-                     DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
+            infoPtr->IsDraggingMonitor = FALSE;
 
-            SelectObject(hDC,
-                         hPrevFont);
+            /* Repaint the area where the monitor is located */
+            MonSelRepaintMonitor(infoPtr,
+                                 Index);
         }
+        else
+            infoPtr->IsDraggingMonitor = FALSE;
+
+        ReleaseCapture();
+
+        MonSelApplyCursorClipping(infoPtr,
+                                  FALSE);
+    }
+}
+
+static VOID
+MonSelInitDragging(IN OUT PMONITORSELWND infoPtr,
+                   IN DWORD Index,
+                   IN PPOINT ppt)
+{
+    POINT pt;
+
+    MonSelCancelDragging(infoPtr);
+    infoPtr->IsDraggingMonitor = FALSE;
+
+    MonSelScreenToPt(infoPtr,
+                     ppt,
+                     &pt);
 
-        if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
+    infoPtr->ptDrag = infoPtr->ptDragBegin = pt;
+    infoPtr->DraggingMonitor = (INT)Index;
+
+    infoPtr->DraggingMargin.cx = ppt->x - infoPtr->Monitors[Index].rc.left;
+    infoPtr->DraggingMargin.cy = ppt->y - infoPtr->Monitors[Index].rc.top;
+    infoPtr->rcDragging = infoPtr->Monitors[Index].rc;
+
+    MonSelApplyCursorClipping(infoPtr,
+                              TRUE);
+}
+
+static VOID
+MonSelDrag(IN OUT PMONITORSELWND infoPtr,
+           IN PPOINT ppt)
+{
+    SIZE szDrag;
+    POINT pt;
+    RECT rcDrag;
+
+    if (infoPtr->DraggingMonitor >= 0)
+    {
+        MonSelScreenToPt(infoPtr,
+                         ppt,
+                         &pt);
+
+        if (!infoPtr->IsDraggingMonitor)
         {
-            InflateRect(&rc,
-                        1,
-                        1);
+            szDrag.cx = GetSystemMetrics(SM_CXDRAG);
+            szDrag.cy = GetSystemMetrics(SM_CYDRAG);
 
-            MonSelDrawDisabledRect(infoPtr,
-                                   hDC,
-                                   &rc);
+            rcDrag.left = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.left + infoPtr->DraggingMargin.cx - (szDrag.cx / 2);
+            rcDrag.top = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.top + infoPtr->DraggingMargin.cy - (szDrag.cy / 2);
+            rcDrag.right = rcDrag.left + szDrag.cx;
+            rcDrag.bottom = rcDrag.top + szDrag.cy;
+
+            if (!PtInRect(&rcDrag,
+                          pt))
+            {
+                /* The user started moving around the mouse: Begin dragging */
+                infoPtr->IsDraggingMonitor = TRUE;
+                MonSelMoveDragRect(infoPtr,
+                                   &pt);
+            }
+        }
+        else
+        {
+            MonSelMoveDragRect(infoPtr,
+                               &pt);
         }
     }
-
-    SetTextColor(hDC,
-                 crPrevText);
-    SetBkMode(hDC,
-              iPrevBkMode);
-    SelectObject(hDC,
-                 hpOldFg);
-    SelectObject(hDC,
-                 hbOldBk);
 }
 
 static LRESULT CALLBACK
@@ -873,13 +1217,45 @@ MonitorSelWndProc(IN HWND hwnd,
             break;
         }
 
+        case WM_MOUSEMOVE:
+        {
+            POINT pt;
+
+            if (!(wParam & MK_LBUTTON))
+            {
+                MonSelCancelDragging(infoPtr);
+                break;
+            }
+
+            if (infoPtr->LeftBtnDown)
+            {
+                pt.x = (LONG)LOWORD(lParam);
+                pt.y = (LONG)HIWORD(lParam);
+
+                MonSelDrag(infoPtr,
+                           &pt);
+            }
+
+            break;
+        }
+
+        case WM_RBUTTONDOWN:
+        {
+            if (!(infoPtr->ControlExStyle & MSLM_EX_SELECTONRIGHTCLICK))
+                break;
+
+            /* fall through */
+        }
+
         case WM_LBUTTONDBLCLK:
         case WM_LBUTTONDOWN:
-        case WM_RBUTTONDOWN:
         {
             INT Index;
             POINT pt;
 
+            if (!infoPtr->HasFocus)
+                SetFocus(infoPtr->hSelf);
+
             pt.x = (LONG)LOWORD(lParam);
             pt.y = (LONG)HIWORD(lParam);
 
@@ -892,6 +1268,14 @@ MonitorSelWndProc(IN HWND hwnd,
                                        TRUE);
             }
 
+            if (Index >= 0 && (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK))
+            {
+                infoPtr->LeftBtnDown = TRUE;
+                MonSelInitDragging(infoPtr,
+                                   (DWORD)Index,
+                                   &pt);
+            }
+
             /* fall through */
         }
 
@@ -902,6 +1286,21 @@ MonitorSelWndProc(IN HWND hwnd,
             break;
         }
 
+        case WM_RBUTTONUP:
+        {
+            MonSelContextMenu(infoPtr,
+                              (SHORT)LOWORD(lParam),
+                              (SHORT)HIWORD(lParam));
+            break;
+        }
+
+        case WM_LBUTTONUP:
+        {
+            MonSelCancelDragging(infoPtr);
+            infoPtr->LeftBtnDown = FALSE;
+            break;
+        }
+
         case WM_GETDLGCODE:
         {
             INT virtKey;
@@ -923,6 +1322,9 @@ MonitorSelWndProc(IN HWND hwnd,
             }
 
             Ret |= DLGC_WANTARROWS;
+
+            if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY)
+                Ret |= DLGC_WANTCHARS;
             break;
         }
 
@@ -936,13 +1338,21 @@ MonitorSelWndProc(IN HWND hwnd,
         case WM_KILLFOCUS:
         {
             infoPtr->HasFocus = FALSE;
+            MonSelCancelDragging(infoPtr);
             MonSelRepaintSelected(infoPtr);
             break;
         }
 
         case WM_UPDATEUISTATE:
         {
-            DWORD OldUIState = infoPtr->UIState;
+            DWORD OldUIState;
+
+            Ret = DefWindowProcW(hwnd,
+                                 uMsg,
+                                 wParam,
+                                 lParam);
+
+            OldUIState = infoPtr->UIState;
             switch (LOWORD(wParam))
             {
                 case UIS_SET:
@@ -1009,6 +1419,78 @@ MonitorSelWndProc(IN HWND hwnd,
             break;
         }
 
+        case WM_KEYDOWN:
+        {
+            INT Index;
+
+            if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYARROWKEY)
+            {
+                switch (wParam)
+                {
+                    case VK_UP:
+                    case VK_LEFT:
+                    {
+                        Index = infoPtr->SelectedMonitor;
+
+                        if (infoPtr->MonitorsCount != 0)
+                        {
+                            if (Index < 0)
+                                Index = 0;
+                            else if (Index > 0)
+                                Index--;
+                        }
+
+                        if (Index >= 0)
+                        {
+                            MonSelSetCurSelMonitor(infoPtr,
+                                                   Index,
+                                                   TRUE);
+                        }
+                        break;
+                    }
+
+                    case VK_DOWN:
+                    case VK_RIGHT:
+                    {
+                        Index = infoPtr->SelectedMonitor;
+
+                        if (infoPtr->MonitorsCount != 0)
+                        {
+                            if (Index < 0)
+                                Index = (INT)infoPtr->MonitorsCount - 1;
+                            else if (Index < (INT)infoPtr->MonitorsCount - 1)
+                                Index++;
+                        }
+
+                        if (infoPtr->SelectedMonitor < infoPtr->MonitorsCount)
+                        {
+                            MonSelSetCurSelMonitor(infoPtr,
+                                                   Index,
+                                                   TRUE);
+                        }
+                        break;
+                    }
+                }
+            }
+            break;
+        }
+
+        case WM_CHAR:
+        {
+            if ((infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY) &&
+                wParam >= '1' && wParam <= '9')
+            {
+                INT Index = (INT)(wParam - '1');
+                if (Index < (INT)infoPtr->MonitorsCount)
+                {
+                    MonSelSetCurSelMonitor(infoPtr,
+                                           Index,
+                                           TRUE);
+                }
+            }
+            break;
+        }
+
         case MSLM_SETMONITORSINFO:
         {
             Ret = MonSelSetMonitorsInfo(infoPtr,
@@ -1081,6 +1563,14 @@ MonitorSelWndProc(IN HWND hwnd,
             break;
         }
 
+        case MSLM_GETMONITORRECT:
+        {
+            Ret = (LRESULT)MonSelGetMonitorRect(infoPtr,
+                                                (INT)wParam,
+                                                (PRECT)lParam);
+            break;
+        }
+
         case WM_CREATE:
         {
             infoPtr = (PMONITORSELWND) HeapAlloc(GetProcessHeap(),