윈도우 포커스 및 최상위로 올리기/활성화
원래 SetForegroundWindow() 함수를 쓰면
윈도우가 앞으로 나오던 것이 win98 부터 처리 방식이 바뀌어서
사용자 입력 포커스를 os 에서 관리하기 시작하면서
해당 api 가 원래대로 작동을 하지 않게 되었습니다.
MSDN 에 보면 다음과 같은 경우에만
앞으로 기어나온다고 설명되어 있습니다.
Quote:
Windows 98/Me: The system restricts which processes can set the
foreground window. A process can set the foreground
window only if one of the following conditions is true:
- The process is the foreground process.
- The process was started by the foreground process.
- The process received the last input event.
- There is no foreground process.
- The foreground process is being debugged.
- The foreground is not locked (see LockSetForegroundWindow).
- The foreground lock time-out has expired
(see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
- Windows 2000/XP: No menus are active.
이렇게 바꾼 이유가.....
사용자가 열심히 타이핑을 하거나 하고 있는데, 다른 윈도우가 포커스를 가로챌 경우
여러가지 문제가 발생할 수 있기 때문이죠.
어찌되었건 강제로 포커스를 가져오고 싶어서
SetFocus() SetForegroundWindow() 등을 써도
안될 경우 다음 방법을 써보시기 바랍니다.
//////2번째 설명 소스는 같다//////////////
윈도우를 최상위로 가져오는 코드를 만드실때는
SetWindowPos 함수를 사용하시는 것보다
BringWindowToTop 함수를 사용하는것이 좋습니다.
하지만 단순히 BringWindowToTop 함수를
호출하는것만으로는 윈도우가 앞으로 나오지 않습니다.
BringWindowToTop 함수를 사용하시기 위해서는
현재 활성화된 윈도우의 스레드에 현재 스레드를
Attach 시켜놓고 사용하셔야 합니다.
따라서 정상적으로 BringWindowToTop 함수를 호출하려면
아래와 같이 코드를 구성해야합니다.
if(::GetForegroundWindow() != this->m_hWnd){
HWND h_active_wnd = ::GetForegroundWindow();
if(h_active_wnd != NULL){
DWORD thread_id = GetWindowThreadProcessId(h_active_wnd, NULL);
DWORD current_thread_id = GetCurrentThreadId();
if(current_thread_id != thread_id){
if(AttachThreadInput(current_thread_id, thread_id, TRUE)){
BringWindowToTop();
AttachThreadInput(current_thread_id, thread_id, FALSE);
}
}
}
}
물론, SetWindowPos 함수를 이용해서
아래와 같이 해도 윈도우를 앞으로 가져올수는 있습니다.
하지만 아래와 같은 방법은 윈도우는 앞에 있어도
해당 윈도우가 활성화되지 않은 상태로 존재하게 됩니다.
// 최상위 윈도우로 설정하여 강제로 앞으로 나오게 한다.
::SetWindowPos(m_pMainWnd->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
// 최상위 윈도우 속성을 제거한다. 하지만 윈도우는 다른 윈도우보다 앞에 존재한다.
::SetWindowPos(m_pMainWnd->m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
결론적으로 BringWindowToTop 함수는
윈도우를 앞으로 가져오면서 활성화를 시킬때 사용하고
::SetWindowPos 함수를 이용하는 방법은 윈도우는 앞으로 가져오지만
활성화는 시키지 않을때 사용하면 적절할것 같습니다.
일반적으로 포커스를 가진 윈도우의 핸들을 가져오거나 지정하는데
사용되는 함수는 GetFocus(), SetFocus()이다.
하지만, 이들 함수들은 모든 윈도우의 포커스를 가져오는 것이 아니고,
현재 윈도우 내의 포커스를 가진 핸들을 가져오는 함수이다.
쉽게 말하자면, 자신의 윈도우에서 포커스를 가진
특정 윈도우(버튼, 에디트 박스 등)의 핸들을 가져올 때 사용하는 것은
문제가 없을 것이지만, 다른 윈도우를 대상으로 이 함수를 쓰게 된다면,
우리가 원하는 핸들 대신 NULL 값을 가져오게 될 것이다.
NULL 값을 가져온 경우 포커스를 가진 윈도우가 다른 스레드 메시지 큐에 있기 때문이다.
하지만, 이에 대한 해결 방법이 있다.
먼저 GetForegroundWindow() 를 사용하여 실제 포커스를 가진
윈도우의 최상위 부모 핸들을 얻는다.
그리고 이 윈도우의 스레드를 구해(GetWindowThreadProcessId())
현재 스레드에 연결(AttachThreadInput())하면 된다.
이 후에 GetFocus()를 호출하게 되면, NULL 값이 아닌 포커스를 가진
다른 윈도우의 핸들을 가져오는 것을 확인 할 수 있다.
MDDN에서는 GetFocus에 대해 이렇게 설명하고 있다.
The GetFocus function retrieves the handle to the window that
has the keyboard focus, if the window is attached to the calling thread's message queue.
Syntax
HWND GetFocus(VOID);
Return Value
The return value is the handle to the window
with the keyboard focus. If the calling thread's message
queuedoes not have an associated window with
the keyboard focus, the return value is NULL.
Remarks
GetFocus returns the window with the keyboard focus
for the current thread's message queue. If GetFocusreturns NULL,
another thread's queue may be attached to a window that has the keyboard focus.
Use the GetForegroundWindow function to retrieve
the handle to the window with which the user is currently working.
You can associate your thread's message queue with
the windows owned by another thread by using the AttachThreadInput function.
Windows 98/Me and Windows NT 4.0 SP3 and later:To get the window
with the keyboard focus on the foreground queue or
the queue of another thread, use the GetGUIThreadInfo function.
간단하게 예를 들어보면, 아래와 같은 방법으로
다른 윈도우의 포커스를 가져올 수 있다.
HWND hWnd = GetForegroundWindow();
DWORD fromId = GetCurrentThreadId();
DWORD toId = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(fromId, toId, TRUE);
HWND focus = GetFocus();
'Delphi Tip > +Tip' 카테고리의 다른 글
안드로이드에서 MessagDlg 사용방법(주의 점) (0) | 2022.03.11 |
---|---|
왕초보를 위한 아주 기본적인 Tips (0) | 2022.03.07 |
외부 프로그램 실행하고 대기하기 (0) | 2022.02.22 |
시스템 대기모드/화면 보호기/모니터 끄기 이벤트 감지하기 (0) | 2022.02.17 |
문자열에서 특정 문자까지 자르기 (0) | 2022.02.16 |
댓글