web-dev-qa-db-ja.com

ウィンドウを上に置き、WinFormsでフォーカスを盗む

これは通常の状況では完全に悪い習慣であることは承知していますが、これは、バーコードスキャナーから入力を受け取る必要のある(キーボードをエミュレートする)テストアプリのためだけのものです。問題は、スキャン中にいくつかのスクリプトを起動する必要があることです。そのため、スクリプトをクリックして実行した直後にウィンドウにフォーカスを戻す必要があります。私はActivate()、BringToFront()、Focus()だけでなく、SetForegroundWindow()、Setcapture()、SetActiveWindow()のようないくつかのWin32呼び出しを使用してみました...タスクバーの項目が点滅し始めて、フォーカスがあることを通知しますwantsがフォーカスを持っていますが、何かがそれを止めています。ところで、私はこれをXP SP2で実行し、.NET 2.0を使用しています。

これは可能ですか?

編集:明確にするために、私はエクスプローラでスクリプトをダブルクリックしてスクリプトを実行しています。したがって、エクスプローラーからテストアプリにフォーカスを戻すために必要です。

23
Adam Haile

視認性

ウィンドウを「最上位」ウィンドウにします。これは、タスクマネージャが他のウィンドウの上に表示される方法です。これはFormのプロパティであり、値をtrue

最上位の設定で「アクティブウィンドウ」の動作をオーバーライドする必要はありません。

フォーカス

私は同様の質問をしました 以前はStackOverflowにありました と答えると、問題が解決します。アプリケーションに低レベルの入力フックを使用させ、スキャナーからのキーコードの通知を受け取ることができます。これにより、アプリケーションにフォーカスがない場合でも、アプリケーションは常にこれらのキーを取得します。

ソリューションを拡張してキーコードを押しつぶし、「フォーカスされている」アプリケーション(メモ帳など)に送信されないようにする必要があります。

Windows 2000以降、アプリケーションがユーザーの直接の介入なしにフォーカスを取得する公式のメカニズムはありません。 RawInputDevicesフックを介して入力ストリームを覗くことが、唯一の賢明な方法です。

多くの記事が役立つ場合があります(C#の実装)

12
Ray Hayes

私はしばらくの間、同様の問題に苦労しました。多くの実験と推測の後、これが私がそれを解決した方法です:

// Get the window to the front.
this.TopMost = true;
this.TopMost = false;

// 'Steal' the focus.
this.Activate();
42
TallGuy

私は同様の問題を抱えており、トリックを行うには次のことがわかりました。 ここ からC#に適合

        // force window to have focus
        uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
        uint appThread = GetCurrentThreadId();
        const uint SW_SHOW = 5;
        if (foreThread != appThread)
        {
            AttachThreadInput(foreThread, appThread, true);
            BringWindowToTop(form.Handle);
            ShowWindow(form.Handle, SW_SHOW);
            AttachThreadInput(foreThread, appThread, false);
        }
        else
        {
            BringWindowToTop(form.Handle);
            ShowWindow(form.Handle, SW_SHOW);
        }
        form.Activate();

EDIT:以下は、C#に必要なPInvoke定義です。

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

// When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();

/// <summary>The GetForegroundWindow function returns a handle to the foreground window.</summary>
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);

[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(HandleRef hWnd);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
12
Ken

私がこの問題に取り組んだ方法は、フォームがTopMostであり、常にフォーカスがあることを確認することだけを目的とした別のスレッドを生成することでした。このコードにより、実行中は他のすべてのアプリケーションが使用できなくなります。これが、特定のアプリケーションに必要なことです。 keepFocusにSleepを追加するか、他のイベントでトリガーすることができます。

using System.Threading;          // be sure to include the System.Threading namespace

    //Delegates for safe multi-threading.
    delegate void DelegateGetFocus();
    private DelegateGetFocus m_getFocus;

    //Constructor.
    myForm()
    {
        m_getFocus = new DelegateGetFocus(this.getFocus);   // initialise getFocus
        InitializeComponent();
        spawnThread(keepFocus);                             // call spawnThread method
    }

    //Spawns a new Thread.
    private void spawnThread(ThreadStart ts)
    {
        try
        {
            Thread newThread = new Thread(ts);
            newThread.IsBackground = true;
            newThread.Start();
        }
        catch(Exception e)
        {
            MessageBox.Show(e.Message, "Exception!", MessageBoxButtons.OK, 
                MessageBoxIcon.Error);
        }
    }

    //Continuously call getFocus.
    private void keepFocus()
    {
        while(true)
        {
            getFocus();
        }
    }

    //Keeps Form on top and gives focus.
    private void getFocus()
    {
        //If we need to invoke this call from another thread.
        if (this.InvokeRequired)
        {
            try
            {
                this.Invoke(m_getFocus, new object[] { });
            }
            catch (System.ObjectDisposedException e)
            {
                // Window was destroyed. No problem but terminate application.
                Application.Exit();
            }
        }
        //Otherwise, we're safe.
        else
        {
            this.TopMost = true;
            this.Activate();
        }
    }       
}
7
mxgg250

特定の入力に注目するか、.TopMostプロパティをtrueに設定してみてください(その後、設定を解除します)。

しかし、私はあなたの問題はこれらのメソッドはすべてWindowsイベントキューにメッセージを配置するだけであり、プログラムは既存のすべてのイベントが処理を完了するのを待たないと、そのイベントを処理してアプリにフォーカスしないと思われます。

0
Joel Coehoorn