Electron 창을 드래그 가능하게 만들고 Mouse Enter/Leave 감지를 유지하는 방법
Source: Dev.to
소개
앱을 완전히 드래그 가능하게 하면서 마우스 enter와 leave 시 높이와 너비를 변경하고 싶었습니다. 기본적으로 창을 드래그 가능하게 하면 드래그 영역에서 마우스 이벤트가 무시되기 때문에 일반적인 enter/leave 감지가 깨집니다.
시각적 비교
마우스가 밖에 있을 때
마우스가 안에 있을 때
창 설정
const mainWindow = new BrowserWindow({
// width, height, x, y, etc.
titleBarStyle: 'hidden',
backgroundMaterial: "acrylic",
visualEffectState: "active",
vibrancy: "popover", // macOS
frame: false, // frameless window
});
창을 드래그 가능하게 만들기
드래그 영역으로 사용할 모든 영역에 다음 클래스를 추가합니다:
.dragAble {
-webkit-user-select: none;
-webkit-app-region: drag;
}
상호작용이 필요하도록 유지해야 하는 요소는 다음을 사용합니다:
.no-drag {
-webkit-app-region: no-drag;
}
마우스 enter와 leave 처리
Electron은 전체 창에 대한 네이티브 mouse‑enter/leave 이벤트를 제공하지 않으므로 직접 구현합니다.
1. 폴링 리스너
유틸리티가 일정 간격으로 실행되어 커서 위치를 창 경계와 비교하고 결과를 콜백에 전달합니다.
function listenToMouseMovement(callback) {
const id = setInterval(() => {
const cursor = screen.getCursorScreenPoint();
const bounds = esm.mainWindow.getBounds();
const inside =
cursor.x >= bounds.x &&
cursor.x = bounds.y &&
cursor.y {
if (esm.isMovingWindow) return; // ignore while dragging
if (inside) {
// Cancel any pending leave timeout
if (leaveTimeout) {
clearTimeout(leaveTimeout);
leaveTimeout = null;
}
if (esm.mouseWasOutsideWindow) {
// Debounce the enter event
if (!enterTimeout) {
enterTimeout = setTimeout(() => {
esm.mouseWasOutsideWindow = false;
mainWindow.webContents.send("onMouseIsInsideTheApp");
}, 120);
}
}
} else {
// Cancel any pending enter timeout
if (enterTimeout) {
clearTimeout(enterTimeout);
enterTimeout = null;
}
if (!esm.mouseWasOutsideWindow) {
// Debounce the leave event
if (!leaveTimeout) {
leaveTimeout = setTimeout(() => {
esm.mouseWasOutsideWindow = true;
mainWindow.webContents.send("onMouseIsOutsideTheApp");
}, 120);
}
}
}
});
3. 창이 이동 중일 때 마우스 체크 무시하기
Electron의 네이티브 이벤트를 사용해 창의 이동 상태를 추적합니다:
esm.mainWindow.on("will-move", () => {
esm.isMovingWindow = true;
});
esm.mainWindow.on("move", () => {
esm.isMovingWindow = true;
if (esm.moveEndTimeout) {
clearTimeout(esm.moveEndTimeout);
esm.moveEndTimeout = null;
}
});
esm.mainWindow.on("moved", () => {
if (esm.moveEndTimeout) clearTimeout(esm.moveEndTimeout);
esm.moveEndTimeout = setTimeout(() => {
esm.isMovingWindow = false;
esm.moveEndTimeout = null;
}, 200);
});
결과
이 방법은 깜빡임을 없애고 창을 완전히 드래그 가능하게 하면서도 마우스 enter와 leave 이벤트에 반응하도록 합니다. 동작 예시는 이 트윗에서 확인할 수 있습니다: (링크는 생략)
읽어 주셔서 감사합니다! 첫 번째 글이며, 앞으로 더 많은 글을 올릴 예정입니다.

