user32: Implement OpenInputDesktop.
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c
index d7825a1..4f664dd 100644
--- a/dlls/user32/tests/winstation.c
+++ b/dlls/user32/tests/winstation.c
@@ -492,29 +492,21 @@
 
     /* OpenInputDesktop creates new handles for each calls */
     old_input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
-todo_wine
     ok(old_input_desk != NULL, "OpenInputDesktop failed!\n");
     memset(name, 0, sizeof(name));
     ret = GetUserObjectInformationA(old_input_desk, UOI_NAME, name, 1024, NULL);
-todo_wine
     ok(ret, "GetUserObjectInformation failed!\n");
-todo_wine
     ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
 
     input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
-todo_wine
     ok(input_desk != NULL, "OpenInputDesktop failed!\n");
     memset(name, 0, sizeof(name));
     ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
-todo_wine
     ok(ret, "GetUserObjectInformation failed!\n");
-todo_wine
     ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
 
-todo_wine
     ok(old_input_desk != input_desk, "returned the same handle!\n");
     ret = CloseDesktop(input_desk);
-todo_wine
     ok(ret, "CloseDesktop failed!\n");
 
     /* by default, GetThreadDesktop is the input desktop, SendInput should success. */
@@ -571,10 +563,8 @@
 
     /* Set thread desktop to the input desktop, SendInput should success. */
     ret = SetThreadDesktop(old_input_desk);
-todo_wine
     ok(ret, "SetThreadDesktop failed!\n");
     thread_desk = GetThreadDesktop(GetCurrentThreadId());
-todo_wine
     ok(thread_desk == old_input_desk, "thread desktop doesn't match!\n");
     memset(name, 0, sizeof(name));
     ret = GetUserObjectInformationA(thread_desk, UOI_NAME, name, 1024, NULL);
@@ -589,17 +579,14 @@
     ret = SwitchDesktop(new_desk);
     ok(ret, "SwitchDesktop failed!\n");
     input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
-todo_wine
     ok(input_desk != NULL, "OpenInputDesktop failed!\n");
     ok(input_desk != new_desk, "returned the same handle!\n");
     memset(name, 0, sizeof(name));
     ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
-todo_wine
     ok(ret, "GetUserObjectInformation failed!\n");
 todo_wine
     ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name);
     ret = CloseDesktop(input_desk);
-todo_wine
     ok(ret, "CloseDesktop failed!\n");
 
     SetLastError(0xdeadbeef);
@@ -626,15 +613,11 @@
      * thread desktop, clean side effects. SendInput should success. */
     ret = SwitchDesktop(old_input_desk);
     input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
-todo_wine
     ok(input_desk != NULL, "OpenInputDesktop failed!\n");
-todo_wine
     ok(input_desk != old_input_desk, "returned the same handle!\n");
     memset(name, 0, sizeof(name));
     ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL);
-todo_wine
     ok(ret, "GetUserObjectInformation failed!\n");
-todo_wine
     ok(!strcmp(name, "Default"), "unexpected desktop %s\n", name);
 
     ret = SetThreadDesktop(old_thread_desk);
@@ -652,10 +635,8 @@
 
     /* free resources */
     ret = CloseDesktop(input_desk);
-todo_wine
     ok(ret, "CloseDesktop failed!\n");
     ret = CloseDesktop(old_input_desk);
-todo_wine
     ok(ret, "CloseDesktop failed!\n");
     ret = CloseDesktop(new_desk);
     ok(ret, "CloseDesktop failed!\n");
@@ -684,10 +665,8 @@
     ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
     ok(!ret, "EnumDesktopsA failed!\n");
     input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
-todo_wine
     ok(input_desk != NULL, "OpenInputDesktop failed!\n");
     ret = CloseDesktop(input_desk);
-todo_wine
     ok(ret, "CloseDesktop failed!\n");
 
     ret = SetProcessWindowStation(w2);
@@ -704,7 +683,6 @@
     SetLastError(0xdeadbeef);
     input_desk = OpenInputDesktop(0, FALSE, DESKTOP_ALL_ACCESS);
     ok(input_desk == NULL, "OpenInputDesktop should fail on non default winstation!\n");
-todo_wine
     ok(GetLastError() == ERROR_INVALID_FUNCTION || broken(GetLastError() == 0xdeadbeef), "last error %08x\n", GetLastError());
 
     hdesk = OpenDesktopA("desk_test", 0, TRUE, DESKTOP_ALL_ACCESS);
diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c
index 96b51179..12b9edc 100644
--- a/dlls/user32/winstation.c
+++ b/dlls/user32/winstation.c
@@ -462,9 +462,23 @@
  */
 HDESK WINAPI OpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK access )
 {
-    FIXME( "(%x,%i,%x): stub\n", flags, inherit, access );
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return 0;
+    HANDLE ret = 0;
+
+    TRACE( "(%x,%i,%x)\n", flags, inherit, access );
+
+    if (flags)
+        FIXME( "partial stub flags %08x\n", flags );
+
+    SERVER_START_REQ( open_input_desktop )
+    {
+        req->flags      = flags;
+        req->access     = access;
+        req->attributes = inherit ? OBJ_INHERIT : 0;
+        if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle );
+    }
+    SERVER_END_REQ;
+
+    return ret;
 }
 
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 7136d9b..604affd 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3804,6 +3804,22 @@
 
 
 
+struct open_input_desktop_request
+{
+    struct request_header __header;
+    unsigned int flags;
+    unsigned int access;
+    unsigned int attributes;
+};
+struct open_input_desktop_reply
+{
+    struct reply_header __header;
+    obj_handle_t handle;
+    char __pad_12[4];
+};
+
+
+
 struct close_desktop_request
 {
     struct request_header __header;
@@ -5233,6 +5249,7 @@
     REQ_enum_winstation,
     REQ_create_desktop,
     REQ_open_desktop,
+    REQ_open_input_desktop,
     REQ_close_desktop,
     REQ_get_thread_desktop,
     REQ_set_thread_desktop,
@@ -5493,6 +5510,7 @@
     struct enum_winstation_request enum_winstation_request;
     struct create_desktop_request create_desktop_request;
     struct open_desktop_request open_desktop_request;
+    struct open_input_desktop_request open_input_desktop_request;
     struct close_desktop_request close_desktop_request;
     struct get_thread_desktop_request get_thread_desktop_request;
     struct set_thread_desktop_request set_thread_desktop_request;
@@ -5751,6 +5769,7 @@
     struct enum_winstation_reply enum_winstation_reply;
     struct create_desktop_reply create_desktop_reply;
     struct open_desktop_reply open_desktop_reply;
+    struct open_input_desktop_reply open_input_desktop_reply;
     struct close_desktop_reply close_desktop_reply;
     struct get_thread_desktop_reply get_thread_desktop_reply;
     struct set_thread_desktop_reply set_thread_desktop_reply;
@@ -5826,6 +5845,6 @@
     struct set_suspend_context_reply set_suspend_context_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 450
+#define SERVER_PROTOCOL_VERSION 451
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index 95d7994..31b85f8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2707,6 +2707,16 @@
 @END
 
 
+/* Open a handle to current input desktop */
+@REQ(open_input_desktop)
+    unsigned int flags;           /* desktop flags */
+    unsigned int access;          /* wanted access rights */
+    unsigned int attributes;      /* object attributes */
+@REPLY
+    obj_handle_t handle;          /* handle to the desktop */
+@END
+
+
 /* Close a desktop */
 @REQ(close_desktop)
     obj_handle_t handle;          /* handle to the desktop */
diff --git a/server/request.h b/server/request.h
index 41c67ee..74f5892 100644
--- a/server/request.h
+++ b/server/request.h
@@ -286,6 +286,7 @@
 DECL_HANDLER(enum_winstation);
 DECL_HANDLER(create_desktop);
 DECL_HANDLER(open_desktop);
+DECL_HANDLER(open_input_desktop);
 DECL_HANDLER(close_desktop);
 DECL_HANDLER(get_thread_desktop);
 DECL_HANDLER(set_thread_desktop);
@@ -545,6 +546,7 @@
     (req_handler)req_enum_winstation,
     (req_handler)req_create_desktop,
     (req_handler)req_open_desktop,
+    (req_handler)req_open_input_desktop,
     (req_handler)req_close_desktop,
     (req_handler)req_get_thread_desktop,
     (req_handler)req_set_thread_desktop,
@@ -1735,6 +1737,12 @@
 C_ASSERT( sizeof(struct open_desktop_request) == 32 );
 C_ASSERT( FIELD_OFFSET(struct open_desktop_reply, handle) == 8 );
 C_ASSERT( sizeof(struct open_desktop_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct open_input_desktop_request, flags) == 12 );
+C_ASSERT( FIELD_OFFSET(struct open_input_desktop_request, access) == 16 );
+C_ASSERT( FIELD_OFFSET(struct open_input_desktop_request, attributes) == 20 );
+C_ASSERT( sizeof(struct open_input_desktop_request) == 24 );
+C_ASSERT( FIELD_OFFSET(struct open_input_desktop_reply, handle) == 8 );
+C_ASSERT( sizeof(struct open_input_desktop_reply) == 16 );
 C_ASSERT( FIELD_OFFSET(struct close_desktop_request, handle) == 12 );
 C_ASSERT( sizeof(struct close_desktop_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_request, tid) == 12 );
diff --git a/server/trace.c b/server/trace.c
index 1a9f403..2171a25 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3192,6 +3192,18 @@
     fprintf( stderr, " handle=%04x", req->handle );
 }
 
+static void dump_open_input_desktop_request( const struct open_input_desktop_request *req )
+{
+    fprintf( stderr, " flags=%08x", req->flags );
+    fprintf( stderr, ", access=%08x", req->access );
+    fprintf( stderr, ", attributes=%08x", req->attributes );
+}
+
+static void dump_open_input_desktop_reply( const struct open_input_desktop_reply *req )
+{
+    fprintf( stderr, " handle=%04x", req->handle );
+}
+
 static void dump_close_desktop_request( const struct close_desktop_request *req )
 {
     fprintf( stderr, " handle=%04x", req->handle );
@@ -4252,6 +4264,7 @@
     (dump_func)dump_enum_winstation_request,
     (dump_func)dump_create_desktop_request,
     (dump_func)dump_open_desktop_request,
+    (dump_func)dump_open_input_desktop_request,
     (dump_func)dump_close_desktop_request,
     (dump_func)dump_get_thread_desktop_request,
     (dump_func)dump_set_thread_desktop_request,
@@ -4508,6 +4521,7 @@
     (dump_func)dump_enum_winstation_reply,
     (dump_func)dump_create_desktop_reply,
     (dump_func)dump_open_desktop_reply,
+    (dump_func)dump_open_input_desktop_reply,
     NULL,
     (dump_func)dump_get_thread_desktop_reply,
     NULL,
@@ -4764,6 +4778,7 @@
     "enum_winstation",
     "create_desktop",
     "open_desktop",
+    "open_input_desktop",
     "close_desktop",
     "get_thread_desktop",
     "set_thread_desktop",
diff --git a/server/winstation.c b/server/winstation.c
index 57e6995..2eaffb0 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -551,6 +551,28 @@
     }
 }
 
+/* open a handle to current input desktop */
+DECL_HANDLER(open_input_desktop)
+{
+    /* FIXME: check access rights */
+    struct winstation *winstation = get_process_winstation( current->process, 0 );
+    struct desktop *desktop;
+
+    if (!winstation) return;
+
+    if (!(winstation->flags & WSF_VISIBLE))
+    {
+        set_error( STATUS_ILLEGAL_FUNCTION );
+        return;
+    }
+
+    if ((desktop = get_desktop_obj( current->process, current->process->desktop, 0 )))
+    {
+        reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes );
+        release_object( desktop );
+    }
+    release_object( winstation );
+}
 
 /* close a desktop */
 DECL_HANDLER(close_desktop)