From 7ef8ea5688b80e8730f2b46f4d21328a6d31b088 Mon Sep 17 00:00:00 2001 From: 110Percent Date: Sat, 23 Jun 2018 15:36:20 -0400 Subject: [PATCH] Added window close event and updated style --- examples/basic.js | 47 +++++--- index.js | 302 ++++++++++++++++++++++++---------------------- 2 files changed, 184 insertions(+), 165 deletions(-) diff --git a/examples/basic.js b/examples/basic.js index 9869955..119cf99 100644 --- a/examples/basic.js +++ b/examples/basic.js @@ -32,40 +32,47 @@ console.log("HWND of window with exact title 'File Explorer':", winctl.GetWindow // Find first window containing the string 'alc' and bring it to the foreground winctl.FindByTitle("alc").then(window => { - console.log("Title of window with title 'alc':", window.getTitle()); - // --> Title of window with title 'alc': Calculator + console.log("Title of window with title 'alc':", window.getTitle()); + // --> Title of window with title 'alc': Calculator - // Activate the window - window.setForegroundWindow(); + // Activate the window + window.setForegroundWindow(); +}).catch(err => { + console.log('Calculator is not open.') }); // Iterate over all windows with a custom filter -> show all visible windows winctl.FindWindows(win => win.isVisible() && win.getTitle()).then(windows => { - console.log("Visible windows:"); - windows.sort((a,b) => a.getTitle().localeCompare(b.getTitle())).forEach(window => console.log(" - %s [classname=%s, pid=%d, hwnd=%d, parent=%d]", window.getTitle(), window.getClassName(), window.getPid(), window.getHwnd(), window.getParent())); -}); -/* --> -Visible windows: - - Bash cpp-modules/winctl [pid=27196, hwnd=26282110, parent=NaN] - - Bash cpp-modules/winctl [pid=30696, hwnd=10357510, parent=NaN] - - Calculator [pid=6948, hwnd=5311194, parent=NaN] - - File Explorer [pid=4860, hwnd=5115324, parent=NaN] - - src [pid=4860, hwnd=219155192, parent=NaN] -*/ + console.log("Visible windows:"); + windows.sort((a, b) => a.getTitle().localeCompare(b.getTitle())).forEach(window => console.log(" - %s [classname=%s, pid=%d, hwnd=%d, parent=%d]", window.getTitle(), window.getClassName(), window.getPid(), window.getHwnd(), window.getParent())); + }).catch(err => { console.error(err) }) + /* --> + Visible windows: + - Bash cpp-modules/winctl [pid=27196, hwnd=26282110, parent=NaN] + - Bash cpp-modules/winctl [pid=30696, hwnd=10357510, parent=NaN] + - Calculator [pid=6948, hwnd=5311194, parent=NaN] + - File Explorer [pid=4860, hwnd=5115324, parent=NaN] + - src [pid=4860, hwnd=219155192, parent=NaN] + */ // Log when a new window opens or the active window changes winctl.Events.addListener("active-window", function(now, prev) { - console.log("Changed active window to: %s [prev=%s]", now.getTitle(), prev.getTitle()); + console.log("Changed active window to: %s [prev=%s]", now.getTitle(), prev.getTitle()); }); winctl.Events.addListener("open-window", function(win) { - console.log("Opened new window: %s [%d]", win.getTitle(), win.getHwnd()); + console.log("Opened new window: %s [%d]", win.getTitle(), win.getHwnd()); +}); + +winctl.Events.addListener("close-window", function(win) { + console.log("Closed window: %s [%d]", win.getTitle(), win.getHwnd()) }); // Stop listening after 5s setTimeout(() => { - winctl.Events.removeAllListeners("active-window"); - winctl.Events.removeAllListeners("open-window"); - console.log("---done---"); + winctl.Events.removeAllListeners("active-window"); + winctl.Events.removeAllListeners("open-window"); + winctl.Events.removeAllListeners("close-window"); + console.log("---done---"); }, 5000); \ No newline at end of file diff --git a/index.js b/index.js index 3890fe1..6a5b113 100644 --- a/index.js +++ b/index.js @@ -3,170 +3,182 @@ var winctl = require('bindings')('winctl'); winctl.FindWindows = function(validateFunc) { - return new Promise(resolve => { - var result = []; - winctl.EnumerateWindows(function(win) { - if(validateFunc == null || validateFunc(win)) { - result.push(win); - } - return true; - }); - - resolve(result); - }); + return new Promise(resolve => { + var result = []; + winctl.EnumerateWindows(function(win) { + if (!validateFunc || validateFunc(win)) { + result.push(win); + } + return true; + }); + + resolve(result); + }); }; winctl.FindByTitle = function(title) { - var pattern = new RegExp(title); - - var FindByTitlePromise = new Promise((resolve, reject) => { - var result = null; - winctl.EnumerateWindows(function(win) { - var title = win.getTitle(); - if(pattern.test(title)) { - result = win; - return false; - } - return true; - }); - - if(result) { - resolve(result); - } else { - reject(); - } - }); - - return FindByTitlePromise; + var pattern = new RegExp(title); + + var FindByTitlePromise = new Promise((resolve, reject) => { + var result = null; + winctl.EnumerateWindows(function(win) { + var title = win.getTitle(); + if (pattern.test(title)) { + result = win; + return false; + } + return true; + }); + + if (result) { + resolve(result); + } else { + reject(); + } + }); + + return FindByTitlePromise; }; winctl.WindowStates = { - HIDE: 0, - SHOWNORMAL: 1, - SHOWMINIMIZED: 2, - MAXIMIZE: 3, - SHOWMAXIMIZED: 3, - SHOWNOACTIVATE: 4, - SHOW: 5, - MINIMIZE: 6, - SHOWMINNOACTIVE: 7, - SHOWNA: 8, - RESTORE: 9, - SHOWDEFAULT: 10, - FORCEMINIMIZE: 11 + HIDE: 0, + SHOWNORMAL: 1, + SHOWMINIMIZED: 2, + MAXIMIZE: 3, + SHOWMAXIMIZED: 3, + SHOWNOACTIVATE: 4, + SHOW: 5, + MINIMIZE: 6, + SHOWMINNOACTIVE: 7, + SHOWNA: 8, + RESTORE: 9, + SHOWDEFAULT: 10, + FORCEMINIMIZE: 11 }; winctl.AncestorFlags = { - PARENT: 1, - ROOT: 2, - ROOTOWNER: 3 + PARENT: 1, + ROOT: 2, + ROOTOWNER: 3 }; winctl.HWND = { - NOTOPMOST: -2, - TOPMOST: -1, - TOP: 0, - BOTTOM: 1 + NOTOPMOST: -2, + TOPMOST: -1, + TOP: 0, + BOTTOM: 1 }; winctl.SWP = { - NOSIZE: 0x0001, - NOMOVE: 0x0002, - NOZORDER: 0x0004, - NOREDRAW: 0x0008, - NOACTIVATE: 0x0010, - DRAWFRAME: 0x0020, - FRAMECHANGED: 0x0020, - SHOWWINDOW: 0x0040, - HIDEWINDOW: 0x0080, - NOCOPYBITS: 0x0100, - NOOWNERZORDER: 0x0200, - NOREPOSITION: 0x0200, - NOSENDCHANGING: 0x0400, - DEFERERASE: 0x2000, - ASYNCWINDOWPOS: 0x4000 + NOSIZE: 0x0001, + NOMOVE: 0x0002, + NOZORDER: 0x0004, + NOREDRAW: 0x0008, + NOACTIVATE: 0x0010, + DRAWFRAME: 0x0020, + FRAMECHANGED: 0x0020, + SHOWWINDOW: 0x0040, + HIDEWINDOW: 0x0080, + NOCOPYBITS: 0x0100, + NOOWNERZORDER: 0x0200, + NOREPOSITION: 0x0200, + NOSENDCHANGING: 0x0400, + DEFERERASE: 0x2000, + ASYNCWINDOWPOS: 0x4000 }; const EventEmitter = require('events'); class WindowEventsEmitter extends EventEmitter { - constructor() { - super(); - - this.activeWindow = winctl.GetActiveWindow(); - this.existingWindows = null; - - this.eventLoops = { - "active-window": { - func: this.checkActiveWindow.bind(this), - events: ["active-window"], - interval: 50 - }, - "window-list": { - func: this.checkNewWindow.bind(this), - events: ["open-window", "close-window"], - interval: 50 - } - }; - } - - addListener(evt, listener) { - super.addListener(evt, listener); - this.updatePollingLoops(); - } - - removeAllListeners(evt) { - super.removeAllListeners(evt); - this.updatePollingLoops(); - } - - removeListener(evt, listener) { - super.removeListeners(evt, listener); - this.updatePollingLoops(); - } - - updatePollingLoops() { - Object.keys(this.eventLoops).forEach(loopName => { - var props = this.eventLoops[loopName]; - - var listenerCount = props.events.reduce((prev, curr) => prev + this.listenerCount(curr), 0); - if(listenerCount > 0 && props.id == null) { - props.id = setInterval(props.func, props.interval); - } else if(listenerCount == 0 && props.id != null) { - clearInterval(props.id); - props.id = null; - } - }); - } - - checkActiveWindow() { - var currentWindow = winctl.GetActiveWindow(); - if(currentWindow.getHwnd() != this.activeWindow.getHwnd()) { - this.emit("active-window", currentWindow, this.activeWindow); - this.activeWindow = currentWindow; - } - } - - checkNewWindow() { - var isFirst = false; - if(this.existingWindows == null) { - isFirst = true; - this.existingWindows = {}; - } - - winctl.FindWindows(win => win.isVisible() && win.getTitle()).then(windows => { - windows.forEach(window => { - if(this.existingWindows[window.getHwnd()] == null) { - // New window - this.existingWindows[window.getHwnd()] = true; - if(!isFirst) { - this.emit("open-window", window); - } - } - }); - - - }); - } + constructor() { + super(); + + this.activeWindow = winctl.GetActiveWindow(); + this.existingWindows = null; + + this.eventLoops = { + 'active-window': { + func: this.checkActiveWindow.bind(this), + events: ['active-window'], + interval: 50 + }, + 'window-list': { + func: this.checkNewWindow.bind(this), + events: ['open-window', 'close-window'], + interval: 50 + } + }; + } + + addListener(evt, listener) { + super.addListener(evt, listener); + this.updatePollingLoops(); + } + + removeAllListeners(evt) { + super.removeAllListeners(evt); + this.updatePollingLoops(); + } + + removeListener(evt, listener) { + super.removeListeners(evt, listener); + this.updatePollingLoops(); + } + + updatePollingLoops() { + Object.keys(this.eventLoops).forEach(loopName => { + var props = this.eventLoops[loopName]; + + var listenerCount = props.events.reduce((prev, curr) => prev + this.listenerCount(curr), 0); + if (listenerCount > 0 && !props.id) { + props.id = setInterval(props.func, props.interval); + } else if (listenerCount === 0 && props.id) { + clearInterval(props.id); + props.id = null; + } + }); + } + + checkActiveWindow() { + var currentWindow = winctl.GetActiveWindow(); + if (currentWindow.getHwnd() != this.activeWindow.getHwnd()) { + this.emit('active-window', currentWindow, this.activeWindow); + this.activeWindow = currentWindow; + } + } + + checkNewWindow() { + var isFirst = false; + if (!this.existingWindows) { + isFirst = true; + this.existingWindows = {}; + } + + let currentWins = {}; + winctl.FindWindows(win => win.isVisible() && win.getTitle()).then(windows => { + windows.forEach(w => { + currentWins[w.getHwnd()] = w; + if (!this.existingWindows[w.getHwnd()]) { + // New window + this.existingWindows[w.getHwnd()] = w; + if (!isFirst) { + this.emit('open-window', w); + } + } + }) + if (!isFirst) { + for (let winT in this.existingWindows) { + let exWin = this.existingWindows[winT]; + if (!currentWins[exWin.getHwnd()] && exWin.getTitle()) { + // Window was closed + delete this.existingWindows[winT]; + this.emit('close-window', exWin); + } + } + } + }).catch(err => { + console.error(err); + }) + } } winctl.Events = new WindowEventsEmitter();