diff --git a/README.md b/README.md index 6b4c2cc..da7f4ad 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,85 @@ -#Clipboard Inserter +# Native Inserter -A simple addon whose purpose is to automatically insert contents of clipboard into the page. +Fork of the Clipboard Inserter whose purpose it is to automatically insert the +data received by an in this repository included native application into a +broswer page. -If you're looking to install this addon, it's available here: +It is useful for use with text extraction tools like Textractor for looking up +words in the browser. - - [Firefox](https://addons.mozilla.org/firefox/addon/clipboard-inserter/) - - [Chrome web store](https://chrome.google.com/webstore/detail/clipboard-inserter/deahejllghicakhplliloeheabddjajm) +This repository contains the browser plugin, native application and native +manifest. Textractor plugin is not included. -Or, if the links don't work, just search for "clipboard inserter" in the appropriate addon market. +Currently this addon is not available on any of the browsers Addon Store. -On Chrome, if you want to use this extension with local files (the `file://` protocol), you have to enable the "Allow access to file URLs" setting in the extension details. +Only tested on GNU/Linux with Firefox. + +## Install + +You will need: + + - This code + - A go compiler + - A browser supporting native extensions (eg modern Firefox, Chrome) + +1) Compile and install the native application +2) Put the native application manifest into your browsers expected directory +3) Install the addon in your browser + +For this to be useful you will also need a sender, for example a Textractor +plugin (not included) and a browser page that the can be inserted to. + +## How does it work + +The browser plugin starts a native application which creates a raw TCP listen +socket for incoming connections. + +One or more applications (eg Textractor plugin) will connect to this socket and +send messages. Messages consist of a 4 Byte little-endian length header and +UTF-8 payload. + +The native application will forward the UTF-8 data to the browser plugin which +in turn will insert the text into a webpage similar to the original clipboard +version. + +## Troubleshooting + +The native application is writing to stderr. Browsers usually forward this to +their default log. + +The browser addon itself + +## (Not so) FAQ + +#### Why not the clipboard + +Abusing the clipboard functionality to transfer data to the browser is ugly. It +does also not work under Wayland which does not allow unfocused applications to +access the clipboard. + +(No opinion here whether the native application/messaging setup is more or less +ugly than the clipboard approach) + +It also has the bonus of working with VMs without setting up clipboard +forwarding between host and guest. + +#### Why a native application + +The APIs including TCP listen sockets are no longer supported by modern +Browsers. The only alternative would be connecting to a WebSocket server, but +this has two drawbacks: + +1) The API only supports the client side protocol and does not implement a +server. This would mean the sending side would need to be the server and the +native application the client, which would not work with multiple senders. + +2) The sending side (eg C++ Textractor plugin) will need to implement a +Websocket server which is a lot more work than raw tcp. + +## Bugs + +- Native messaging requires native host order prefixed messages. Golang does + not have an easy way to retrieve this information. The native application + will use little-endian which is the default on most common architectures +- Messages over the native-messaging 1MB limit will be discarded instead of + split up diff --git a/bg/index.html b/bg/index.html index b92c5d4..53d007c 100644 --- a/bg/index.html +++ b/bg/index.html @@ -1,5 +1,6 @@ + diff --git a/bg/monitor.js b/bg/monitor.js index c19a41f..6329829 100644 --- a/bg/monitor.js +++ b/bg/monitor.js @@ -1,13 +1,12 @@ console.log("I'm alive") -let previousContent = "" let listeningTabs = [] -let timer = null let options = defaultOptions chrome.storage.local.get(defaultOptions, o => options = o) + chrome.storage.onChanged.addListener((changes, area) => { if(area === "local") { const optionKeys = Object.keys(options) @@ -16,78 +15,45 @@ chrome.storage.onChanged.addListener((changes, area) => { options[key] = changes[key].newValue } } - updateTimer() } }) -chrome.browserAction.onClicked.addListener(() => { - chrome.tabs.query({ active: true, currentWindow: true }, - ([t]) => toggleTab(t.id)) +chrome.browserAction.onClicked.addListener((tab) => { + toggleTab(tab.id) }) -window.onload = () => { - document.querySelector("#paste-target").addEventListener("paste", e => { - if(e.clipboardData.getData("text/plain") === "") { - e.preventDefault() // prevent anything that is not representable as plain text from being pasted - } - }) -} +napp = browser.runtime.connectNative("native_inserter") +napp.onDisconnect.addListener((p) => { + if (p.error) { + console.error(`Disconnected native app due to an error: ${p.error.message}`) + } +}) +napp.onMessage.addListener((msg) => { + console.log("Received: " + msg.body) + const pasteTarget = document.querySelector("#paste-target") + pasteTarget.innerText = msg.body + const content = pasteTarget.innerText + listeningTabs.forEach(id => notifyForeground(id, content)) +}) function toggleTab(id) { - const index = listeningTabs.indexOf(id) - if(index >= 0) { - uninject(id) - listeningTabs.splice(index, 1) - updateTimer() - chrome.browserAction.setBadgeText({ text: "", tabId: id }) - } else { - chrome.tabs.executeScript({file: "/fg/insert.js"}) - listeningTabs.push(id) - updateTimer() - chrome.browserAction.setBadgeBackgroundColor({ color: "green", tabId: id }) - chrome.browserAction.setBadgeText({ text: "ON", tabId: id }) - } + const index = listeningTabs.indexOf(id) + if(index >= 0) { + uninject(id) + listeningTabs.splice(index, 1) + chrome.browserAction.setBadgeText({ text: "", tabId: id }) + } else { + chrome.tabs.executeScript({file: "/fg/insert.js"}) + listeningTabs.push(id) + chrome.browserAction.setBadgeBackgroundColor({ color: "green", tabId: id }) + chrome.browserAction.setBadgeText({ text: "ON", tabId: id }) + } } function notifyForeground(id, text) { - chrome.tabs.sendMessage(id, { - action: "insert", text, options - }) + chrome.tabs.sendMessage(id, { action: "insert", text, options }) } function uninject(id) { chrome.tabs.sendMessage(id, { action: "uninject" }) } - -function checkClipboard() { - const pasteTarget = document.querySelector("#paste-target") - pasteTarget.innerText = "" - pasteTarget.focus() - document.execCommand("paste") - const content = pasteTarget.innerText - if(content.trim() !== previousContent.trim() && content != "") { - listeningTabs.forEach(id => notifyForeground(id, content)) - previousContent = content - } -} - -function updateTimer() { - function stop() { - clearInterval(timer.id) - timer = null - } - function start() { - const id = setInterval(checkClipboard, options.monitorInterval) - timer = { id, interval: options.monitorInterval } - } - if(listeningTabs.length > 0) { - if(timer === null) { - start() - } else if(timer.interval !== options.monitorInterval) { - stop() - start() - } - } else { - stop() - } -} diff --git a/manifest.json b/manifest.json index a5c94d5..b939db8 100644 --- a/manifest.json +++ b/manifest.json @@ -1,22 +1,23 @@ { "manifest_version": 2, - "name": "Clipboard Inserter", - "version": "0.3.2", + "name": "Native Inserter", + "version": "1.0.0", - "description": "A simple addon that inserts clipboard contents into the page. Uses icon made by Google from www.flaticon.com licensed by CC 3.0 BY", + "description": "An addon that inserts contents received from a native application into a page. Forked from clipboard-inserter. Uses icon made by Google from www.flaticon.com licensed by CC 3.0 BY", "icons": {}, - "applications": { + "browser_specific_settings": { "gecko": { - "id": "@clipboard-inserter" + "id": "@native-inserter", + "strict_min_version": "50.0" } }, "permissions": [ "activeTab", - "clipboardRead", "storage", + "nativeMessaging", "file://*/*" ], @@ -27,7 +28,7 @@ "32": "icon/icon32.png", "64": "icon/icon64.png" }, - "default_title": "Toggle clipboard inserter" + "default_title": "Toggle Native Inserter" }, "background": {