Implement console input
Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.c
Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.h
Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/xencons.c

Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.c
--- branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.c	2005-05-16 22:21:00 UTC (rev 15363)
+++ branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.c	2005-05-16 22:42:53 UTC (rev 15364)
@@ -132,6 +132,7 @@
   i386TrapSaveDRHook = XenTrapSaveDR;
   HYPERVISOR_set_trap_table(trap_table);
 
+  XenConsInit();
   XenCtrlIfRegisterReceiver(CMSG_SHUTDOWN, XenShutdownHandler);
 
   /* Ready to receive events now */
@@ -196,20 +197,6 @@
   printf(routine " unimplemented. Shutting down\n"); \
   XenDie()
 
-BOOL
-XenConsKbHit()
-  {
-    XEN_UNIMPLEMENTED("XenConsKbHit");
-    return FALSE;
-  }
-
-int
-XenConsGetCh()
-  {
-    XEN_UNIMPLEMENTED("XenConsGetCh");
-    return 0;
-  }
-
 VOID
 XenVideoSetTextCursorPosition(ULONG X, ULONG Y)
   {

Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.h
--- branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.h	2005-05-16 22:21:00 UTC (rev 15363)
+++ branches/xen/reactos/boot/freeldr/freeldr/arch/i386/machxen.h	2005-05-16 22:42:53 UTC (rev 15364)
@@ -50,6 +50,7 @@
 VOID XenEvtchnDisableEvents();
 VOID XenEvtchnEnableEvents();
 
+VOID XenConsInit();
 VOID XenConsPutChar(int Ch);
 BOOL XenConsKbHit();
 int XenConsGetCh();

Modified: branches/xen/reactos/boot/freeldr/freeldr/arch/i386/xencons.c
--- branches/xen/reactos/boot/freeldr/freeldr/arch/i386/xencons.c	2005-05-16 22:21:00 UTC (rev 15363)
+++ branches/xen/reactos/boot/freeldr/freeldr/arch/i386/xencons.c	2005-05-16 22:42:53 UTC (rev 15364)
@@ -41,6 +41,7 @@
  */
 
 #include "freeldr.h"
+#include "keycodes.h"
 #include "machxen.h"
 
 #include <rosxen.h>
@@ -61,6 +62,15 @@
 static char OutputBuffer[OUTPUT_BUFFER_SIZE];
 static unsigned OutputPtr = 0;
 
+#define INPUT_BUFFER_SIZE 64
+static int InputBuffer[INPUT_BUFFER_SIZE];
+static unsigned InputCount = 0;
+
+#define ESC_SEQ_TIMEOUT 200000000 /* in nanosec, 0.2 sec */
+static UCHAR InputEscSeq[4];
+static unsigned InputEscSeqCount = 0;
+static ULONGLONG InputEscSeqTime = 0;
+
 VOID
 XenConsFlush()
 {
@@ -138,4 +148,157 @@
     }
 }
 
+static void
+XenConsGetTime(PULONGLONG Now)
+{
+  ULONG ShadowTimeVersion;
+
+  do
+    {
+      ShadowTimeVersion = XenSharedInfo->time_version2;
+      *Now = XenSharedInfo->system_time;
+    }
+  while (ShadowTimeVersion != XenSharedInfo->time_version1);
+}
+
+static void
+XenConsCheckInputEscSequence()
+{
+  static struct
+    {
+    char *EscSequence;
+    int Key;
+    }
+  KnownSequences[] =
+    {
+      { "\033[A", KEY_UP },
+      { "\033[B", KEY_DOWN },
+    };
+  unsigned i;
+  ULONGLONG Now;
+
+  if (0 != InputEscSeqCount)
+    {
+      XenConsGetTime(&Now);
+      if (InputEscSeqTime + ESC_SEQ_TIMEOUT <= Now
+          || InputEscSeqCount == sizeof(InputEscSeq) / sizeof(InputEscSeq[0]))
+        {
+          for (i = 0; i < sizeof(InputEscSeq) / sizeof(InputEscSeq[0]); i++)
+            {
+              if (InputCount < INPUT_BUFFER_SIZE)
+                {
+                  InputBuffer[InputCount++] = InputEscSeq[i];
+                }
+            }
+          InputEscSeqCount = 0;
+        }
+      else
+        {
+          for (i = 0; i < sizeof(KnownSequences) / sizeof(KnownSequences[0]); i++)
+            {
+              if (InputEscSeqCount == strlen(KnownSequences[i].EscSequence)
+                  && 0 == memcmp(InputEscSeq, KnownSequences[i].EscSequence,
+                                 InputEscSeqCount))
+                {
+                  if (InputCount < INPUT_BUFFER_SIZE)
+                    {
+                      InputBuffer[InputCount++] = KnownSequences[i].Key;
+                    }
+                  InputEscSeqCount = 0;
+                  break;
+                }
+            }
+        }
+    }
+}
+
+int
+XenConsGetCh()
+{
+  int Key;
+  
+  XenEvtchnDisableEvents();
+  XenConsCheckInputEscSequence();
+  while (0 == InputCount)
+    {
+      HYPERVISOR_block();
+      XenEvtchnDisableEvents();
+    }
+  Key = InputBuffer[0];
+  InputCount--;
+  if (0 != InputCount)
+    {
+      memmove(InputBuffer, InputBuffer + 1, InputCount * sizeof(int));
+    }
+  XenEvtchnEnableEvents();
+
+  return Key;
+  }
+
+BOOL
+XenConsKbHit()
+{
+  BOOL Hit;
+
+  XenEvtchnDisableEvents();
+  XenConsCheckInputEscSequence();
+  Hit = (0 != InputCount);
+  XenEvtchnEnableEvents();
+
+  if (! Hit)
+    {
+      HYPERVISOR_yield();
+    }
+
+  return Hit;
+}
+
+static void
+XenConsProcessInput(unsigned Length, PUCHAR Data)
+{
+  unsigned i;
+
+  XenConsCheckInputEscSequence();
+  for (i = 0; i < Length; i++)
+    {
+      if (0 != InputEscSeqCount || '\033' == Data[i])
+        {
+          InputEscSeq[InputEscSeqCount++] = Data[i];
+          XenConsGetTime(&InputEscSeqTime);
+          XenConsCheckInputEscSequence();
+        }
+      else
+        {
+          InputBuffer[InputCount++] = (int) Data[i];
+        }
+    }
+}
+
+static void
+XenConsMsgHandler(ctrl_msg_t *Msg, unsigned long Id)
+{
+  switch (Msg->subtype)
+    {
+    case CMSG_CONSOLE_DATA:
+      XenConsProcessInput(Msg->length, &Msg->msg[0]);
+      Msg->length = 0;
+      break;
+    default:
+      Msg->length = 0;
+      break;
+    }
+
+  XenCtrlIfSendResponse(Msg);
+}
+
+VOID
+XenConsInit()
+{
+  OutputPtr = 0;
+  InputCount = 0;
+  InputEscSeqCount = 0;
+
+  XenCtrlIfRegisterReceiver(CMSG_CONSOLE, XenConsMsgHandler);
+}
+
 /* EOF */