WebView handle로 Click 이벤트를 보내는 방법
2025. 6. 4. 22:42ㆍ프로그램/C#
WebView2 핸들로 클릭 이벤트를 보내는 것의 한계 및 문제점
WebView2 컨트롤의 Handle은 해당 컨트롤이 렌더링되는 Windows 창 자체를 나타냅니다. User32.dll을 통해 이 핸들에 마우스 이벤트를 보내는 것은 운영체제 수준에서 해당 창 영역에 마우스 클릭을 시뮬레이션하는 것입니다.
그러나 다음과 같은 이유로 웹 콘텐츠 클릭에는 부적합합니다.
- 창과 콘텐츠의 분리: WebView2는 내부적으로 Edge Chromium 브라우저 엔진을 사용하여 웹 콘텐츠를 렌더링합니다. Handle에 메시지를 보내는 것은 웹뷰 컨트롤의 경계 내에서 마우스를 클릭하는 것일 뿐, 웹뷰 내부의 DOM 트리나 렌더링된 요소와 직접 상호작용하는 것이 아닙니다.
- 좌표계 불일치:
- User32 API의 마우스 이벤트는 일반적으로 스크린 좌표 또는 클라이언트 영역 좌표를 사용합니다.
- 웹뷰 내부의 HTML 요소는 CSS 픽셀 단위의 자체적인 좌표계를 가집니다.
- DPI 스케일링이 적용되면 이 둘 사이의 변환이 더욱 복잡해지고 오차가 발생하기 쉽습니다. 웹뷰가 스크롤되면 내부 요소의 상대적 위치도 변합니다.
- 안정성 및 신뢰성 부족: 웹 페이지의 레이아웃이 동적으로 변경되거나, 요소가 로드되는 타이밍이 달라지면, 특정 스크린 좌표에 보낸 클릭이 예상치 못한 다른 요소를 클릭하거나 아무것도 클릭하지 못할 수 있습니다.
- 활성화 필요: SetCursorPos나 mouse_event 같은 전역 마우스 시뮬레이션 방법을 사용하려면 대상 창이 활성화(Active)되어 있어야 합니다.
- 예상치 못한 부작용: 실제 마우스 커서가 움직이거나, 다른 애플리케이션에 영향을 줄 수 있습니다.
User32.dll을 이용한 WebView2 핸들 클릭 (권장하지 않음)
이 방법은 WebView2 내부 콘텐츠를 클릭하는 데 사용하지 않는 것이 좋지만, 기술적으로 가능함을 보여주기 위해 예시를 제공합니다.
C#
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing; // Point 등을 위해
// User32.dll 함수 선언
public static class User32
{
// 메시지 상수
public const int WM_LBUTTONDOWN = 0x0201; // 왼쪽 마우스 버튼 누름
public const int WM_LBUTTONUP = 0x0202; // 왼쪽 마우스 버튼 뗌
public const int WM_SETCURSOR = 0x0020; // 커서 설정 메시지
// 창에 메시지를 보냅니다.
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
// 창의 클라이언트 영역 좌표를 스크린 좌표로 변환합니다.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
// 스크린 커서 위치를 설정합니다. (전역 마우스 이동)
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
// 마우스 이벤트를 시뮬레이션합니다. (전역 클릭)
[DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);
public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
public const int MOUSEEVENTF_LEFTUP = 0x0004;
}
public partial class MainForm : Form
{
private Microsoft.Web.WebView2.WinForms.WebView2 webView21;
public MainForm()
{
InitializeComponent();
webView21 = new Microsoft.Web.WebView2.WinForms.WebView2();
this.Controls.Add(webView21);
webView21.Dock = DockStyle.Fill;
this.Load += MainForm_Load;
}
private async void MainForm_Load(object sender, EventArgs e)
{
await webView21.EnsureCoreWebView2Async(null);
webView21.Source = new Uri("https://www.google.com"); // 테스트 URL
// 예시를 위해 버튼 추가
Button clickButton = new Button { Text = "WebView Handle Click", Location = new Point(10, 10) };
clickButton.Click += ClickButton_Click;
this.Controls.Add(clickButton);
clickButton.BringToFront(); // 버튼이 웹뷰 위에 보이도록
}
private void ClickButton_Click(object sender, EventArgs e)
{
// WebView2 컨트롤의 핸들
IntPtr webViewHandle = webView21.Handle;
// 웹뷰 클라이언트 영역 내의 클릭할 상대 좌표 (예: 웹뷰의 중앙)
// 이 좌표가 실제 웹 콘텐츠의 어떤 요소를 클릭할지는 보장할 수 없음.
int clickX = webView21.Width / 2;
int clickY = webView21.Height / 2;
// LParam 값을 구성 (Y 좌표를 상위 16비트에, X 좌표를 하위 16비트에)
IntPtr lParam = (IntPtr)((clickY << 16) | clickX);
// 방법 1: SendMessage를 사용하여 핸들로 직접 메시지 보내기
// 이 방법은 WebView2 내부 DOM 요소에 대한 클릭을 보장하지 않습니다.
// 웹뷰 자체의 컨트롤 이벤트가 발생할 수 있습니다.
User32.SendMessage(webViewHandle, User32.WM_LBUTTONDOWN, IntPtr.Zero, lParam);
User32.SendMessage(webViewHandle, User32.WM_LBUTTONUP, IntPtr.Zero, lParam);
MessageBox.Show("WM_LBUTTONDOWN/UP 메시지를 WebView2 핸들로 보냈습니다.", "정보");
// 방법 2: 전역 커서 이동 및 마우스 이벤트 시뮬레이션 (더 비추천)
// 이 방법은 실제 마우스 커서를 움직이고 전역 클릭을 발생시킵니다.
// WebView2가 활성화되어 있어야 하고, 정확한 스크린 좌표 변환이 필요합니다.
// Point clientPoint = new Point(clickX, clickY);
// User32.ClientToScreen(webViewHandle, ref clientPoint);
// User32.SetCursorPos(clientPoint.X, clientPoint.Y);
// User32.mouse_event(User32.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
// User32.mouse_event(User32.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// MessageBox.Show("전역 마우스 클릭을 시뮬레이션했습니다.", "정보");
}
}
권장되는 방법 (재강조)
WebView2 내부의 웹 콘텐츠를 클릭하거나 조작하려면, ExecuteScriptAsync()를 사용하여 JavaScript를 주입하는 것이 가장 정확하고 강력하며 권장되는 방법입니다.
C#
// WebView2 내부에서 특정 좌표 (x, y)의 요소를 클릭하는 JavaScript 주입
private async Task ClickElementInWebView(int x, int y)
{
string script = $@"
(function() {{
const element = document.elementFromPoint({x}, {y});
if (element) {{
element.click();
return 'Clicked element at {x}, {y}';
}} else {{
return 'No element found at {x}, {y}';
}}
}})();
";
await webView21.CoreWebView2.ExecuteScriptAsync(script);
}
// 사용 예:
// await ClickElementInWebView(100, 200);
이 방법은 웹뷰의 Handle에 직접 이벤트를 보내는 것과 달리, 웹 콘텐츠의 DOM 구조와 상호작용하여 실제 사용자가 클릭한 것과 동일한 효과를 낼 수 있습니다.
'프로그램 > C#' 카테고리의 다른 글
| 이스케이프 버바텀 문자열보간 은 또 뭐야? (0) | 2025.06.04 |
|---|---|
| C# WebView21 Alert 창 직접 핸들링 하는 방법 (0) | 2025.05.28 |