How can i write a dll function that uses the C# Keyboard Class
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");
}
}
}
}
}
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.