1

我想使用以下代码在某个时间访问键盘的状态。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Windows.Input;

namespace some.any
{

    public class ANY_CLASS
    {
    [STAThread] //seems to do nothing here
    public static short ThisIsCalledByAnExternalProgram()
    {
        try
        {
            if (Keyboard.IsKeyDown(Key.LeftAlt))
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
        catch (Exception e)
        {
                MessageBox.Show(e.ToString());
                return 2;
         }
    }
}

此代码需要一些 dll 才能编译:WindowsBase.dll 和 PresentationCore.dll

键盘需要一个 STA 线程,通常我会将 [STAThread] 属性写入主函数并且它会工作,但此代码将用作 dll,所以我不能这样做。我的函数 ThisIsCalledByAnExternalProgram() 必须作为 STA 运行,但它没有。

我如何让这段代码作为 dll 工作?

编辑:当您在 STAThread 标记的方法中调用 ThisIsCalledByAnExternalProgram() 时会发生什么?

当我用我的外部程序调用该函数时,我得到一个异常: System.InvalidOperationException: ...调用线程必须是 STA,因为许多 UI 组件都需要这个。堆栈是:

System.Windows.Input.InputManager..ctor()
System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
ThisIsCalledByAnExternalProgram()

编辑#3:我误读了这个问题 - ...在标记的 STAThread 内...我目前无法尝试这个。假设它通过并工作 - 这仍然不能解决问题,因为我无法控制调用程序。

编辑#2:使用 Win32 钩子:由于可移植性,我想留在 .net 中。所有全局钩子变量最终都依赖于虚拟机下面的机器,我想使用准备好的c#键盘类。

它在不同的上下文中工作 - 这是一个简短的演示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
//Requires WindowsBase.dll
//Requires PresentationCore.dll


namespace KeyBoardDemo
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            while (true)
            {
                if (Keyboard.IsKeyDown(Key.LeftAlt))
                {
                    Console.WriteLine("LEFT ALT IS PRESSED");
                }
                else
                {
                    Console.WriteLine("LEFT ALT IS NOT PRESSED");
                }
            }
        }
    }
}
4

2 回答 2

0

考虑使用钩子,而不是仅将 winform 类用于输入。这篇文章很好地解释了只用 C# 和一些 pinvoking 来做到这一点;它还提供了一个可以满足您需求的输入库 (.dll)。本文的范围主要是全局挂钩,但也讨论了使用特定于应用程序的挂钩。

http://www.codeproject.com/KB/cs/globalhook.aspx

于 2011-10-27T12:26:23.747 回答
0

我找到了解决问题的方法,但感觉像是一种解决方法。

A)我必须绕过静态属性,以便创建新线程。B) 在使用键盘之前,我必须确保 STA。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Windows.Input;
using System.Threading;

namespace some.any
{

    public class ANY_CLASS
    {
    static STAKeyBoard mSTAKeyBoard = new STAKeyBoard();

    public static short ThisIsCalledByAnExternalProgram()
    {
        try
        {
            if (mSTAKeyBoard.IsKeyDown(Key.LeftAlt))
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
        catch (Exception e)
        {
                MessageBox.Show(e.ToString());
                return 2;
         }
    }

    class STAKeyBoard
    {
        private Thread mKeyBoardReadThread = null;
        private Boolean mKeyState = false;
        private Key mKeyOfInterest;
        private string running = "ONLY ONE REQUEST";

        public Boolean IsKeyDown(Key KeyOfInterest)
        {
            lock (running)
            {
                mKeyOfInterest = KeyOfInterest;
                mKeyBoardReadThread = new Thread(new ThreadStart(GetKeyState));
                mKeyBoardReadThread.SetApartmentState(ApartmentState.STA);
                mKeyBoardReadThread.Start();
                mKeyBoardReadThread.Join(1000);
                mKeyBoardReadThread.Abort();
                mKeyBoardReadThread = null;
                return mKeyState;
            }
        }

        private void GetKeyState()
        {
            mKeyState = Keyboard.IsKeyDown(mKeyOfInterest);
        }
    }
}
于 2011-11-03T10:56:23.390 回答