diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0e048a5..068d20d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,8 +15,6 @@ jobs: matrix: node-version: - 18 - - 16 - - 14 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 39be5f7..be1b16a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,6 @@ jobs: - x64 node: - 18 - - 14 - - 16 include: - os: windows-latest node: 18 diff --git a/Package.swift b/Package.swift index 6dfcc66..51a4218 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.9 import PackageDescription let package = Package( diff --git a/index.d.ts b/index.d.ts index f2f360a..036cf7c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,168 +1,162 @@ -declare namespace activeWindow { - interface Options { - /** - Enable the accessibility permission check. _(macOS)_ - - Setting this to `false` will prevent the accessibility permission prompt on macOS versions 10.15 and newer. The `url` property won't be retrieved. - - @default true - */ - readonly accessibilityPermission: boolean; - - /** - Enable the screen recording permission check. _(macOS)_ +export type Options = { + /** + Enable the accessibility permission check. _(macOS)_ - Setting this to `false` will prevent the screen recording permission prompt on macOS versions 10.15 and newer. The `title` property in the result will always be set to an empty string. + Setting this to `false` will prevent the accessibility permission prompt on macOS versions 10.15 and newer. The `url` property won't be retrieved. - @default true - */ - readonly screenRecordingPermission: boolean; - } + @default true + */ + readonly accessibilityPermission: boolean; - interface BaseOwner { - /** - Name of the app. - */ - name: string; - - /** - Process identifier - */ - processId: number; - - /** - Path to the app. - */ - path: string; - } + /** + Enable the screen recording permission check. _(macOS)_ - interface BaseResult { - /** - Window title. - */ - title: string; - - /** - Window identifier. - - On Windows, there isn't a clear notion of a "Window ID". Instead it returns the memory address of the window "handle" in the `id` property. That "handle" is unique per window, so it can be used to identify them. [Read more…](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632597(v=vs.85).aspx#window_handle). - */ - id: number; - - /** - Window position and size. - */ - bounds: { - x: number; - y: number; - width: number; - height: number; - }; - - /** - App that owns the window. - */ - owner: BaseOwner; - - /** - Memory usage by the window. - */ - memoryUsage: number; - } + Setting this to `false` will prevent the screen recording permission prompt on macOS versions 10.15 and newer. The `title` property in the result will always be set to an empty string. - interface MacOSOwner extends BaseOwner { - /** - Bundle identifier. - */ - bundleId: string; - } + @default true + */ + readonly screenRecordingPermission: boolean; +}; - interface MacOSResult extends BaseResult { - platform: 'macos'; +export type BaseOwner = { + /** + Name of the app. + */ + name: string; - owner: MacOSOwner; + /** + Process identifier + */ + processId: number; - /** - URL of the active browser tab if the active window is Safari (includes Technology Preview), Chrome (includes Beta, Dev, and Canary), Edge (includes Beta, Dev, and Canary), Brave (includes Beta and Nightly), Mighty, Ghost Browser, WaveBox, Sidekick, Opera (includes Beta and Developer), or Vivaldi. - */ - url?: string; - } + /** + Path to the app. + */ + path: string; +}; - interface LinuxResult extends BaseResult { - platform: 'linux'; - } +export type BaseResult = { + /** + Window title. + */ + title: string; - interface WindowsResult extends BaseResult { - platform: 'windows'; - } + /** + Window identifier. - type Result = MacOSResult | LinuxResult | WindowsResult; -} + On Windows, there isn't a clear notion of a "Window ID". Instead it returns the memory address of the window "handle" in the `id` property. That "handle" is unique per window, so it can be used to identify them. [Read more…](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632597(v=vs.85).aspx#window_handle). + */ + id: number; -declare const activeWindow: { /** - Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) (title, id, bounds, owner, etc). - - @example - ``` - import activeWindow = require('active-win'); - - (async () => { - const result = await activeWindow(); - - if (!result) { - return; - } - - if (result.platform === 'macos') { - // Among other fields, result.owner.bundleId is available on macOS. - console.log(`Process title is ${result.title} with bundle id ${result.owner.bundleId}.`); - } else if (result.platform === 'windows') { - console.log(`Process title is ${result.title} with path ${result.owner.path}.`); - } else { - console.log(`Process title is ${result.title} with path ${result.owner.path}.`); - } - })(); - ``` + Window position and size. */ - (options?: activeWindow.Options): Promise; + bounds: { + x: number; + y: number; + width: number; + height: number; + }; /** - Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) synchronously (title, id, bounds, owner, etc). - - @example - ``` - import activeWindow = require('active-win'); - - const result = activeWindow.sync(); - - if (result) { - if (result.platform === 'macos') { - // Among other fields, result.owner.bundleId is available on macOS. - console.log(`Process title is ${result.title} with bundle id ${result.owner.bundleId}.`); - } else if (result.platform === 'windows') { - console.log(`Process title is ${result.title} with path ${result.owner.path}.`); - } else { - console.log(`Process title is ${result.title} with path ${result.owner.path}.`); - } - } - ``` + App that owns the window. */ - sync(options?: activeWindow.Options): activeWindow.Result | undefined; + owner: BaseOwner; /** - Get metadata about all open windows. - - Windows are returned in order from front to back. + Memory usage by the window. */ - getOpenWindows(options?: activeWindow.Options): Promise; + memoryUsage: number; +}; +// eslint-disable-next-line @typescript-eslint/naming-convention +export type MacOSOwner = { /** - Get metadata about all open windows synchronously. + Bundle identifier. + */ + bundleId: string; +} & BaseOwner; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export type MacOSResult = { + platform: 'macos'; - Windows are returned in order from front to back. + owner: MacOSOwner; + + /** + URL of the active browser tab if the active window is Safari (includes Technology Preview), Chrome (includes Beta, Dev, and Canary), Edge (includes Beta, Dev, and Canary), Brave (includes Beta and Nightly), Mighty, Ghost Browser, WaveBox, Sidekick, Opera (includes Beta and Developer), or Vivaldi. */ - getOpenWindowsSync(options?: activeWindow.Options): activeWindow.Result[]; -}; + url?: string; +} & BaseResult; + +export type LinuxResult = { + platform: 'linux'; +} & BaseResult; + +export type WindowsResult = { + platform: 'windows'; +} & BaseResult; + +export type Result = MacOSResult | LinuxResult | WindowsResult; + +/** +Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) (title, id, bounds, owner, etc). + +@example +``` +import {activeWindow} from 'active-win'; + +const result = await activeWindow(); + +if (!result) { + return; +} + +if (result.platform === 'macos') { + // Among other fields, `result.owner.bundleId` is available on macOS. + console.log(`Process title is ${result.title} with bundle id ${result.owner.bundleId}.`); +} else if (result.platform === 'windows') { + console.log(`Process title is ${result.title} with path ${result.owner.path}.`); +} else { + console.log(`Process title is ${result.title} with path ${result.owner.path}.`); +} +``` +*/ +export function activeWindow(options?: Options): Promise; + +/** +Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) synchronously (title, id, bounds, owner, etc). + +@example +``` +import {activeWindowSync} from 'active-win'; + +const result = activeWindowSync(); + +if (result) { + if (result.platform === 'macos') { + // Among other fields, `result.owner.bundleId` is available on macOS. + console.log(`Process title is ${result.title} with bundle id ${result.owner.bundleId}.`); + } else if (result.platform === 'windows') { + console.log(`Process title is ${result.title} with path ${result.owner.path}.`); + } else { + console.log(`Process title is ${result.title} with path ${result.owner.path}.`); + } +} +``` +*/ +export function activeWindowSync(options?: Options): Result | undefined; + +/** +Get metadata about all open windows. + +Windows are returned in order from front to back. +*/ +export function openWindows(options?: Options): Promise; + +/** +Get metadata about all open windows synchronously. -export = activeWindow; +Windows are returned in order from front to back. +*/ +export function openWindowsSync(options?: Options): Result[]; diff --git a/index.js b/index.js index 8c0e023..dd25ebb 100644 --- a/index.js +++ b/index.js @@ -1,65 +1,85 @@ -'use strict'; - -module.exports = options => { +import process from 'node:process'; +import { + activeWindowSync as activeWindowSyncMacOS, + openWindowsSync as openWindowsSyncMacOS, +} from './lib/macos.js'; +import { + activeWindowSync as activeWindowSyncLinux, + openWindowsSync as openWindowsSyncLinux, +} from './lib/linux.js'; +import { + activeWindowSync as activeWindowSyncWindows, + openWindowsSync as openWindowsSyncWindows, +} from './lib/windows.js'; + +export async function activeWindow(options) { if (process.platform === 'darwin') { - return require('./lib/macos.js')(options); + const {activeWindow} = await import('./lib/macos.js'); + return activeWindow(options); } if (process.platform === 'linux') { - return require('./lib/linux.js')(options); + const {activeWindow} = await import('./lib/linux.js'); + return activeWindow(options); } if (process.platform === 'win32') { - return require('./lib/windows.js')(options); + const {activeWindow} = await import('./lib/windows.js'); + return activeWindow(options); } - return Promise.reject(new Error('macOS, Linux, and Windows only')); -}; + throw new Error('macOS, Linux, and Windows only'); +} -module.exports.sync = options => { +export function activeWindowSync(options) { if (process.platform === 'darwin') { - return require('./lib/macos.js').sync(options); + return activeWindowSyncMacOS(options); } if (process.platform === 'linux') { - return require('./lib/linux.js').sync(options); + return activeWindowSyncLinux(options); } if (process.platform === 'win32') { - return require('./lib/windows.js').sync(options); + return activeWindowSyncWindows(options); } throw new Error('macOS, Linux, and Windows only'); -}; +} -module.exports.getOpenWindows = options => { +export async function openWindows(options) { if (process.platform === 'darwin') { - return require('./lib/macos.js').getOpenWindows(options); + const {openWindows} = await import('./lib/macos.js'); + return openWindows(options); } if (process.platform === 'linux') { - return require('./lib/linux.js').getOpenWindows(options); + const {openWindows} = await import('./lib/linux.js'); + return openWindows(options); } if (process.platform === 'win32') { - return require('./lib/windows.js').getOpenWindows(options); + const {openWindows} = await import('./lib/windows.js'); + return openWindows(options); } - return Promise.reject(new Error('macOS, Linux, and Windows only')); -}; + throw new Error('macOS, Linux, and Windows only'); +} -module.exports.getOpenWindowsSync = options => { +export function openWindowsSync(options) { if (process.platform === 'darwin') { - return require('./lib/macos.js').getOpenWindowsSync(options); + return openWindowsSyncMacOS(options); } if (process.platform === 'linux') { - return require('./lib/linux.js').getOpenWindowsSync(options); + return openWindowsSyncLinux(options); } if (process.platform === 'win32') { - return require('./lib/windows.js').getOpenWindowsSync(options); + return openWindowsSyncWindows(options); } throw new Error('macOS, Linux, and Windows only'); -}; +} + +// Note to self: The `main` field in package.json is requried for pre-gyp. diff --git a/index.test-d.ts b/index.test-d.ts index 4065154..1021d7e 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,12 +1,21 @@ import {expectType, expectError} from 'tsd'; -import activeWindow = require('./index.js'); -import {Result, LinuxResult, MacOSResult, WindowsResult, BaseOwner} from './index.js'; +import { + activeWindow, + activeWindowSync, + openWindows, + openWindowsSync, + type Result, + type LinuxResult, + type MacOSResult, + type WindowsResult, + BaseOwner, +} from './index.js'; expectType>(activeWindow()); -const result = activeWindow.sync({ +const result = activeWindowSync({ screenRecordingPermission: false, - accessibilityPermission: false + accessibilityPermission: false, }); expectType(result); diff --git a/lib/linux.js b/lib/linux.js index 2386bfd..7acdd57 100644 --- a/lib/linux.js +++ b/lib/linux.js @@ -1,17 +1,17 @@ -'use strict'; -const {promisify} = require('util'); -const fs = require('fs'); -const childProcess = require('child_process'); +import process from 'node:process'; +import {promisify} from 'node:util'; +import fs from 'node:fs'; +import childProcess from 'node:child_process'; const execFile = promisify(childProcess.execFile); const readFile = promisify(fs.readFile); const readlink = promisify(fs.readlink); -const xpropBin = 'xprop'; -const xwininfoBin = 'xwininfo'; -const xpropActiveArgs = ['-root', '\t$0', '_NET_ACTIVE_WINDOW']; -const xpropOpenArgs = ['-root', '_NET_CLIENT_LIST_STACKING']; -const xpropDetailsArgs = ['-id']; +const xpropBinary = 'xprop'; +const xwininfoBinary = 'xwininfo'; +const xpropActiveArguments = ['-root', '\t$0', '_NET_ACTIVE_WINDOW']; +const xpropOpenArguments = ['-root', '_NET_CLIENT_LIST_STACKING']; +const xpropDetailsArguments = ['-id']; const processOutput = output => { const result = {}; @@ -35,8 +35,8 @@ const parseLinux = ({stdout, boundsStdout, activeWindowId}) => { const windowIdProperty = 'WM_CLIENT_LEADER(WINDOW)'; const resultKeys = Object.keys(result); - const windowId = (resultKeys.indexOf(windowIdProperty) > 0 && - Number.parseInt(result[windowIdProperty].split('#').pop(), 16)) || activeWindowId; + const windowId = (resultKeys.indexOf(windowIdProperty) > 0 + && Number.parseInt(result[windowIdProperty].split('#').pop(), 16)) || activeWindowId; const processId = Number.parseInt(result['_NET_WM_PID(CARDINAL)'], 10); @@ -50,14 +50,14 @@ const parseLinux = ({stdout, boundsStdout, activeWindowId}) => { id: windowId, owner: { name: JSON.parse(result['WM_CLASS(STRING)'].split(',').pop()), - processId + processId, }, bounds: { x: Number.parseInt(bounds['Absolute upper-left X'], 10), y: Number.parseInt(bounds['Absolute upper-left Y'], 10), width: Number.parseInt(bounds.Width, 10), - height: Number.parseInt(bounds.Height, 10) - } + height: Number.parseInt(bounds.Height, 10), + }, }; }; @@ -69,13 +69,11 @@ const getMemoryUsageByPid = async pid => { }; const getMemoryUsageByPidSync = pid => { - const statm = require('fs').readFileSync(`/proc/${pid}/statm`, 'utf8'); + const statm = fs.readFileSync(`/proc/${pid}/statm`, 'utf8'); return Number.parseInt(statm.split(' ')[1], 10) * 4096; }; -const getPathByPid = pid => { - return readlink(`/proc/${pid}/exe`); -}; +const getPathByPid = pid => readlink(`/proc/${pid}/exe`); const getPathByPidSync = pid => { try { @@ -85,18 +83,18 @@ const getPathByPidSync = pid => { async function getWindowInformation(windowId) { const [{stdout}, {stdout: boundsStdout}] = await Promise.all([ - execFile(xpropBin, [...xpropDetailsArgs, windowId], {env: {...process.env, LC_ALL: 'C.utf8'}}), - execFile(xwininfoBin, [...xpropDetailsArgs, windowId]) + execFile(xpropBinary, [...xpropDetailsArguments, windowId], {env: {...process.env, LC_ALL: 'C.utf8'}}), + execFile(xwininfoBinary, [...xpropDetailsArguments, windowId]), ]); const data = parseLinux({ activeWindowId: windowId, boundsStdout, - stdout + stdout, }); const [memoryUsage, path] = await Promise.all([ getMemoryUsageByPid(data.owner.processId), - getPathByPid(data.owner.processId).catch(() => {}) + getPathByPid(data.owner.processId).catch(() => {}), ]); data.memoryUsage = memoryUsage; data.owner.path = path; @@ -104,22 +102,22 @@ async function getWindowInformation(windowId) { } function getWindowInformationSync(windowId) { - const stdout = childProcess.execFileSync(xpropBin, [...xpropDetailsArgs, windowId], {encoding: 'utf8', env: {...process.env, LC_ALL: 'C.utf8'}}); - const boundsStdout = childProcess.execFileSync(xwininfoBin, [...xpropDetailsArgs, windowId], {encoding: 'utf8'}); + const stdout = childProcess.execFileSync(xpropBinary, [...xpropDetailsArguments, windowId], {encoding: 'utf8', env: {...process.env, LC_ALL: 'C.utf8'}}); + const boundsStdout = childProcess.execFileSync(xwininfoBinary, [...xpropDetailsArguments, windowId], {encoding: 'utf8'}); const data = parseLinux({ activeWindowId: windowId, boundsStdout, - stdout + stdout, }); data.memoryUsage = getMemoryUsageByPidSync(data.owner.processId); data.owner.path = getPathByPidSync(data.owner.processId); return data; } -module.exports = async () => { +export async function activeWindow() { try { - const {stdout: activeWindowIdStdout} = await execFile(xpropBin, xpropActiveArgs); + const {stdout: activeWindowIdStdout} = await execFile(xpropBinary, xpropActiveArguments); const activeWindowId = getActiveWindowId(activeWindowIdStdout); if (!activeWindowId) { @@ -130,11 +128,11 @@ module.exports = async () => { } catch { return undefined; } -}; +} -module.exports.sync = () => { +export function activeWindowSync() { try { - const activeWindowIdStdout = childProcess.execFileSync(xpropBin, xpropActiveArgs, {encoding: 'utf8'}); + const activeWindowIdStdout = childProcess.execFileSync(xpropBinary, xpropActiveArguments, {encoding: 'utf8'}); const activeWindowId = getActiveWindowId(activeWindowIdStdout); if (!activeWindowId) { @@ -145,11 +143,12 @@ module.exports.sync = () => { } catch { return undefined; } -}; +} -module.exports.getOpenWindows = async () => { +export async function openWindows() { try { - const {stdout: openWindowIdStdout} = await execFile(xpropBin, xpropOpenArgs); + const {stdout: openWindowIdStdout} = await execFile(xpropBinary, xpropOpenArguments); + // Get open windows Ids const windowsIds = openWindowIdStdout.split('#')[1].trim().replace('\n', '').split(','); @@ -167,11 +166,11 @@ module.exports.getOpenWindows = async () => { } catch { return undefined; } -}; +} -module.exports.getOpenWindowsSync = () => { +export function openWindowsSync() { try { - const openWindowIdStdout = childProcess.execFileSync(xpropBin, xpropOpenArgs, {encoding: 'utf8'}); + const openWindowIdStdout = childProcess.execFileSync(xpropBinary, xpropOpenArguments, {encoding: 'utf8'}); const windowsIds = openWindowIdStdout.split('#')[1].trim().replace('\n', '').split(','); if (!windowsIds || windowsIds.length === 0) { @@ -190,4 +189,4 @@ module.exports.getOpenWindowsSync = () => { console.log(error); return undefined; } -}; +} diff --git a/lib/macos.js b/lib/macos.js index 9a5bb1a..7110488 100644 --- a/lib/macos.js +++ b/lib/macos.js @@ -1,10 +1,12 @@ -'use strict'; -const path = require('path'); -const {promisify} = require('util'); -const childProcess = require('child_process'); +import path from 'node:path'; +import {promisify} from 'node:util'; +import childProcess from 'node:child_process'; +import {fileURLToPath} from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); const execFile = promisify(childProcess.execFile); -const bin = path.join(__dirname, '../main'); +const binary = path.join(__dirname, '../main'); const parseMac = stdout => { try { @@ -20,34 +22,34 @@ const getArguments = options => { return []; } - const args = []; + const arguments_ = []; if (options.accessibilityPermission === false) { - args.push('--no-accessibility-permission'); + arguments_.push('--no-accessibility-permission'); } if (options.screenRecordingPermission === false) { - args.push('--no-screen-recording-permission'); + arguments_.push('--no-screen-recording-permission'); } - return args; + return arguments_; }; -module.exports = async options => { - const {stdout} = await execFile(bin, getArguments(options)); +export async function activeWindow(options) { + const {stdout} = await execFile(binary, getArguments(options)); return parseMac(stdout); -}; +} -module.exports.sync = options => { - const stdout = childProcess.execFileSync(bin, getArguments(options), {encoding: 'utf8'}); +export function activeWindowSync(options) { + const stdout = childProcess.execFileSync(binary, getArguments(options), {encoding: 'utf8'}); return parseMac(stdout); -}; +} -module.exports.getOpenWindows = async options => { - const {stdout} = await execFile(bin, [...getArguments(options), '--open-windows-list']); +export async function openWindows(options) { + const {stdout} = await execFile(binary, [...getArguments(options), '--open-windows-list']); return parseMac(stdout); -}; +} -module.exports.getOpenWindowsSync = options => { - const stdout = childProcess.execFileSync(bin, [...getArguments(options), '--open-windows-list'], {encoding: 'utf8'}); +export function openWindowsSync(options) { + const stdout = childProcess.execFileSync(binary, [...getArguments(options), '--open-windows-list'], {encoding: 'utf8'}); return parseMac(stdout); -}; +} diff --git a/lib/windows-binding.js b/lib/windows-binding.js deleted file mode 100644 index 81f9506..0000000 --- a/lib/windows-binding.js +++ /dev/null @@ -1,12 +0,0 @@ -const binary = require('@mapbox/node-pre-gyp'); -const path = require('path'); -const fs = require('fs'); - -const bindingPath = binary.find(path.resolve(path.join(__dirname, '../package.json'))); - -const binding = (fs.existsSync(bindingPath)) ? require(bindingPath) : { - getActiveWindow: () => {}, - getOpenWindows: () => {} -}; - -module.exports = binding; diff --git a/lib/windows.js b/lib/windows.js index 8d01f7d..b040c74 100644 --- a/lib/windows.js +++ b/lib/windows.js @@ -1,9 +1,32 @@ -const addon = require('./windows-binding.js'); +import path from 'node:path'; +import fs from 'node:fs'; +import {fileURLToPath} from 'node:url'; +import {createRequire} from 'node:module'; +import preGyp from '@mapbox/node-pre-gyp'; -module.exports = async () => addon.getActiveWindow(); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); -module.exports.getOpenWindows = async () => addon.getOpenWindows(); +const require = createRequire(import.meta.url); -module.exports.sync = addon.getActiveWindow; +const bindingPath = preGyp.find(path.resolve(path.join(__dirname, '../package.json'))); -module.exports.getOpenWindowsSync = addon.getOpenWindows; +const addon = (fs.existsSync(bindingPath)) ? require(bindingPath) : { + getActiveWindow() {}, + getOpenWindows() {}, +}; + +export async function activeWindow() { + return addon.getActiveWindow(); +} + +export function activeWindowSync() { + return addon.getActiveWindow(); +} + +export function openWindows() { + return addon.getOpenWindows(); +} + +export function openWindowsSync() { + return addon.getOpenWindows(); +} diff --git a/package.json b/package.json index 0085c79..f954639 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "active-win", "version": "8.2.1", - "description": "Get metadata about the active window (title, id, bounds, owner, URL, etc)", + "description": "Get metadata about the active window and open windows (title, id, bounds, owner, URL, etc)", "license": "MIT", "repository": { "type": "git", @@ -13,12 +13,16 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "main": "./index.js", "sideEffects": false, "engines": { - "node": ">=14" + "node": ">=18.18" }, - "main": "./index", - "types": "./index.d.ts", "binary": { "module_name": "node-active-win", "module_path": "./lib/binding/napi-{napi_build_version}-{platform}-{libc}-{arch}", @@ -26,8 +30,7 @@ "remote_path": "v{version}", "package_name": "napi-{napi_build_version}-{platform}-{libc}-{arch}.tar.gz", "napi_versions": [ - 3, - 6 + 9 ] }, "scripts": { @@ -54,10 +57,11 @@ "app", "application", "window", - "win", + "windows", "active", "focused", "current", + "open", "title", "name", "id", @@ -77,25 +81,22 @@ "brave" ], "devDependencies": { - "ava": "^2.4.0", - "tsd": "^0.14.0", - "xo": "^0.38.2", + "ava": "^6.1.2", + "tsd": "^0.31.0", + "xo": "^0.58.0", "node-pre-gyp-github": "^1.4.4" }, "optionalDependencies": { - "@mapbox/node-pre-gyp": "^1.0.10", - "node-addon-api": "^5.0.0", - "node-gyp": "^9.3.0" + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^8.0.0", + "node-gyp": "^10.1.0" }, "peerDependencies": { - "node-gyp": "^9.3.0" + "node-gyp": "^10.1.0" }, "peerDependenciesMeta": { "node-gyp": { "optional": true } - }, - "ava": { - "verbose": true } } diff --git a/readme.md b/readme.md index d6da80a..f5644d0 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # active-win -Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) (title, id, bounds, owner, URL, etc) +> Get metadata about the [active window](https://en.wikipedia.org/wiki/Active_window) and open windows (title, id, bounds, owner, URL, etc) Works on macOS 10.14+, Linux ([note](#linux-support)), and Windows 7+. @@ -10,34 +10,34 @@ Works on macOS 10.14+, Linux ([note](#linux-support)), and Windows 7+. npm install active-win ``` +**[This is an ESM package which requires you to use ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)** + ## Usage ```js -const activeWindow = require('active-win'); - -(async () => { - console.log(await activeWindow(options)); - /* - { - title: 'Unicorns - Google Search', - id: 5762, - bounds: { - x: 0, - y: 0, - height: 900, - width: 1440 - }, - owner: { - name: 'Google Chrome', - processId: 310, - bundleId: 'com.google.Chrome', - path: '/Applications/Google Chrome.app' - }, - url: 'https://sindresorhus.com/unicorn', - memoryUsage: 11015432 - } - */ -})(); +import {activeWindow} from 'active-win'; + +console.log(await activeWindow(options)); +/* +{ + title: 'Unicorns - Google Search', + id: 5762, + bounds: { + x: 0, + y: 0, + height: 900, + width: 1440 + }, + owner: { + name: 'Google Chrome', + processId: 310, + bundleId: 'com.google.Chrome', + path: '/Applications/Google Chrome.app' + }, + url: 'https://sindresorhus.com/unicorn', + memoryUsage: 11015432 +} +*/ ``` ## API @@ -64,7 +64,7 @@ Default: `true` Enable the screen recording permission check. Setting this to `false` will prevent the screen recording permission prompt on macOS versions 10.15 and newer. The `title` property in the result will always be set to an empty string. -### activeWindow.sync(options?) +### activeWindowSync(options?) Get metadata about the active window synchronously. @@ -89,21 +89,21 @@ Returns a `Promise` with the result, or `Promise` if there is - Supported browsers: Safari (includes Technology Preview), Chrome (includes Beta, Dev, and Canary), Edge (includes Beta, Dev, and Canary), Brave (includes Beta and Nightly), Mighty, Ghost Browser, Wavebox, Sidekick, Opera (includes Beta and Developer), or Vivaldi - `memoryUsage` *(number)* - Memory usage by the window owner process -### activeWindow.getOpenWindows() +### openWindows() Get metadata about all open windows. Windows are returned in order from front to back. -Returns `Promise`. +Returns `Promise`. -### activeWindow.getOpenWindowsSync() +### openWindowsSync() Get metadata about all open windows synchronously. Windows are returned in order from front to back. -Returns `activeWindow.Result[]`. +Returns `Result[]`. ## OS support diff --git a/test.js b/test.js index 5b8bd31..e2e9c16 100644 --- a/test.js +++ b/test.js @@ -1,6 +1,11 @@ import {inspect} from 'node:util'; import test from 'ava'; -import activeWindow from './index.js'; +import { + activeWindow, + activeWindowSync, + openWindows, + openWindowsSync, +} from './index.js'; function asserter(t, result) { t.log(inspect(result)); @@ -11,7 +16,7 @@ function asserter(t, result) { t.is(typeof result.owner.name, 'string'); } -function asserterGetOpenWindows(t, result) { +function asserterOpenWindows(t, result) { t.log(inspect(result)); t.is(typeof result, 'object'); t.is(typeof result.length, 'number'); @@ -22,14 +27,14 @@ test('activeWindow', async t => { asserter(t, await activeWindow()); }); -test('activeWindow.sync', t => { - asserter(t, activeWindow.sync()); +test('activeWindowSync', t => { + asserter(t, activeWindowSync()); }); -test('activeWindow.getOpenWindows', async t => { - asserterGetOpenWindows(t, await activeWindow.getOpenWindows()); +test('openWindows', async t => { + asserterOpenWindows(t, await openWindows()); }); -test('activeWindow.getOpenWindowsSync', t => { - asserterGetOpenWindows(t, activeWindow.getOpenWindowsSync()); +test('openWindowsSync', t => { + asserterOpenWindows(t, openWindowsSync()); });