这是我正在尝试做的事情,
当用户双击鼠标选择任何正在运行应用程序中的单词(文本)时,特定高亮显示的单词应插入到已经运行的Windows应用程序中。
到目前为止,我已经使用了全局按键
实现了逻辑,其中用户必须触发CRT+C键盘键组合将所选单词复制到win表单应用程序中。
我想知道是否有任何方法可以在没有按下键盘上的任何按钮的情况下将选定文本获取到该应用程序中?
这是我正在尝试做的事情,
当用户双击鼠标选择任何正在运行应用程序中的单词(文本)时,特定高亮显示的单词应插入到已经运行的Windows应用程序中。
到目前为止,我已经使用了全局按键
实现了逻辑,其中用户必须触发CRT+C键盘键组合将所选单词复制到win表单应用程序中。
我想知道是否有任何方法可以在没有按下键盘上的任何按钮的情况下将选定文本获取到该应用程序中?
阅读一些资料后,我找到了这个方法:
GetCursorPos
from user32.dll
Get windows based on cursor position with WindowFromPoint
from
user32.dll
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(Point lpPoint);
[DllImport("user32.dll")]
public static extern bool GetCursorPos(out Point lpPoint);
public static IntPtr GetWindowUnderCursor()
{
Point ptCursor = new Point();
if (!(PInvoke.GetCursorPos(out ptCursor)))
return IntPtr.Zero;
return WindowFromPoint(ptCursor);
}
Send copy command with SendMessage
form user32.dll
(see
Using User32.dll SendMessage To Send Keys With ALT Modifier)
/// <summary>
/// This static class holds the Win32 function declarations and constants needed by
/// this sample application.
/// </summary>
internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WmDrawclipboard = 0x0308;
/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WmChangecbchain = 0x030D;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}
public void Initialize()
{
var wih = new WindowInteropHelper(this.mainWindow);
this.hWndSource = HwndSource.FromHwnd(wih.Handle);
this.globalMouseHook = Hook.GlobalEvents();
this.mainWindow.CancellationTokenSource = new CancellationTokenSource();
var source = this.hWndSource;
if (source != null)
{
source.AddHook(this.WinProc); // start processing window messages
this.hWndNextViewer = Win32.SetClipboardViewer(source.Handle); // set this window as a viewer
}
this.SubscribeLocalevents();
this.growlNotifications.Top = SystemParameters.WorkArea.Top + this.startupConfiguration.TopOffset;
this.growlNotifications.Left = SystemParameters.WorkArea.Left + SystemParameters.WorkArea.Width - this.startupConfiguration.LeftOffset;
this.IsInitialized = true;
}
鼠标事件;
private void SubscribeLocalevents()
{
this.globalMouseHook.MouseDoubleClick += async (o, args) => await this.MouseDoubleClicked(o, args);
this.globalMouseHook.MouseDown += async (o, args) => await this.MouseDown(o, args);
this.globalMouseHook.MouseUp += async (o, args) => await this.MouseUp(o, args);
}
private async Task MouseUp(object sender, MouseEventArgs e)
{
this.mouseSecondPoint = e.Location;
if (this.isMouseDown && !this.mouseSecondPoint.Equals(this.mouseFirstPoint))
{
await Task.Run(() =>
{
if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
return;
SendKeys.SendWait("^c");
});
this.isMouseDown = false;
}
this.isMouseDown = false;
}
private async Task MouseDown(object sender, MouseEventArgs e)
{
await Task.Run(() =>
{
if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
return;
this.mouseFirstPoint = e.Location;
this.isMouseDown = true;
});
}
private async Task MouseDoubleClicked(object sender, MouseEventArgs e)
{
this.isMouseDown = false;
await Task.Run(() =>
{
if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
return;
SendKeys.SendWait("^c");
});
}
最后一部分,当我们捕捉到问题时我们该怎么办,
private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WmChangecbchain:
if (wParam == this.hWndNextViewer)
this.hWndNextViewer = lParam; //clipboard viewer chain changed, need to fix it.
else if (this.hWndNextViewer != IntPtr.Zero)
Win32.SendMessage(this.hWndNextViewer, msg, wParam, lParam); //pass the message to the next viewer.
break;
case Win32.WmDrawclipboard:
Win32.SendMessage(this.hWndNextViewer, msg, wParam, lParam); //pass the message to the next viewer //clipboard content changed
if (Clipboard.ContainsText() && !string.IsNullOrEmpty(Clipboard.GetText().Trim()))
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background,
(Action)
delegate
{
var currentText = Clipboard.GetText().RemoveSpecialCharacters();
if (!string.IsNullOrEmpty(currentText))
{
//In this section, we are doing something, because TEXT IS CAPTURED.
Task.Run(
async () =>
{
if (this.mainWindow.CancellationTokenSource.Token.IsCancellationRequested)
return;
await
this.WhenClipboardContainsTextEventHandler.InvokeSafelyAsync(this,
new WhenClipboardContainsTextEventArgs { CurrentString = currentText });
});
}
});
}
break;
}
return IntPtr.Zero;
}
这个技巧是向另一个窗口或操作系统发送复制命令,而不是使用Control+C命令。因此,可以使用SendKeys.SendWait("^c");
来实现。
之前两个回答有些难以理解,而且不够详细。无论如何,非常感谢它们帮助我在尝试多次后实现了这个函数。
现在是2021年!让我们深入探讨我的详细、简单和最新的方法。
从Nuget安装MousekeyHook,它之前是globalmousekeyhook。
使用您的函数注册鼠标事件(MouseDoubleClick事件和MouseDragFinished事件,在这种情况下,您可能已选择了一些文本)。
保存剪贴板的当前内容以便稍后恢复。(可选)
清除剪贴板以确定稍后是否选择了一些文本。
通过System.Windows.Forms.SendKeys.SendWait("^c");
简单地发送Ctrl+C
命令。
获取剪贴板的内容。
如果您选择了一些文本,则可以通过System.Windows.Clipboard.GetText()
简单地获取它并进行任何操作。
如果没有选择,则恢复剪贴板。(可选)
这些是我的代码:
private IKeyboardMouseEvents globalMouseHook;
public MainWindow()
{
// Note: for the application hook, use the Hook.AppEvents() instead.
globalMouseHook = Hook.GlobalEvents();
// Bind MouseDoubleClick event with a function named MouseDoubleClicked.
globalMouseHook.MouseDoubleClick += MouseDoubleClicked;
// Bind DragFinished event with a function.
// Same as double click, so I didn't write here.
globalMouseHook.MouseDragFinished += MouseDragFinished;
}
// I make the function async to avoid GUI lags.
private async void MouseDoubleClicked(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Save clipboard's current content to restore it later.
IDataObject tmpClipboard = System.Windows.Clipboard.GetDataObject();
System.Windows.Clipboard.Clear();
// I think a small delay will be more safe.
// You could remove it, but be careful.
await Task.Delay(50);
// Send Ctrl+C, which is "copy"
System.Windows.Forms.SendKeys.SendWait("^c");
// Same as above. But this is more important.
// In some softwares like Word, the mouse double click will not select the word you clicked immediately.
// If you remove it, you will not get the text you selected.
await Task.Delay(50);
if (System.Windows.Clipboard.ContainsText())
{
string text = System.Windows.Clipboard.GetText();
// Your code
}
else
{
// Restore the Clipboard.
System.Windows.Clipboard.SetDataObject(tmpClipboard);
}
}
MouseDoubleClicked
)绑定到您的键盘事件即可。 - Even Wonder