diff --git a/api-samples/commands/README.md b/api-samples/commands/README.md new file mode 100644 index 00000000..8e186a33 --- /dev/null +++ b/api-samples/commands/README.md @@ -0,0 +1,13 @@ +# chrome.commands + +This sample demonstrates the [`chrome.commands`](https://developer.chrome.com/docs/extensions/reference/api/commands) API by defining custom keyboard shortcuts and responding to command events. + +## Overview + +The extension registers two custom keyboard shortcuts in the manifest and listens for them using `chrome.commands.onCommand`. One command shows a notification, the other toggles a feature on and off with badge text feedback. The popup uses `chrome.commands.getAll()` to display all registered shortcuts and their current key bindings. + +## Running this extension + +1. Clone this repository. +2. Load this directory in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +3. Use the keyboard shortcuts shown in the popup or customize them at `chrome://extensions/shortcuts`. diff --git a/api-samples/commands/background.js b/api-samples/commands/background.js new file mode 100644 index 00000000..a919c1a3 --- /dev/null +++ b/api-samples/commands/background.js @@ -0,0 +1,41 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +let featureEnabled = false; + +chrome.commands.onCommand.addListener(async (command) => { + if (command === 'run-action') { + chrome.notifications.create({ + type: 'basic', + iconUrl: 'images/icon-128.png', + title: 'Commands API Demo', + message: 'The "run-action" command was triggered.' + }); + } + + if (command === 'toggle-feature') { + featureEnabled = !featureEnabled; + const state = featureEnabled ? 'ON' : 'OFF'; + + chrome.action.setBadgeText({ text: featureEnabled ? 'ON' : '' }); + chrome.action.setBadgeBackgroundColor({ color: '#4688F1' }); + + chrome.notifications.create({ + type: 'basic', + iconUrl: 'images/icon-128.png', + title: 'Feature Toggled', + message: `The feature is now ${state}.` + }); + } +}); diff --git a/api-samples/commands/images/icon-128.png b/api-samples/commands/images/icon-128.png new file mode 100644 index 00000000..58cd488f Binary files /dev/null and b/api-samples/commands/images/icon-128.png differ diff --git a/api-samples/commands/images/icon-16.png b/api-samples/commands/images/icon-16.png new file mode 100644 index 00000000..50cc8cfa Binary files /dev/null and b/api-samples/commands/images/icon-16.png differ diff --git a/api-samples/commands/images/icon-48.png b/api-samples/commands/images/icon-48.png new file mode 100644 index 00000000..18dcf3fe Binary files /dev/null and b/api-samples/commands/images/icon-48.png differ diff --git a/api-samples/commands/manifest.json b/api-samples/commands/manifest.json new file mode 100644 index 00000000..c9e22af3 --- /dev/null +++ b/api-samples/commands/manifest.json @@ -0,0 +1,39 @@ +{ + "name": "Commands API Demo", + "version": "1.0", + "description": "Uses the chrome.commands API to define keyboard shortcuts and handle command events.", + "manifest_version": 3, + "background": { + "service_worker": "background.js" + }, + "permissions": ["notifications"], + "icons": { + "16": "images/icon-16.png", + "48": "images/icon-48.png", + "128": "images/icon-128.png" + }, + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "images/icon-16.png", + "48": "images/icon-48.png", + "128": "images/icon-128.png" + } + }, + "commands": { + "run-action": { + "suggested_key": { + "default": "Ctrl+Shift+Y", + "mac": "Command+Shift+Y" + }, + "description": "Run the sample action" + }, + "toggle-feature": { + "suggested_key": { + "default": "Ctrl+Shift+U", + "mac": "Command+Shift+U" + }, + "description": "Toggle a feature on or off" + } + } +} diff --git a/api-samples/commands/popup.css b/api-samples/commands/popup.css new file mode 100644 index 00000000..ba8ccd5d --- /dev/null +++ b/api-samples/commands/popup.css @@ -0,0 +1,52 @@ +body { + width: 300px; + padding: 12px 16px; + font-family: system-ui, sans-serif; + font-size: 14px; + color: #202124; +} + +h1 { + font-size: 16px; + font-weight: 600; + margin: 0 0 12px; +} + +.command-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 0; + border-bottom: 1px solid #e8eaed; +} + +.command-row:last-child { + border-bottom: none; +} + +.command-name { + color: #3c4043; +} + +kbd { + background: #f1f3f4; + border: 1px solid #dadce0; + border-radius: 4px; + padding: 2px 8px; + font-family: monospace; + font-size: 12px; + color: #5f6368; +} + +#hint { + margin: 12px 0 0; + font-size: 12px; + color: #80868b; +} + +#hint code { + background: #f1f3f4; + padding: 1px 4px; + border-radius: 3px; + font-size: 11px; +} diff --git a/api-samples/commands/popup.html b/api-samples/commands/popup.html new file mode 100644 index 00000000..2c140820 --- /dev/null +++ b/api-samples/commands/popup.html @@ -0,0 +1,16 @@ + + + + + + + +

Registered Commands

+
+

+ Customize shortcuts at + chrome://extensions/shortcuts +

+ + + diff --git a/api-samples/commands/popup.js b/api-samples/commands/popup.js new file mode 100644 index 00000000..8b8b407d --- /dev/null +++ b/api-samples/commands/popup.js @@ -0,0 +1,36 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +async function listCommands() { + const commands = await chrome.commands.getAll(); + const container = document.getElementById('commands'); + + for (const command of commands) { + const row = document.createElement('div'); + row.className = 'command-row'; + + const name = document.createElement('span'); + name.className = 'command-name'; + name.textContent = command.description || command.name; + + const shortcut = document.createElement('kbd'); + shortcut.textContent = command.shortcut || 'Not set'; + + row.appendChild(name); + row.appendChild(shortcut); + container.appendChild(row); + } +} + +listCommands();