1

I currently work with the Steelseries GameSense SDK to make my own effects etc. for my keyboard and mouse.

To light up my mouse and keyboard on clicks and presses, I use the globalmousekeyhook library.

Unfortunately, the mouse and keyboard events don't get triggered.

Also, my mouse starts lagging, and keyboard input gets delayed.

The lag and the delay only stay for about half a minute.

I suspect that windows removes the hooks because it detects the lag.

I also tried this example program and everything works fine there.

Here is the code:

private static readonly IKeyboardMouseEvents GlobalHook = Hook.GlobalEvents();
static InputManager()
{
    Logger.Log("Starting...", Logger.Type.Info);
    GlobalHook.KeyDown += KeyEvent;
    GlobalHook.MouseDownExt += MouseEvent;
    Logger.Log("Ready!", Logger.Type.Info);
}

And the event functions:

private static void KeyEvent(object sender, KeyEventArgs eventArgs)
{
    Logger.Log(eventArgs.KeyCode.ToString());
}
private static void MouseEvent(object sender, MouseEventArgs eventArgs)
{
    Logger.Log(eventArgs.Button.ToString());
}

You can find the whole class (and the project) here.

The constructor is the only thing that gets executed in the program.

What I found regarding the lag is that the event function has to be fast. That cannot be the problem in my case because the Logger.Log() function is fast, and the lag also occurs when using Console.WriteLine().

As I said, the example program runs fine. I tried copying the example code, but that made no difference. The only real difference between my program and the example program is that the example uses .Net Core but I use .Net Framework (4.8). Could that be the reason? If it is the reason, is there any way to use the library with .Net Framework? I look forward to any help.

Habetuz
  • 111
  • 1
  • 6
  • It's normal to if you try to respond all events. You may try logging in a new thread but it will also use unnecessary system resources. **private static void KeyEvent(object sender, KeyEventArgs eventArgs) { Task.Run(() => { Logger.Log(eventArgs.KeyCode.ToString()); }); }** – aliassce Jun 03 '21 at 18:44
  • 1
    @OlivierRogier It even lags when I comment out Logger.Log() and therefore empty the event function. Also unfortunately the linked wrapper does not suit my case because I need to hook all events. – Habetuz Jun 03 '21 at 18:56
  • @aliassce I tried your suggestion and it still lags. The [example](https://github.com/gmamaladze/globalmousekeyhook/tree/vNext/examples/ConsoleHook) I linked also logs all events, but it does not lag there for some reason. – Habetuz Jun 03 '21 at 19:02
  • `Console.ReadLine` in `Program.Main()` is blocking everything, in any case you are not running a meesage loop, so I'm not sure what you expect to happen. Note that the example code you supply is *very* different, it sets up a message loop with `Application.Run(new ApplicationContext());` I must say I don't understand why `InputManager.Start` is empty and all the hookup code is in the static constructor. That doesn't sound very safe. – Charlieface Jun 03 '21 at 19:39
  • @Charlieface I do not have a message loop right now cause I first need to get the mouse and keyboard hook working. I expect a console output with the key or the mouse button I click (you can see that in the `KeyEvent` and `MouseEvent` functions). The static constructor gets called before any other method gets called. So when you call `InputManager.Start()` it runs the constructor. This has the advantage that the "start" function gets called even when you call any method of the class. Could you explain why `Console.ReadLine()` is blocking? Is there an alternative to keep the program running? – Habetuz Jun 03 '21 at 19:53
  • `Console.ReadLine` waits for an input on `stdin` pipe, and will block the pump on the message queue. You *need* a message pump because the hook receives messages via the message queue. Is there another method: of course, just run the message loop and `Console.ReadLine` on different threads – Charlieface Jun 03 '21 at 21:05
  • @Charlieface I made a function `KeepAlive` which only calls `Console.ReadLine()`. As you suggested I run this function on a different thread with `new Thread(KeepAlive).Start()`. This indeed keeps the program running, nevertheless it still lags and no events are triggered. Also there is another side effect: I cannot type into the console anymore (even after Windows removes the hooks). Typing still works on other programs. The changes are [pushed](https://github.com/habetuz/KaLE/blob/master/KaLE.Program.cs). – Habetuz Jun 03 '21 at 21:28
  • I'm completely confused as to why you thought that would work in the way the other code did or why you did not do the same as it. You *need* a message pump. A `while(true) ;` loop is just wasting CPU – Charlieface Jun 03 '21 at 21:31
  • @Charlieface I'm sorry to confuse you. I first tried `Console.ReadLine()` in the `KeepAlive` function but that did not work so I tried with `while(true) ;` loop. I changed it back to `Console.ReadLine()` now. – Habetuz Jun 03 '21 at 21:37

1 Answers1

0

There are two issues:

  • You need a message pump in order to receive hook messages. For this you can use the following code, as shown in the example you link
Application.Run(new ApplicationContext());
  • You now have two things you are trying to do on the same thread: pump the messages and wait for input. Instead, split them into different threads:
private static void Main(string[] args)
{
    Logger.Log("Program started. Welcome.", Logger.Type.Info);
    ////GameSense.Controller.Start();
    new Thread(() => Console.ReadLine()).Start();
            
    InputManager.Start();
    
    Application.Run(new ApplicationContext());
    InputManager.End();
    Application.Exit();  // needed to close down the message pump and end the other thread
}
Charlieface
  • 52,284
  • 6
  • 19
  • 43
  • Thank you very much! I'm not very familiar with std pumps. Leaned something new today! – Habetuz Jun 03 '21 at 21:55
  • Just checked: I have to call `Application.Run(new ApplicationContext())` in the same thread after `InputManager.Start()`. It only works this way. (The example also has it that way) – Habetuz Jun 03 '21 at 22:00
  • You could do it that way round if you want, then place `Console.ReadLine` in the other thread. I don't think it makes a difference – Charlieface Jun 03 '21 at 22:11
  • It actually only works if you put both on the same thread. `Application.Run(new ApplicationContext())` to start the new std pipe (when I understand it right?) and Console.ReadLine() does not block the "old" pipe? The way it is currently on GitHub works. When I try your code it still lags. – Habetuz Jun 03 '21 at 22:24
  • `Application.Run` doesn't have anything to do with the pipe, and it will block you from using `ReadLine` – Charlieface Jun 03 '21 at 22:25
  • Okay, as I said, I am not very familiar with this stuff. Nevertheless the current state of the answer does not work. The version on my GitHub works. – Habetuz Jun 03 '21 at 22:40