使用 C# 和 Win API 移动 On-Screen 键盘 (osk.exe)

Move On-Screen Keyboard (osk.exe) with C# & Win API

我制作了这个 .ps1 小脚本,因为它允许我 运行 C# 而无需使用编译器(至少直接)。我想移动以 cmd /c osk.exe 打开的 "Accessibility On-Screen Keyboard",因为我不能真正使用 TabTip - Win8+ 上的平移触摸屏键盘。

由于 On-Screen 键盘不像平移键盘那么漂亮,我想 将键盘移动 到所需位置 调整它的大小。我注意到 OSK 有一个 child window (OSKMainClassDirectUIHWND),所以我为此努力了,但没有运气。另一方面,单个 window 的相同代码适用于记事本并正确放置和调整它的大小。

我将 Process.Start() 放入 if 中,以便它返回一些反馈,因此我看到它找到了 child window - 很好。 但是,它没有移动它。

当我按下 Alt+Tab 并按住 Alt 时出现了一件有趣的事情 - OSK window 看起来像灰色全屏(metro-like 样式)。我不确定这是否是 parent window 的预期行为。

此外,我认为这是 window 样式的问题,但不,样式几乎相同(除了两个不相关的样式),所以我不知道如何继续。有什么想法吗?

代码:

$CSsource = @"
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Win {
    public static class API {
        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(
            string lpClassName,
            string lpWindowName
        );

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(
            IntPtr parentHwnd,
            IntPtr childAfter,
            string className,
            string windowTitle
        );

        [DllImport("user32.dll")]
        static extern bool ShowWindow(
            IntPtr hWnd,
            int nCmdShow
        );

        [DllImport("user32.dll")]
        static extern bool MoveWindow(
            IntPtr hWnd,
            int X, int Y,
            int Width, int Height,
            bool Repaint
        );

        public static void Move(
            string wClass, string wName,
            string childClass,
            int top, int left,
            int width, int height
        ) {
            IntPtr hwnd = FindWindow(wClass, wName);
            if ((int) hwnd > 0) {
                IntPtr subHwnd;
                if (childClass != String.Empty) {
                    subHwnd = FindWindowEx(hwnd, IntPtr.Zero, childClass, null);
                } else {
                    subHwnd = IntPtr.Zero;
                }

                if ((int) subHwnd > 0) {
                    MoveWindow(subHwnd, left, top, width, height + 50, true);
                    Process.Start("cmd"); //feedback from loop, heh
                } else {
                    MoveWindow(hwnd, left, top, width, height + 50, true);
                }
            }
        }
    }
}
"@

add-type -TypeDefinition $CSsource
#[Win.API]::Move('OSKMainClass', 'On-Screen Keyboard', 'DirectUIHWND', 50, 50, 200, 100)
#[Win.API]::Move('OSKMainClass', 'Accessibility On-Screen Keyboard', 'DirectUIHWND', 50, 50, 200, 100)
[Win.API]::Move('OSKMainClass', 'Accessibility On-Screen Keyboard', '', 50, 50, 200, 100)
[Win.API]::Move('Notepad', 'Untitled - Notepad', '', 50, 50, 200, 100)

OSK window 样式:

记事本window 样式:

以上+

OSK 在其清单中有 UIAccess="true",因此它以更高的完整性级别(略高于中等)运行。

要与之互动,您需要:

  1. 运行 您的应用提升了

  1. 将 UIAccess="true" 放入您的清单中
  2. 签署 .exe(This blog post 表示您可以在测试期间自行签署)
  3. 将 .exe 放在 Program Files 文件夹中的某个位置

您也可以尝试禁用 UAC 以确认是您缺少 UIAccess 的问题。