branch update for HEAD-2003091401
[reactos.git] / subsys / csrss / api / conio.c
index 0d1e7ba..73481fe 100644 (file)
@@ -24,7 +24,7 @@
 
 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
 #define ALIAS(Name, Target) typeof(Target) Name = Target
-
+extern VOID CsrConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData);
 
 /* GLOBALS *******************************************************************/
 
@@ -33,9 +33,48 @@ static HANDLE KeyboardDeviceHandle;
 static PCSRSS_CONSOLE ActiveConsole;
 CRITICAL_SECTION ActiveConsoleLock;
 static COORD PhysicalConsoleSize;
+static BOOL KeyReadInhibit = FALSE;
 
 /* FUNCTIONS *****************************************************************/
 
+VOID CsrConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
+{
+    HANDLE Process, hThread;
+    NTSTATUS Status;
+    CLIENT_ID ClientId, ClientId1;
+       
+    DPRINT1("CsrConsoleCtrlEvent Parent ProcessId = %x\n",     ClientId.UniqueProcess);
+
+    if (ProcessData->CtrlDispatcher)
+    {
+       ClientId.UniqueProcess = (HANDLE) ProcessData->ProcessId;
+       Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
+       if( !NT_SUCCESS( Status ) )
+       {
+           DPRINT("CsrConsoleCtrlEvent: Failed for handle duplication\n");
+           return;
+       }
+
+       DPRINT1("CsrConsoleCtrlEvent Process Handle = %x\n", Process);
+
+
+       Status = RtlCreateUserThread(Process, NULL, FALSE, 0, NULL, NULL,
+                                   (PTHREAD_START_ROUTINE)ProcessData->CtrlDispatcher,
+                                   (PVOID) Event, &hThread, &ClientId1);
+       if( !NT_SUCCESS( Status ) )
+       {
+           DPRINT("CsrConsoleCtrlEvent: Failed Thread creation\n");
+           NtClose(Process);
+           return;
+       }
+       DPRINT1("CsrConsoleCtrlEvent Parent ProcessId = %x, ReturnPId = %x, hT = %x\n",
+               ClientId.UniqueProcess, ClientId1.UniqueProcess, hThread);
+       NtClose(hThread);
+       NtClose(Process);
+    }
+}
+
+
 CSR_API(CsrAllocConsole)
 {
    PCSRSS_CONSOLE Console;
@@ -88,6 +127,7 @@ CSR_API(CsrAllocConsole)
         ProcessData->Console = 0;
         return Reply->Status = Status;
       }
+
    ClientId.UniqueProcess = (HANDLE)ProcessData->ProcessId;
    Status = NtOpenProcess( &Process, PROCESS_DUP_HANDLE, 0, &ClientId );
    if( !NT_SUCCESS( Status ) )
@@ -113,6 +153,12 @@ CSR_API(CsrAllocConsole)
        return Status;
      }
    NtClose( Process );
+   LOCK;
+   ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
+   DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);      
+   InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ProcessEntry);
+   UNLOCK;
+
    return STATUS_SUCCESS;
 }
 
@@ -736,6 +782,7 @@ NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
   Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
   Console->EarlyReturn = FALSE;
   InitializeListHead(&Console->InputEvents);
+  InitializeListHead(&Console->ProcessList);
 
   InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL);
 
@@ -757,6 +804,9 @@ NTSTATUS STDCALL CsrInitConsole(PCSRSS_CONSOLE Console)
        RtlFreeHeap( CsrssApiHeap, 0, Console->ActiveBuffer );
        return Status;
      }
+  /* Create the GDI Window to be used in windowed mode */
+  /* FIXME: create window; now write NULL */
+  Console->hWindow = (HWND) NULL;
   /* add a reference count because the buffer is tied to the console */
   Console->ActiveBuffer->Header.ReferenceCount++;
   /* make console active, and insert into console list */
@@ -923,8 +973,12 @@ VOID Console_Api( DWORD RefreshEvent )
          continue;
        }
       KeyEventRecord->InputEvent.EventType = KEY_EVENT;
-      Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
-        &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
+      if( !KeyReadInhibit ) {
+        Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb,
+                             &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 );
+      } else {
+       Status = STATUS_PENDING;
+      }
       if( !NT_SUCCESS( Status ) )
        {
          DbgPrint( "CSR: ReadFile on keyboard device failed\n" );
@@ -1031,7 +1085,29 @@ VOID Console_Api( DWORD RefreshEvent )
 
          UNLOCK;
        }
-      if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
+     /* process Ctrl-C and Ctrl-Break */
+     if (ActiveConsole->Mode & ENABLE_PROCESSED_INPUT &&
+         KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown &&
+        ((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) || 
+        (KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
+        (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
+         {
+           PCSRSS_PROCESS_DATA current;
+           PLIST_ENTRY current_entry;
+            DPRINT1("Console_Api Ctrl-C\n");
+           LOCK;
+           current_entry = ActiveConsole->ProcessList.Flink;
+           while (current_entry != &ActiveConsole->ProcessList)
+           {
+               current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
+               current_entry = current_entry->Flink;
+               CsrConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
+           }
+           UNLOCK;
+           RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord );
+           continue;
+        }
+     if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState &
         ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) &&
         ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ||
           KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) )
@@ -1154,6 +1230,8 @@ VOID Console_Api( DWORD RefreshEvent )
               KeyEventRecord->Echoed = TRUE;
            }
       }
+
+      
       ActiveConsole->WaitingChars++;
       if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) )
        NtSetEvent( ActiveConsole->ActiveEvent, 0 );
@@ -2331,9 +2409,9 @@ CSR_API(CsrReadConsoleOutput)
    BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
    BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
    Length = BufferSize.X * BufferSize.Y;
-   Size = Length * sizeof(INPUT_RECORD);
+   Size = Length * sizeof(CHAR_INFO);
    
-    if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
+   if(((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
          || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
    {
       UNLOCK;
@@ -2356,7 +2434,7 @@ CSR_API(CsrReadConsoleOutput)
    
    for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
    {
-     CurCharInfo = CharInfo + (i * BufferSize.Y);
+     CurCharInfo = CharInfo + (i * BufferSize.X);
      
      Offset = (((Y + ScreenBuffer->ShowY) % ScreenBuffer->MaxY) * ScreenBuffer->MaxX + ReadRegion.Left) * 2;
      for(X = ReadRegion.Left; X < ReadRegion.Right; ++X)
@@ -2443,4 +2521,134 @@ CSR_API(CsrWriteConsoleInput)
    return Reply->Status;
 }
 
+/**********************************************************************
+ *     HardwareStateProperty
+ *
+ *     DESCRIPTION
+ *             Set/Get the value of the HardwareState and switch
+ *             between direct video buffer ouput and GDI windowed
+ *             output.
+ *     ARGUMENTS
+ *             Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
+ *             object. We use the same object to reply.
+ *     NOTE
+ *             ConsoleHwState has the correct size to be compatible
+ *             with NT's, but values are not.
+ */
+static NTSTATUS FASTCALL SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
+{
+   DbgPrint( "Console Hardware State: %d\n", ConsoleHwState );
+
+   if ( (CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
+      ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
+   {
+      /* Inhibit keyboard input when hardware state ==
+       * CONSOLE_HARDWARE_STATE_GDI_MANAGED */
+      if (CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState) {
+         DbgPrint( "Keyboard Inhibited.\n" );
+         KeyReadInhibit = TRUE;
+      } else {
+         DbgPrint( "Keyboard Enabled.\n" );
+         KeyReadInhibit = FALSE;
+      }
+      if (Console->HardwareState != ConsoleHwState)
+      {
+        /* TODO: implement switching from full screen to windowed mode */
+        /* TODO: or back; now simply store the hardware state */
+         Console->HardwareState = ConsoleHwState;
+      }
+      return STATUS_SUCCESS;   
+   }
+   return STATUS_INVALID_PARAMETER_3; // Client: (handle, set_get, [mode])
+}
+
+CSR_API(CsrHardwareStateProperty)
+{
+   PCSRSS_CONSOLE Console;
+   NTSTATUS       Status;
+   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
+   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
+
+   LOCK;
+   
+   Status = CsrGetObject (
+                  ProcessData,
+                  Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
+                  (Object_t**) & Console
+                  );
+   if (!NT_SUCCESS(Status))
+   {
+      DbgPrint( "Failed to get console handle in SetConsoleHardwareState\n" );
+      Reply->Status = Status;
+   }
+   else
+   {
+      if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
+      {
+       DbgPrint( "Bad magic on Console: %08x\n", Console->Header.Type );
+        Reply->Status = STATUS_INVALID_HANDLE;
+      }
+      else
+      {
+         switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
+         {
+         case CONSOLE_HARDWARE_STATE_GET:
+            Reply->Data.ConsoleHardwareStateReply.State = Console->HardwareState;
+            break;
+      
+         case CONSOLE_HARDWARE_STATE_SET:
+           DbgPrint( "Setting console hardware state.\n" );
+            Reply->Status = SetConsoleHardwareState (Console, Request->Data.ConsoleHardwareStateRequest.State);
+            break;
+
+         default:
+            Reply->Status = STATUS_INVALID_PARAMETER_2; // Client: (handle, [set_get], mode)
+            break;
+         }
+      }
+   }
+
+   UNLOCK;
+
+   return Reply->Status;
+}
+
+CSR_API(CsrGetConsoleWindow)
+{
+   PCSRSS_CONSOLE Console;
+   NTSTATUS       Status;
+   Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
+   Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE);
+
+   LOCK;
+   
+   Status = CsrGetObject (
+                  ProcessData,
+                  Request->Data.ConsoleWindowRequest.ConsoleHandle,
+                  (Object_t**) & Console
+                  );
+   if (!NT_SUCCESS(Status))
+   {
+      Reply->Status = Status;
+   }
+   else
+   {
+      if(Console->Header.Type != CSRSS_CONSOLE_MAGIC)
+      {
+         Reply->Status = STATUS_INVALID_HANDLE;
+      }
+      else
+      {
+        // Is this GDI handle valid in the client's context?
+        Reply->Data.ConsoleWindowReply.WindowHandle = Console->hWindow;
+      }
+   }
+
+   UNLOCK;
+
+   return Reply->Status;
+}
+
 /* EOF */