アプリケーションがフォーカスを奪うのを防ぐ


191

アプリケーションがアクティブウィンドウからフォーカスを奪うのを防ぐ解決策はありますか?

これは特に、アプリケーションを起動しているときに他の操作に切り替えると、新しいアプリケーションがテキストの半文を受信し始めるときに迷惑です。


9
私はすべてのウィンドウには、スーパーユーザのためだと思う私の場合はWindows 7の@Ivoが、バージョンは、関連するだろう
svandragt

3
モデレーターはこの質問を結合しました:superuser.com/questions/199821/…現在の質問。これは間違っています。現在の質問に対する答えはWindows 7には適用されないため、マージしないでください。これまでのところ、Windows 7でこの問題の解決策を見つけることができませんでした
Alex Angelico

17
これは、私がこれまで使用したすべてのGUIを備えた私のナンバーワンのペットの1つです。入力中のせいで、いくつかのブリーピングダイアログボックスがフォーカスを奪い、キーストロークの半分が他の場所に移動します。あなたは、ウィンドウシステムの実装者が数十年前にこれを見つけたと思うでしょう。ウィンドウにアクティビティがある場合は、新しいウィンドウの公開を遅らせます。たとえば、現在フォーカスされているウィンドウで最後にボタンをクリックまたはキーストロークを行ってから3〜4秒経過するまで、GUIにポップアップを表示しません。ど!
カズ

24
This is especially annoying when I'm starting an application, switch to do something else and the new application starts receiving half a sentence of text.ダイアログがポップアップし、あなたが意図せずも、あなたが押すように起こったため、メッセージを見ることなく、それを却下するときには、より迷惑なんだSpaceEnterの文章を入力しながら。
Synetech 14年

3
これは実際に迷惑以上の方法です。セキュリティリスクだと思います。パスワードを入力して入力を取得している最中にアプリケーションがポップアップするのを止めるものは何もありません。
クリス・ピーコック

回答:


51

これは、Windows内部の広範な操作なしでは不可能であり、それを乗り越える必要があります。

オペレーティングシステムが別のアクションを許可する前に、あるアクションを実行することが本当に重要である場合、毎日のコンピューターの使用には瞬間があります。そのためには、特定のウィンドウにフォーカスをロックする必要があります。Windowsでは、この動作の制御は、主に使用する個々のプログラムの開発者に委ねられています。

このトピックに関して、すべての開発者が適切な決定を下すわけではありません。

私はこれが非常にイライラし、迷惑であることを知っていますが、ケーキを持って食べることもできません。日常生活の中で、特定のUI要素にフォーカスを移動したり、フォーカスをその上に固定したままにするように要求するアプリケーションにまったく問題がない場合が多分あります。しかし、ほとんどのアプリケーションは、現在誰がリードであるかを決定することになると、いくぶん平等であり、システムが完全になることはありません。

しばらく前、私はこの問題を完全に解決するために広範な調査を行いました(そして失敗しました)。私の研究の結果は、迷惑プロジェクトのページで見つけることができます

このプロジェクトには、次の呼び出しによって繰り返しフォーカスを取得しようとするアプリケーションも含まれています。

switch( message ) {
  case WM_TIMER:
    if( hWnd != NULL ) {
      // Start off easy
      // SetForegroundWindow will not move the window to the foreground,
      // but it will invoke FlashWindow internally and, thus, show the
      // taskbar.
      SetForegroundWindow( hWnd );

      // Our application is awesome! It must have your focus!
      SetActiveWindow( hWnd );

      // Flash that button!
      FlashWindow( hWnd, TRUE );
    }
    break;

このスニペットからわかるように、私の研究は、ユーザーインターフェイスの動作の他の側面にも焦点を当てています。

これを解決しようとした方法は、すべての新しいプロセスにDLLをロードし、別のウィンドウをアクティブにするAPI呼び出しをフックすることでした。
最後の部分は簡単です。素晴らしいAPIがライブラリをフックしているおかげです。私は非常に素晴らしいmhookライブラリを使用しました:

#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"

typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) ( 
  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,     
  __inout    PVOID SystemInformation, 
  __in       ULONG SystemInformationLength, 
  __out_opt  PULONG ReturnLength    
);

// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow   = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindow" );

PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindowEx" );

PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "SetForegroundWindow" );

// Hooks
BOOL WINAPI
HookedFlashWindow(
  __in  HWND hWnd,
  __in  BOOL bInvert
  ) {
  return 0;
}

BOOL WINAPI 
HookedFlashWindowEx(
  __in  PFLASHWINFO pfwi
  ) {
  return 0;
}

BOOL WINAPI 
HookedSetForegroundWindow(
  __in  HWND hWnd
  ) {
  // Pretend window was brought to foreground
  return 1;
}


BOOL APIENTRY 
DllMain( 
  HMODULE hModule,
  DWORD   ul_reason_for_call,
  LPVOID  lpReserved
  ) {
  switch( ul_reason_for_call ) {
    case DLL_PROCESS_ATTACH:
      Mhook_SetHook( (PVOID*)&OriginalFlashWindow,         HookedFlashWindow );
      Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx,       HookedFlashWindowEx );
      Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
      break;

    case DLL_PROCESS_DETACH:
      Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
      Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
      Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
      break;
  }
  return TRUE;
}

当時の私のテストから、これはうまくいきました。DLLをすべての新しいプロセスにロードする部分を除きます。想像するかもしれませんが、それは軽すぎることではありません。私は当時AppInit_DLLsアプローチを使用していました(これは単に十分ではありません)。

基本的に、これはうまく機能します。しかし、DLLを新しいプロセスに適切に挿入するものを作成する時間はありませんでした。そして、これに費やされた時間は、フォーカスを盗むことによって私が引き起こす不快感を大きく覆い隠します。

DLLインジェクションの問題に加えて、Google Codeでの実装ではカバーしていなかったフォーカスを盗む方法もあります。同僚が実際にいくつかの追加調査を行い、その方法を取り上げました。問題はSOで議論されました:https : //stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus


このソリューションをJavaに移植できると思いますか?私は検索して質問をしてきましたが、何も見つかりませんでした。たぶん私はJavaでフックライブラリ自体をインポートできjneますか?
トマーシュZato

@TomášZato:わかりません。私は自分でこのコードを積極的に使用していません。
デアホッホスタプラー

私は少なくともC ++としてコンパイルしようとしています(そしてコンパイルされたDLLをJavaから挿入/削除します)。しかし、それもうまくいきません。ここでコメントで説明したくありませんが、実際に機能させるために私を助けていただければ、とても優雅です!私はここにそうすることをどのようにコメントを投稿します動作させることを得れば、私は、チャットルームを作成しました:chat.stackexchange.com/rooms/21637/...
トマーシュZato

23

Windows 7では、ForegroundLockTimeoutレジストリエントリはチェックされなくなりました。ProcessMonitorでこれを確認できます。実際、Windows 7では、フォアグラウンドウィンドウを変更できません。詳細を読んでください。Windows2000からも存在しています。

しかし、ドキュメンテーションはひどく、お互いを追いかけ、それを回避する方法を見つけます

そのため、、SetForegroundWindowまたは類似のAPI関数でバグが発生しています...

これを本当に適切に行う唯一の方法はLockSetForegroundWindow、定期的にを呼び出す小さなアプリケーションを作成し、バグのあるAPI関数への呼び出しを事実上無効にすることです。

それは十分ではない場合は(別のバギーAPI呼び出し?)あなたはさらに行くと、いくつか行うことができますAPIの監視を何が起こっているかを確認するために、そしてあなたは、単に、すべてのプロセスのAPIコールフックあなたは取り除くことができた後に任意の呼び出すこと混乱を前景。しかし、皮肉なことに、これはマイクロソフトによって推奨されていません...


3
誰かがWindows 7でこれの再現可能なユースケースを持っていますか?人々がむしろ反対の経験をすることを考えると(たとえば、私はしばしば現在のウィンドウの後ろに隠れることを要求することがわかります)、Windows 7でこれが起こるのをまだ見ていませんが、アプリケーションを書くのはかなり面倒ですが、試して。さらに、MicrosoftはこれをWindows 7ではもう起こらないと述べているように、キーボードのフォーカスを誤って切り替えることしかできないことを最高の人々が発見したため、このAPI呼び出しはそれを修正しますが、実際に動作するかどうかをテストする方法はわかりません。 。
タマラWijsman

1
インストーラー(InnoSetupに基づく)は、他のプロセスおよび可能な他の(隠された)セットアップを起動しますが、どのセットアップ作成者がベースにしているのかわかりません。
ダニエルベック

6
@TomWijsman:regeditを開き、見つからないランダムテキストを検索します。別のアプリに移動して、入力を開始します。検索が終了すると、regeditはフォーカスを奪います。
エンドリス

1
@endolith:ここではWindows 8 Replase Previewを使用して再現できません。どのOSを使用していますか?私の場合はそれだけで下部にあるアプリケーションを強調表示しますが、すべての...で私のブラウジングを中断していません
タマラWijsman

21
はい、Win7 Pro 64ビット。また、フォーカスを盗むことは昇格したプロセスではさらに悪くなります。なぜなら、押してはいけないときに<Enter>を押してしまい、誤ってシステムにホースを入れてしまうからです。何もする必要があり、これまでフォーカスを盗むことはできません。
エンドリス

18

TweakUIにはこれを行うオプションがあります。これは、疑わしいソフトウェア開発者がアプリに集中するために使用する通常のトリックのほとんどを防ぎます。

しかし、それは進行中の武器戦争なので、それがすべてのために働くかどうかわかりません。

更新EndangeredMassaによると、TweakUIはWindows 7では動作しません。


2
tweakuiはWindows 7と互換性がありますか?
フランクスター

@フランクスター。わからない、申し訳ありませんが、おそらくそうではないと思います。それをダウンロードして試してください。誰もが知っている場合は報告してください。
サイモンPスティーブンス

5
TweakUIが設定するレジストリ設定を使用しても、Win7では機能しません。
危険にさらさ

@EndangeredMassaどのレジストリキーがそれですか?
-n611x007

2
レジストリキーは、HKEY_CURRENT_USER \ Control Panel \ Desktop \ ForegroundLockTimeout(ミリ秒単位)です。そして、はい、Windows 7ではもう機能しません。
foo

14

「フォーカスを盗む」には2つの方法があるため、混乱が生じる可能性があると思います。(1)ウィンドウが前面に来る、(2)キーストロークを受け取るウィンドウ。

ここで言及されている問題は、おそらく2番目の問題です。ユーザーの要求や許可なしに、ウィンドウが自分自身をフォアグラウンドに持ってくることによってフォーカスを要求します。

ここでは、XPと7の間で議論を分けなければなりません。

Windows XP

XPには、アプリケーションがフォーカスを奪うのを防ぐためにXPをWindows 7と同じように動作させるレジストリハックがあります。

  1. regeditを使用して、次に移動しますHKEY_CURRENT_USER\Control Panel\Desktop
  2. をダブルクリックしてForegroundLockTimeout、その値を16進数でに設定します30d40
  3. [OK]を押して、regeditを終了します。
  4. PCを再起動して、変更を有効にします。

Windows 7

(以下の説明は、ほとんどXPにも当てはまります。)

Windowsがアプリケーションがフォーカスを奪い、機能し続けることを完全にブロックする方法はないことを理解してください。たとえば、ファイルのコピー中にウイルス対策が脅威の可能性を検出し、実行するアクションを求めるウィンドウをポップアップ表示したい場合、このウィンドウがブロックされていると、コピーが終了しない理由がわかりません。

Windows 7では、Windows自体の動作を変更できるのは1つだけです。MS-Windowsfocus-follows-mouseレジストリハックを使用して、カーソルの下のウィンドウにフォーカスまたはアクティベーションを常に行います。デスクトップ全体にアプリケーションがポップアップするのを防ぐために、遅延を追加できます。
この記事を参照してください:Windows 7-マウスホバーでウィンドウをアクティブにします-有効にします。

それ以外の場合、有罪プログラムを検出して無力化する必要があります:これが常にフォーカスを取得している同じアプリケーションである場合、このアプリケーションはフォーカスを取得するようにプログラムされており、コンピューターからの起動を無効にすることでこれを防ぐことができます、またはこの動作を回避するには、そのアプリケーションが提供する設定を使用してください。

VBコードに含まれているVBSスクリプトを使用して、誰がフォーカスを盗んでいるかを特定できます。これは、作者が犯人をプリンターソフトウェアの「コールホーム」アップデーターとして特定するために使用します。

他のすべてが失敗したときの必死の手段であり、もしあなたがこのひどくプログラムされたアプリケーションを特定したなら、それを最小化し、それが前にそれ自身をもたらさないことを望みます。より強力な形式の最小化は、Best Free Application Minimizerにリストされている無料製品のいずれかを使用することによるトレイへの 追加です。

必死の順序の最後のアイデアは、DesktopsDexpotなどの製品を使用して仮想的にデスクトップを破壊し、デフォルト以外のデスクトップで作業を行うことです。

[編集]

マイクロソフトがアーカイブギャラリーを廃止したため、上記のVBコードを以下に示します。

Declare Auto Function GetForegroundWindow Lib "user32.dll" () As Integer
Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Integer, ByRef procid As Integer) As UInteger

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.RichTextBox1.AppendText("Starting up at " & Now & vbCrLf)
    End Sub

    Private Sub GoingAway(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate, Me.LostFocus

        Dim hwnd As Integer = GetForegroundWindow()
        ' Note that process_id will be used as a ByRef argument
        ' and will be changed by GetWindowThreadProcessId
        Dim process_id As Integer = 1
        GetWindowThreadProcessId(hwnd, process_id)

        If (process_id <> 1) Then
            Dim appExePath As String = Process.GetProcessById(process_id).MainModule.FileName() 
            Me.RichTextBox1.AppendText("Lost focus at " & Now & " due to " & appExePath & vbCrLf)
        Else
            Me.RichTextBox1.AppendText("Lost focus due to unknown cause.")
        End If

    End Sub

48
「このウィンドウがブロックされていると、コピーが終了しない理由を理解できなくなります」それは事実ではありません。正しい動作は、点滅するタスクバーアイコン(またはバルーンポップアップまたはトースター通知など)でユーザーに通知することです。キーストロークをインターセプトするウィンドウでユーザーを中断するということは、ウイルス対策ソフトウェアに何らかのアクションをランダムに実行するように指示することを意味します。間違いなく物事を行うには良い方法ではありません。
エンドリス

1
「このウィンドウがブロックされていると、コピーが終了しない理由を理解できなくなります」それは事実ではありません。正しい動作は、点滅するタスクバーアイコンでユーザーに通知することです... ボタンまたは実行中のプログラムで何かをクリックすると、新しいモーダルダイアログが作成される(たとえば、ファイルを開く)ことがありましたが、ダイアログが作成される前に別のプログラムに切り替えます。その結果、ダイアログは非表示になり、他のプログラムに切り替えることができず、ダイアログを閉じることができません。タスクバーボタンもAlt-Tab機能しません。ダイアログを前面に強制するだけです。
Synetech

1
@Synetech:非フロントダイアログの唯一の解決策は、タスクを強制終了することです。Windowsのフォーカスアルゴリズムは本当にひどいです。
harrymc

2
@harrymc、アプリの1つを殺すことに頼る必要はありません。ウィンドウ操作プログラムを実行して(WinSpy ++はすばらしいトリックを実行します)、ウィンドウを前面に非表示にします。その後、スタックバックダイアログを閉じて、非表示ウィンドウを再表示します。便利ではありませんが、どちらかのプロセスを強制終了するよりはましです。
Synetech

1
@harrymc、そうでもない。アプリを殺して物を失うと、より多くの蒸気が発生します。それがモーダルダイアログ(親ウィンドウをロックし、タスクバーボタンを持たない)である場合、それはAlt+Tabリストに表示されず、私の経験では、モーダルダイアログが開いているAlt+Tab場合、特にダイアログがフォーカスを取得するために変更がなかった場合、常にモーダルダイアログが表示されるとは限りません。:-|
Synetech

2

Ghacksには可能な解決策があります。

アプリケーションによっては、ポップアップによってアクティブウィンドウのフォーカスを奪うアプリケーションが1日に数回発生します。これは、いくつかの理由で発生する可能性があります。たとえば、ファイルを抽出したり、転送が終了したりする場合です。これはほとんどの場合問題になりませんが、時々記事を書いているときもあります。それは、もう一度いくつかの単語を入力する必要があるだけでなく、集中力を失い、フォーカスを取り戻すためにクリックしなければならないことも意味します。

プロレビューのウェブサイトでは、これを防ぐ方法についてのヒントを持っています。フォーカスのスチールを防ぐ最も簡単な方法は、「アプリケーションがフォーカスをスチールしないようにする」と呼ばれる設定を持つTweak UIを使用することです。このオプションをオンにすると、他のアプリケーションが突然表示され、現在作業中のウィンドウのフォーカスが奪われることを防ぎます。

これは、アプリケーションが以前に最小化された場合にのみ機能します。フォーカスを盗む代わりに、Tweak UIの同じメニューで定義できる回数点滅します。Tweak UIを使用したくない場合は、Windowsレジストリの設定を変更できます。

レジストリキーHKEY_CURRENT_USER>コントロールパネル>デスクトップに移動し、ForegroundLockTimeout値を30d40(16進数)または200000(10進数)に変更します。キーForeGroundFlashCountは、ユーザーに警告するウィンドウのフラッシュの量を定義します。0は無制限を意味します。


20
これは、XP以降のOSでは機能しません。そのレジストリ値は既に設定されており(デフォルトでは、私は信じています)、とにかく動作しません。
危険にさらさ

1
私がWindows 7(64ビット)でフォーカススティーリング(最終的にアクティブになったとき、VS 2012)を経験していることと、上記のレジストリの提案はすでに適切に行われていることです。この回答の技術的な確認:superuser.com/a/403554/972
マイケルポールコニス14

2

Der Hochstaplerの答えに触発され、64ビットプロセスと32ビットプロセスの両方で動作し、Windows 7以降でのフォーカススチールを防ぐDLLインジェクターを作成することにしました:https : //blade.sk/stay-focused/

動作方法は、新しく作成されたウィンドウを監視し(を使用SetWinEventHook)、Der Hochstaplerのものと非常によく似たDLLをウィンドウのプロセスに挿入します(まだない場合)。DLLをアンロードし、終了時に元の機能を復元します。

私のテストでは、これまでのところ非常にうまく機能しています。ただし、問題は単にアプリを呼び出すよりも深くなるようですSetForegroundWindow。たとえば、新しいウィンドウが作成されると、自動的にフォアグラウンドになり、ユーザーが別のウィンドウに入力することも妨げられます。

フォーカスを盗む他の方法に対処するには、より多くのテストが必要であり、それが起こっているシナリオに関するフィードバックをお待ちしています。


0

別のプロセスからそのプロセスのメインウィンドウをプログラムでアクティブ化し、最大化し、フォーカスした後、新しくアクティブ化されたターゲットウィンドウの点滅をTaskBarが停止する方法を見つけました。まず、この操作を許可するかどうかには多くの制限があります。

「システムは、フォアグラウンドウィンドウを設定できるプロセスを制限します。プロセスは、次のいずれかの条件に該当する場合にのみフォアグラウンドウィンドウを設定できます。

  • プロセスはフォアグラウンドプロセスです。
  • プロセスは、フォアグラウンドプロセスによって開始されました。
  • プロセスは最後の入力イベントを受け取りました。
  • フォアグラウンドプロセスはありません。
  • フォアグラウンドプロセスがデバッグされています。
  • 前景はロックされていません(LockSetForegroundWindowを参照)。
  • フォアグラウンドロックタイムアウトの有効期限が切れました(SystemParametersInfoのSPI_GETFOREGROUNDLOCKTIMEOUTを参照)。
  • アクティブなメニューはありません。

https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-allowsetforegroundwindow

そのため、制御プロセスがフォアグラウンドにある場合、ターゲットプロセスのプロセスIDAllowSetForegroundWindowを呼び出すことにより、一時的別のプロセスがフォアグラウンドを完全に盗むことができます。その後、ターゲットプロセスは独自のウィンドウハンドルを使用してSetForegroundWindow自体を呼び出すことができ、動作します。

明らかに、これには2つのプロセス間の調整が必要ですが、機能します。すべてのExplorerクリック起動を既存のアプリインスタンスにリダイレクトするシングルインスタンスアプリを実装するためにこれを行う場合は、既にとにかく物事を調整するために(例えば)名前付きパイプを持っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.