2015-11-29 119 views
0

正如您從下面的代碼片段中看到的,我已經實現了一種通過其客戶區拖動Windows命令提示符的方法。使用ReadConsoleInput()拖動控制檯窗口

這段代碼的問題是,如果用戶遵循下列步驟:

  1. 無焦點控制檯窗口
  2. 焦點控制檯窗口通過點擊和拖動它(不釋放)
  3. 拖動窗口,以便光標逃離窗口區域(這可能意味着移動光標太快,或超出設置範圍(第二個顯示器),或通過任務欄/其他永遠在頂部的窗口)

控制檯窗口將停在光標後面,直到它再次移動到窗口內。

事實上,當控制檯窗口在步驟1已經處於對焦狀態時,這種情況不會發生,這對我來說真的很奇怪。我已經試過調試了這麼多個小時,現在我不能再做了。我會很感激這方面的幫助。

// Continuously read input 
while(ReadConsoleInput(hIn, &ir, 1, &nr)) 
{ 
    switch(ir.EventType) 
    { 
     // Left mouse button down that either focuses or unfocuses console window 
     case FOCUS_EVENT: 
      // Left mouse button down that focuses console window 
      if(ir.Event.FocusEvent.bSetFocus) 
      { 
       GetCursorPos(&firstPos); 
       ScreenToClient(hWnd, &firstPos); 
      } 
      break; 
     case MOUSE_EVENT: 
      // Mouse did something inside console window 
      switch(ir.Event.MouseEvent.dwButtonState) 
      { 
       // Left mouse button down or up 
       case FROM_LEFT_1ST_BUTTON_PRESSED: 
        // Left mouse down or up, no drag 
        if(!ir.Event.MouseEvent.dwEventFlags) 
        { 
         GetCursorPos(&firstPos); 
         ScreenToClient(hWnd, &firstPos); 
        } 
        // Left button down, and mouse move. -> drag 
        if(ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) 
        { 
         GetCursorPos(&currentRelativeToScreen); 

         // Calculate window position while dragging 
         // | 
         // v 
         if(currentRelativeToScreen.x - firstPos.x > scrnSz.right - ca.right) 
          wndPos.X = scrnSz.right - ca.right; 
         else if(currentRelativeToScreen.x - firstPos.x < 0) 
          wndPos.X = 0; 
         else 
          wndPos.X = currentRelativeToScreen.x - firstPos.x; 

         if(currentRelativeToScreen.y - firstPos.y > scrnSz.bottom - ca.bottom) 
          wndPos.Y = scrnSz.bottom - ca.bottom; 
         else if(currentRelativeToScreen.y - firstPos.y < 0) 
          wndPos.Y = 0; 
         else 
          wndPos.Y = currentRelativeToScreen.y - firstPos.y; 
         // End window position calculations 

         SetWindowPos(hWnd, 0, wndPos.X, wndPos.Y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); 
        } 
        break; 
       default: 
        break; 
      } 
      break; 
     default: 
      break; 
    } 

回答

1

拖動窗口,使光標逃逸窗口區域[...]控制檯窗口將停止光標以下,直到它的移動是在窗口內試。

這是預期的行爲,如在https://msdn.microsoft.com/en-us/library/windows/desktop/ms684239.aspx記錄(着重添加)。

無論何時用戶移動鼠標或按下或釋放其中一個鼠標按鈕,都會生成鼠標事件。 僅當控制檯組具有鍵盤焦點時,纔將鼠標事件放置在控制檯的輸入緩衝區中並且光標處於控制檯窗口邊框內


[編輯]回答這個後續評論。

這個當控制檯窗口已經聚焦在步驟1

雖然沒有從官方文檔顯然不會發生,點擊後控制檯窗口出現捕獲鼠標(並由此跟蹤它甚至在移到控制檯窗口之外)只有如果在點擊時它已經有焦點了。對於焦點不清的控制檯窗口,第一次單擊會將焦點(無需全局捕獲鼠標,因此只在光標位於其客戶區域內時纔會收到MOUSE_MOVE通知),而第二次單擊則進入獨佔捕捉模式(並全部接收MOUSE_MOVE通知與光標位置無關)。

這可以通過設置爲快速編輯模式的標準控制檯窗口進行驗證。如果窗口具有輸入焦點,則即使鼠標移動到窗口之外,單擊並拖動選擇控制檯中的文本。但是,如果窗口沒有焦點。第一次點擊只是爲它提供焦點,但不會進入任何捕捉模式,拖動也不會選擇任何文本。

對鼠標移動
+0

你怎麼又解釋說,如果窗口有焦點的整個時間的鼠標事件產生,而光標仍在窗口邊界之外?此外,即使這是預期的行爲(我懷疑,從UX的角度來看,加上其他窗口的行爲並沒有這種方式),我仍然有興趣提供一種方法來規避這種行爲。 – user4780006

+0

我編輯了我的答案來覆蓋那個部分。不知道有一種解決方法,因爲控制檯窗口本身是相當特殊的。 – dxiv

+0

很好的編輯,很好的解釋。但我仍然在尋找(至少有點)理智的方式......我猜即使在第一次(聚焦)點擊時,模擬全局捕獲鼠標移動的命令提示符。我假設這會以某種方式手動跟蹤鼠標。 – user4780006

0

做:

if(button==leftButton){ 
ReleaseCapture(); 
SenMessage(hWnd,WM_NCLBUTTON_DOWN,HTCAPTION,lParam); 
}