0

I am currently developing an operating system using the MOSA-OS compiler to compile CIL to machine code. Unfortunately, while developing an operating system it is not so simple to just "Console.ReadLine" to get input. Nothing from System.Console is working, and I can't use WinForms either. Is there an alternative way to get keypresses/input?

A user
  • 94
  • 8
  • If it's a custom OS, don't you need to implement such functionality yourself? Sorry - last time I did such stuff I needed to read the designated IO port to accomplish this - so my advise might be outdated XD – Stefan Jun 06 '20 at 15:44

1 Answers1

0

Hooking into the user32.dll is a great way. Here is a low-level keyboard listener that will do the job. All you need to do is call HookKeyboard() and listen for the OnKeyPressed event.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Input;

namespace DesktopWPFAppLowLevelKeyboardHook
{
    public class LowLevelKeyboardListener
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        public event EventHandler<KeyPressedArgs> OnKeyPressed;

        private LowLevelKeyboardProc _proc;
        private IntPtr _hookID = IntPtr.Zero;

        public LowLevelKeyboardListener()
        {
            _proc = HookCallback;
        }

        public void HookKeyboard()
        {
            _hookID = SetHook(_proc);
        }

        public void UnHookKeyboard()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);

                if (OnKeyPressed != null) { OnKeyPressed(this, new KeyPressedArgs(KeyInterop.KeyFromVirtualKey(vkCode))); }
            }

            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    }

    public class KeyPressedArgs : EventArgs
    {
        public Key KeyPressed { get; private set; }

        public KeyPressedArgs(Key key)
        {
            KeyPressed = key;
        }
    }
}
Beckam White
  • 143
  • 10
  • ... but, this is Windows OS, not a *"currently developing an operating system"*, or am I missing something here? – Stefan Jun 06 '20 at 15:56
  • He tagged it as C# and this is the only way outside of `System.Input` that I know of to get keyboard input. – Beckam White Jun 06 '20 at 16:07
  • Can you explain how this relates to my comment? C# can run on multiple OS'ses these days - it's not only windows bound. To read from a console one needs to access the hardware ports where key presses are stored. Your low level approach reads data from the Win API - which is fine if OP uses windows - which I doubt – Stefan Jun 06 '20 at 16:13
  • It relates to your comment because it answers your question... I'm well aware that C# can run on OS's other than Windows but you cannot get input from other OS's with C# especially a custom OS which he seems to be crafting. I am just suggesting an answer, I'm not saying it is the solution. Feel free to downvote. – Beckam White Jun 06 '20 at 16:29
  • Ah, okay, well yes, I am just wondering how windows dlls would be available on on-windows os-ses. I won't down vote, because - I think we need more input from OP. – Stefan Jun 06 '20 at 16:33