I recognize this is relatively simple but it could be useful to some:
Github repository.
Sadly it isn't perfect still as it appears as though I can't figure out how to execute the code through IAccessible. Ultimately that means I can inject the code but I can't run it without entering chrome and sending {F6}{enter}
Regardless, for those who can't install plugins it looks like the best method there is as far as I can see. Also, sadly it doesn't look like there is a 2-way link... So you can send data to chrome, but unless you enable accessibility in chrome://accessibility you won't be able to get any data out unless you use alert(data) however here you can only have around 1600 bytes of data. Sooo yeah.
Anyway I hope some people find this useful
Inject Javascript into Chrome
- Delta Pythagorean
- Posts: 627
- Joined: 13 Feb 2017, 13:44
- Location: Somewhere in the US
- Contact:
Re: Inject Javascript into Chrome
As of right now, I'm working on a Chrome WebAPI to talk to and communicate with websites via Chrome, the problem is I haven't been able to do anything with it lol
As of right now, it's basically a toddler. You can visit the GitHub page in my signature below this message
As of right now, it's basically a toddler. You can visit the GitHub page in my signature below this message
[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat
Re: Inject Javascript into Chrome
Hi Sancarn,
Actually I didn't know one can reliably operate upon chrome search bar. Thanks for sharing. It's too bad, however, that it requires such a huge library like acc. For that matter, and as for me - Windows 8.1; chrome up-to-date - injectJS func, most of time, fails to send Enter key in particular and in such a way that I must manually press enter in order to inject the js source.
Btw, here's a example of speech recognition feature by a hacky 2-way link using injectJS and without using any plugin: chrome send the speech recognition result or its recognition state to ahk by its title (retrieved by WInGetTitle) which is set by the injected js, js triggered by WinMove (the javascript also previously set onresize-eventlisteners).
Actually I didn't know one can reliably operate upon chrome search bar. Thanks for sharing. It's too bad, however, that it requires such a huge library like acc. For that matter, and as for me - Windows 8.1; chrome up-to-date - injectJS func, most of time, fails to send Enter key in particular and in such a way that I must manually press enter in order to inject the js source.
Btw, here's a example of speech recognition feature by a hacky 2-way link using injectJS and without using any plugin: chrome send the speech recognition result or its recognition state to ahk by its title (retrieved by WInGetTitle) which is set by the injected js, js triggered by WinMove (the javascript also previously set onresize-eventlisteners).
Code: Select all
; note: the script will create two files in the script's current working directory (Dictation.Config.ini and HTMLFile.html)
#NoEnv
; #Warn
; #SingleInstance force
#Include %A_ScriptDir%\acc.ahk ; requires acc
injectJS(__js) { ; from https://github.com/sancarn/Small_AHK_Projects/blob/master/ChromeInjectJavascript/ChromeInjectJavascript.ahk
if (__js = "")
return false
if (WinExist("ahk_exe chrome.exe")) {
WinActivate
WinWaitActive
Acc_Get("Object", "4.1.2.2.3.5.2",, "ahk_exe chrome.exe").accValue(0) := "javascript:void((function(){" . __js . "})())"
ControlSend, Chrome Legacy Window, {F6}{Enter}
return !ErrorLevel
}
return false, ErrorLevel:=1
}
js =
(LTrim Join
var A_LastWidth = window.outerWidth, A_LastHeight = window.outerHeight;
Dictation = new function() {
document.getElementById("lang").setAttribute("onclick", "javascript:updateLang(this);return false;");
window.addEventListener("resize", function() {
var __width = window.outerWidth - A_LastWidth;
Dictation.winResizeEventMonitor(__width, !__width);
});
return {
recognitionState: 0,
set recognitionLanguage(__LID) {
if (__LID < 1) return;
console.info((document.getElementById("lang")[document.getElementById("lang").selectedIndex=__LID - 1]).value);
document.getElementById("lang").click();
},
start: function() {
this.recognitionState = 1, document.getElementById("btnClear").click(), document.getElementById("btn").click(), document.title = this.recognitionState;
console.log(arguments.callee.name);
this.titleUpdater = window.setInterval(function() {
document.title = document.getElementById("labnol").innerText + document.getElementById("notfinal").innerText;
}, 700);
},
stop: function() {
this.recognitionState = -1, document.getElementById("btn").click(), clearInterval(this.titleUpdater), document.title = this.recognitionState;
console.log(arguments.callee.name);
window.setTimeout(function(__Dictation) {
document.title = (__Dictation.recognitionState=0);
}, 700, this);
},
setRecognitionLanguage: function(__language) {
if (this.recognitionState) {
console.warn(arguments[0]);
return;
}
this.recognitionLanguage = __language;
},
winResizeEventMonitor: function(__width, __height) {
if (__height)
{
switch(this.recognitionState) {
case 1:
this.stop();
break;
case 0:
this.start();
break;
case -1:
break;
}
A_LastHeight = window.outerHeight;
}
else if (__width)
{
this.setRecognitionLanguage(__width);
A_LastWidth = window.outerWidth;
}
}
}
};
console.log(document.title="test_dictation");
)
global SpeechRecognition, WB
if not (SpeechRecognition:=new Dictation()) { ; create a new instance of Dictation
MsgBox, 64,, % "Dictation.LastError:" . {-3:"NO_INTERNET"
, -2:"CHROME_NOTFOUND"
, -1:"CHROME_RUN_ERRORLEVEL"
, 1:"INJECTJS_ERROR"
, 2:"INJECTJS_ERROR"
, 3:"SETRECOGNITIONLANGUAGE_ERROR"
, 4:"SETRECOGNITIONLANGUAGE_ERROR"}[Dictation.LastError]
ExitApp
}
; speech recognition callback function:
SpeechRecognition.onInterimResult := Func("updateInterimResults")
SpeechRecognition.onResult := Func("saveToClipboard")
Gui, 1:Add, DropDownList, % "vdropDownListControl x12 y9 w150 R10 Choose" . Dictation.startLanguage . " +AltSubmit gsetRecognitionLanguage", % Dictation.languages
Gui, 1:Add, Button, vbuttonControl x172 y9 w160 h20 grecognitionToogleState, start/stop &recognition
Gui, 1:Add, ActiveX, vWB x12 y39 w710 h100, Shell.Explorer
if not (FileExist(var:=A_ScriptDir . "/HTMLFile.html")) {
FileAppend,
(
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8" />
<title>HTMLFile</title>
<style>
.S2 {
vertical-align: sub;
font-size: 9px;
color: #666;
}
</style>
</head>
<body>
<span class="X" style="display: none;"></span>
<div class="C" style="padding: 15px;">
</div>
</body>
</html>
), % var, utf-8
}
WB.Navigate("file:///" . var)
while (WB.busy or WB.readyState <> 4)
sleep, 100
Gui, 1:Add, Progress, vprogressControl x12 y149 w710 h10 range0-100, 100
Gui, 1:Show, h170 w734, %A_ScriptName%
OnExit("ExitFunc")
return ; end of the auto-execurte part of the script
setRecognitionLanguage:
GuiControl, 1:Enable0, % A_GuiControl
GuiControl, 1:Enable0, buttonControl
GuiControlGet, var,, % A_GuiControl
SpeechRecognition.setRecognitionLanguage(var)
GuiControl, 1:Enable1, % A_GuiControl
GuiControl, 1:Enable1, buttonControl
return
recognitionToogleState:
GuiControl, 1:Enable0, % A_GuiControl
var := SpeechRecognition.recognizing
SpeechRecognition.recognitionToogleState()
GuiControl, 1:Enable%var%, dropDownListControl
GuiControl, 1:Enable1, % A_GuiControl
return
updateInterimResults(__dictation) {
GuiControl, 1:, progressControl, % ((__dictation.waitForInterimResultTimeRemaining*100)/__dictation.interimResultTimeout)
if (__dictation.waitForInterimResultTimeRemaining) {
VarSetCapacity(__str, 110*(__interimResultsOutputArray:=StrSplit(__dictation.lastInterimResult, A_Space)).MaxIndex())
Loop % __interimResultsOutputArray.MaxIndex()
__str .= "<span class=""S1"">" . __interimResultsOutputArray[a_index] . "</span><span class=""S2""> " . a_index . " </span>"
WB.document.getElementsByClassName("C")[0].innerHTML := __str
} else {
__dictation.recognitionToogleState()
GuiControl, 1:Enable, dropDownListControl
}
}
saveToClipboard(__dictation, __result) {
clipboard := __result
TrayTip, %A_ScriptName%, Result has been copied to clipboard.
}
GuiClose:
ExitApp
ExitFunc() {
return (SpeechRecognition:=0)
}
; ====================
Class Dictation {
static configFile := A_ScriptDir . "\Dictation.Config.ini"
, url := "https://dictation.io"
, LastError := 0
recognizing := false
, interimResultTimeout := 7
, lastInterimResultElapsedTime := 0
, lastInterimResult := ""
, onInterimResultFunc := this.updateInterimResults
, onResultFunc := this.saveToClipboard
Init() {
static __ := Dictation.Init()
if not (FileExist(Dictation.configFile)) {
FileAppend,
(LTrim
[start]
language=62
[languages]
Afrikaans=1
Bahasa Indonesia=2
Bahasa Melayu=3
Català=4
Čeština=5
Dansk=6
Deutsch=7
Australia=8
Canada=9
India=10
New Zealand=11
South Africa=12
English=13
United States=14
Argentina=15
Bolivia=16
Chile=17
Colombia=18
Costa Rica=19
Ecuador=20
El Salvador=21
Español=22
Estados Unidos=23
Guatemala=24
Honduras=25
México=26
Nicaragua=27
Panamá=28
Paraguay=29
Perú=30
Puerto Rico=31
República Dominicana=32
Uruguay=33
Venezuela=34
Euskara=35
Filipino=36
Français=37
Galego=38
हिन्दी=39
Hrvatski=40
IsiZulu=41
Íslenska=42
Italiano=43
Svizzera=44
Lietuvių=45
Magyar=46
Nederlands=47
Norsk bokmål=48
Polski=49
Brasil=50
Portugal=51
Română=52
Slovenščina=53
Slovenčina=54
Suomi=55
Svenska=56
Tiếng Việt=57
ภาษาไทย=58
Türkçe=59
Ελληνικά=60
български=61
Русский=62
Српски=63
Українська=64
한국어=65
普通话 (中国大陆)=66
普通话 (香港)=67
中文 (台灣)=68
粵語 (香港)=69
日本語=70
), % Dictation.configFile, utf-16
}
IniRead, __language, % Dictation.configFile, start, language
if (__language == "ERROR")
ExitApp
Dictation.startLanguage := __language
IniRead, __languages, % Dictation.configFile, languages
if (__languages == "ERROR")
ExitApp
Dictation.languages := RTrim(RegExReplace(__languages, "=.+?\n", "|"), "=" . StrSplit(__languages, "`n").length())
}
__New() {
if not (DllCall("Wininet.dll\InternetGetConnectedState", "Str", 0x40, "Int", 0)) ; check internet connection
return !Dictation.LastError:=-3
RegRead, __regKey, HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\App Paths\Chrome.exe ; retrieves chrome.exe path via registry
if (ErrorLevel)
return !Dictation.LastError:=-2
run % """" . __regKey . """ " . Dictation.url,, UseErrorLevel
if (ErrorLevel)
return !Dictation.LastError:=-1
WinWait % Dictation.__Class . A_Space . "ahk_exe chrome.exe"
this.HWND := "ahk_id " . WinExist()
sleep, 3000
global js
injectJS(js)
if (ErrorLevel)
return !Dictation.LastError:=1
sleep, 500
MsgBox, Can't run the js without entering manually {Enter}...
WinWait % "test_dictation" . A_Space . this.HWND,, 4
if (ErrorLevel)
return !Dictation.LastError:=2
WinMove, % this.HWND,,,,, % A_ScreenHeight
WinRestore, % this.HWND
this.setRecognitionLanguage(Dictation.startLanguage)
if (ErrorLevel)
return !Dictation.LastError:=ErrorLevel
return this
}
__Delete() {
if (Dictation.LastError >= 0) {
if (this.recognitionState())
this.recognitionToogleState()
PostMessage, % (WM_SYSCOMMAND:="0x112"), % (SC_CLOSE:="0xF060"),,, % this.HWND
}
}
recognitionToogleState() {
static __x := 0, __y := 1
IfEqual, __x, %__y%, return
__x := __y
if (__f:=this.boundIterator) {
SetTimer, % __f, off
SetTimer, % __f, delete
this.boundIterator := ""
}
WinMove, % this.HWND,,,,, % A_ScreenHeight - __y
WinWait % __y . A_Space . this.HWND,, 2
if (ErrorLevel)
ExitApp
if (this.recognizing:=__y) {
this.boundIterator := __f := this.updateResult.Bind(this)
SetTimer, % __f, % this.iteratorPeriod
} else this.onResultFunc.Bind(this, this.lastInterimResult).Call(), this.lastInterimResultElapsedTime := 0, this.lastInterimResult := ""
__y := !__y
return !ErrorLevel
}
recognitionState() {
return this.recognizing
}
setRecognitionLanguage(__language) {
static __l := StrSplit(Dictation.languages, "|").length()
if not (((__language:=abs(__language)) >= 1) and __language <= __l)
return !ErrorLevel:=3
SetWinDelay, -1
WinGetPos,,, __w1,, % "ahk_id " . WinExist(this.HWND)
WinMove,,,,, % __w1 - (__language)
WinGetPos,,, __w2
sleep, 100
WinMove,,,,, % __w1
WinGetPos,,, __w1
return ErrorLevel:=!((__w1 - __w2 == __language)*4)
}
iteratorPeriod {
set {
static ITERATOR_MIN_PERIOD := 250
if (value < ITERATOR_MIN_PERIOD)
return ITERATOR_MIN_PERIOD
return value
}
}
interimResult {
set {
if (this.lastInterimResult == value)
this.lastInterimResultElapsedTime += 0.5
else this.lastInterimResult := value, this.lastInterimResultElapsedTime := 0
this.waitForInterimResultTimeRemaining := this.interimResultTimeout - this.lastInterimResultElapsedTime
this.onInterimResultFunc.Bind(this).Call()
}
}
updateResult() {
WinGetTitle, __winTitle, % this.HWND
this.interimResult := InStr(__winTitle, Dictation.url) ? "" : StrSplit(__winTitle, " - Google Chrome")[1]
}
onInterimResult {
set {
if (value.maxParams > 0 or (value:=Func(value)).maxParams > 0) {
this.onInterimResultFunc := value
return !ErrorLevel:=0
}
this.onInterimResultFunc := this.updateInterimResults
return !ErrorLevel:=6
}
}
onResult {
set {
if (value.maxParams > 0 or (value:=Func(value)).maxParams > 0) {
this.onResultFunc := value
return !ErrorLevel:=0
}
this.onResultFunc := this.saveToClipboard
return !ErrorLevel:=7
}
}
updateInterimResults() {
if (this.waitForInterimResultTimeRemaining) {
TrayTip,, % this.lastInterimResult,, 0x1
} else this.recognitionToogleState()
}
saveToClipboard(__result) {
clipboard := __result
}
}
Re: Inject Javascript into Chrome
Well of course it doesn't require the whole of acc.ahk I was just too lazy to separate the functions I needed... Even more so, it's my custom version of acc.ahk which is even bigger... Really it only needs Acc_Parent, Acc_Child, Acc_GetChild and Acc_ObjectFromWindow.A_AhkUser wrote:Actually I didn't know one can reliably operate upon chrome search bar. Thanks for sharing. It's too bad, however, that it requires such a huge library like acc. For that matter, and as for me - Windows 8.1; chrome up-to-date - injectJS func, most of time, fails to send Enter key in particular and in such a way that I must manually press enter in order to inject the js source.
Code: Select all
Acc_Init()
{
Static h := DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_Query(Acc) {
try return ComObj(9, ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Parent(Acc) {
try parent := Acc.accParent
return parent ? Acc_Query(parent) :
}
Acc_Child(Acc, ChildId=0) {
try child := Acc.accChild(ChildId)
return child ? Acc_Query(child) :
}
; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
Acc_Query(Acc) {
try return ComObj(9, ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_GetChild(Acc_or_Hwnd, child_path) {
Acc := WinExist("ahk_id" Acc_or_Hwnd)? Acc_ObjectFromWindow(Acc_or_Hwnd):Acc_or_Hwnd
if ComObjType(Acc,"Name") = "IAccessible" {
Loop Parse, child_path, csv
Acc := A_LoopField="P"? Acc_Parent(Acc):Acc_Children(Acc)[A_LoopField]
return Acc
}
}
Acc_ObjectFromWindow(hWnd, idObject = -4){
Acc_Init()
if (DllCall("oleacc\AccessibleObjectFromWindow"
, "Ptr", hWnd
, "UInt", idObject &= 0xFFFFFFFF
, "Ptr", -VarSetCapacity(IID,16)
+ NumPut(idObject == 0xFFFFFFF0
? 0x46000000000000C0
: 0x719B3800AA000C81
, NumPut(idObject == 0xFFFFFFF0
? 0x0000000000020400
: 0x11CF3C3D618736E0,IID,"Int64"),"Int64")
, "Ptr*", pacc) = 0)
return ComObjEnwrap(9,pacc,1)
}
UriEncode(Uri, Enc = "UTF-8")
{
StrPutVar(Uri, Var, Enc)
f := A_FormatInteger
SetFormat, IntegerFast, H
Loop
{
Code := NumGet(Var, A_Index - 1, "UChar")
If (!Code)
Break
If (Code >= 0x30 && Code <= 0x39 ; 0-9
|| Code >= 0x41 && Code <= 0x5A ; A-Z
|| Code >= 0x61 && Code <= 0x7A) ; a-z
Res .= Chr(Code)
Else
Res .= "%" . SubStr(Code + 0x100, -1)
}
SetFormat, IntegerFast, %f%
Return, Res
}
getSingleLineOfJS(js){
oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
oHTTP.Open("POST", "https://javascript-minifier.com/raw", True)
oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
data:= "input=" . UriEncode(js)
oHTTP.send(data)
Status := oHTTP.WaitForResponse(-1) ; Success = -1, Timeout = 0, No response = Empty String
if status=0
{
msgbox, "You are not connected to the internet."
return
}
return oHTTP.ResponseText
}
injectJS(js,minify=1){
if minify
js := getSingleLineOfJS(js)
if !js
return
addressBar := Acc_GetChild(WinExist("ahk_exe chrome.exe"),"4.1.2.2.3.5.2")
winactivate,ahk_exe chrome.exe
addressBar.accValue(0) := "javascript:void((function(){" . js . "})())"
ControlSend,Chrome Legacy Window,{F6}{enter},ahk_exe chrome.exe
}
Damn that's cool Thanks for sharingBtw, here's a example of speech recognition feature by a hacky 2-way link using injectJS and without using any plugin: chrome send the speech recognition result or its recognition state to ahk by its title (retrieved by WInGetTitle) which is set by the injected js, js triggered by WinMove (the javascript also previously set onresize-eventlisteners).
Re: Inject Javascript into Chrome
I know this thread is very old, but if people still need this as like me...
A simple way to achieve what op needed without relying on sending {F6}{ENTER}:
1) Save a bookmark of the javascript code to be executed.
2) Use Acc lib to press/click that saved bookmark
I have a simple example here to mute/unmute your microphone in Google Meet from anywhere.
Save this JS as a bookmark:
And use this ahk script:
From that you can accomplish more advanced things like click bookmark with X or Y name, etc...
A simple way to achieve what op needed without relying on sending {F6}{ENTER}:
1) Save a bookmark of the javascript code to be executed.
2) Use Acc lib to press/click that saved bookmark
I have a simple example here to mute/unmute your microphone in Google Meet from anywhere.
Save this JS as a bookmark:
Code: Select all
javascript:document.querySelector('[data-is-muted=false] > div').click();void(0)
Code: Select all
#include Lib\Acc.ahk
SetTitleMatchMode, 2
#IfWinExist, Meet:
#Space::
oo := Acc_Get("Object", "4.1.2.1.4.35", 0, "Meet:") ; Change the path to yours bookmarked JS
oo.accDoDefaultAction(0)
Return
Re: Inject Javascript into Chrome
sancarn, Your js injection may fail.
Better use this variant
https://www.autohotkey.com/boards/viewtopic.php?f=76&t=75527
Better use this variant
https://www.autohotkey.com/boards/viewtopic.php?f=76&t=75527
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: No registered users and 115 guests