Pregunta

I want to use the following code to access the state of the keyboard at a certain time.

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;
         }
    }
}

This code requires some dlls to compile: WindowsBase.dll and PresentationCore.dll

Keyboard requires a STA Thread, normally i would write the [STAThread] attribute to the main function and it would work, but this code will be used as a dll, so i can not do that. My function ThisIsCalledByAnExternalProgram() would have to run as an STA but it doesnt.

How do i get this code to work as a dll?

EDIT: What happens when you call ThisIsCalledByAnExternalProgram() within a STAThread flagged method?

When i call the function with my external program i get an exception: System.InvalidOperationException: ...The calling thread must be STA, because many UI components require this. Stack is:

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

EDIT#3: I misread the question - ...within a STAThread flagged... i can currently not try this one. suppose it passes and works - this would still not solve the problem since i have no control over the calling program.

EDIT#2: Use a Win32 hook: I want to stay within .net because of portability. All global hook variants are in the end dependent on the machine below the virtual machine, i want to use the prepared Keyboard class of c#.

It works in a different context - here is a short demo:

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");
                }
            }
        }
    }
}
¿Fue útil?

Solución 2

I found a solution to my Problem, but it feels like a Workaround.

A) I have to get around the static property so i can create new Threads. B) I have to ensure STA before using Keayboard.

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);
        }
    }
}

Otros consejos

Consider using a hook, instead of using winform classes just for input. This article is a great explanation of doing that with just C# with some pinvoking; it provides a input library (.dll) as well that may suit your needs. The article's scope is mainly global hooks but it also discusses using application specific hooks.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top