How can I execute Javascript methods with AutoHotkey? - javascript

I am writing an AutoHotkey script to enter data into an Oracle PeopleSoft application. Rather than trying to locate specific elements on the page, I want to try execute JavaScript commands directly instead.
So instead of using a hardcoded MouseClick, left, 205, 281 to click the "Add New Values" button, I want to directly run submitAction_win0(document.win0,'#ICSwitchMode')
I've tried entering commands directly into the address bar, but this doesn't seem to have any effect.
#k::
jsCommand = javascript:submitAction_win0(document.win0,'#ICSwitchMode');
Send, !d ; places cursor in URL field
Send, %jsCommand%{Enter} ; submit JS command (doesn't work)
Return
According to this AHK thread, it should be possible to accomplish this using a ScriptControl object, but I'm a bit unsure how to use them.
How can I execute JavaScript commands using AutoHotkey?

Per an example I used in a previous question's answer for controlling IE, walking the DOM, etc:
F3::
wb := ComObjCreate("InternetExplorer.Application") ; Create a IE instance
wb.Visible := True
wb.Navigate("http://google.com")
Sleep, 5000
SendInput, This is test.{Enter}
Sleep, 5000
wb.document.getElementById("lst-ib").value := "This is another test."
wb.document.getElementById("_fZl").click()
return

Related

Delete USB history (regedit) with script

I have a javascript and Powershell script allowing to detect a usb plug, and which shows me a pop up. Indeed, my script only detects new usb keys that have not yet been plugged into the system. That's why I would like to delete the usb key history from my computer, like USB OBLIVION does, in order to have as a new connection to each usb plug.
I don't see what I need to add to my script... I have already tried deleting the content of:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB
Thanks
You could try these, but don't forget to wipe the from them other 3 paths as well
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SWD\WPDBUSENUM
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices\
You could also consider using WMI Event subscriptions, this works whatever the usb key is already known or not, but do not clear the registry :
to detect usb plug :
Register-CIMIndicationEvent –Query `
"Select * From __InstanceCreationEvent Within 1 Where TargetInstance IsA 'Win32_LogicalDisk'" `
–SourceIdentifier "WMIInsert" –Action { Write-Host `
"$($Event.SourceEventArgs.NewEvent.TargetInstance.Name) plugged!`n" }
to detect usb ejection :
Register-CIMIndicationEvent –Query `
"Select * From __InstanceDeletionEvent Within 1 Where TargetInstance IsA 'Win32_LogicalDisk'" `
–SourceIdentifier "WMIEject" –Action { Write-Host `
"$($Event.SourceEventArgs.NewEvent.TargetInstance.Name) ejected!`n" }
Within 1 means to detect every one second. Depending on your needs, you can configure Within 30 for example to look it for every 30 seconds (every plug or ejection in the meantime are captured as well).
the -Action parameter let you do whatever you want since this is a scriptblock (In the example I provided the event is only displayed to the console).
And do not forget that StackOverflow is not a free coding service, so next time, please share the piece of code where you have got a problem or a bug.

Why does jquery return different values than the values submitted?

Update:
Please see the answer noted below as, ultimately, the problem had nothing to do with jsquery.
=============
Issue:
I submit an object to jquery to convert into a serialized string that will become part of a "POST" request to a server, and the data returned from the serialization request is different than the data sent on many occasions.
An example:
The JavaScript code that implements the server POST request:
function send_data(gpg_data) {
var query_string;
query_string = '?' + $.param(gpg_data, traditional = true);
console.log('gpg_data =', gpg_data)
console.log('query_string =', query_string);
$.post(server_address + query_string);
return;
}
This is the structure sent to the jquery param() function.
(copied from the browser console in developer mode.)
gpg_data =
{controller_status: 'Connected', motion_state: 'Stopped', angle_dir: 'Stopped', time_stamp: 21442, x_axis: 0, …}
angle_dir: "Stopped"
controller_status: "Connected"
force: 0
head_enable: 0
head_x_axis: 0
head_y_axis: 0
motion_state: "Stopped"
time_stamp: 21490
trigger_1: 0
trigger_2: 0
x_axis: 0
y_axis: "0.00"
. . . and the returned "query string" was:
query_string = ?controller_status=Connected&motion_state=Stopped&angle_dir=Stopped&time_stamp=21282&x_axis=0&y_axis=0.00&head_x_axis=0&head_y_axis=0&force=0&trigger_1=1&trigger_2=1&head_enable=0
The data received by the server is:
ImmutableMultiDict([('controller_status', 'Connected'), ('motion_state', 'Stopped'), ('angle_dir', 'Stopped'), ('time_stamp', '21282'), ('x_axis', '0'), ('y_axis', '0.00'), ('head_x_axis', '0'), ('head_y_axis', '0'), ('force', '0'), ('trigger_1', '1'), ('trigger_2', '1'), ('head_enable', '0')])
For example, note that "trigger_1" returns 1 when the data sent to it is a zero.
I have tried setting the query to "traditional = true" to revert to an earlier style of query handling as some articles suggested - which did not work.  I tried this with jquery 3.2 and 3.6.
I am not sure exactly how jquery manages to munge the data so I have no idea where to look.
I have looked at my script and at the unpacked jquery code, and I can make no sense out of why or how it does what it does.
Any help understanding this would be appreciated.
P.S.
web searches on "troubleshooting jquery" returned very complex replies that had more to do with editing e-commerce web pages with fancy buttons and logins than with simply serializing data.
P.P.S.
I am tempted to just chuck the jquery and write my own serialization routine. (grrrr!)
===================
Update:
As requested, a link to the browser-side context.
To run: unpack the zip file in a folder somewhere and attach an analog joystick/gamepad to any USB port, then launch index.html in a local browser.  Note that a purely digital gamepad - with buttons only or with a joystick that acts like four buttons - won't work.
You will want to try moving joystick axes 1 and 2, (programmatically axes 0 and 1) and use the first (0th) trigger button.
You will get a zillion CORS errors and it will complain bitterly that it cannot reach the server, but the server side context requires a GoPiGo-3 robot running GoPiGo O/S 3.0.1, so I did not include it.
Note: This does not work in Firefox as Firefox absolutely requires a "secure context" to use the Gamepad API.  It does work in the current version of Chrome, (Version 97.0.4692.99 (Official Build) (64-bit)), but throws warnings about requiring a secure context.
Please also note that I have made every attempt I know how to try to troubleshoot the offending JavaScript, but trying to debug code that depends on real-time event handling in a browser is something I have not figured out how to do - despite continuous searching and efforts.  Any advice on how to do this would be appreciated!
======================
Update:
Researching debugging JavaScript in Chrome disclosed an interesting tidbit:
Including the line // #ts-check as the first line in the JavaScript code turns on additional "linting" (?) or other checks that, (mostly) were a question of adding "var" to the beginning of variable declarations.
However. . . .
There was one comment it made:
gopigo3_joystick.x_axis = Number.parseFloat((jsdata.axes[0]).toFixed(2));
gopigo3_joystick.y_axis = Number.parseFloat(jsdata.axes[1]).toFixed(2);
I could not assign gopigo3_joystick.y_axis to a string object, (or something like that), and I was scratching my head - that was one of the pesky problems I was trying to solve!
If you look closely at that second line, you will notice I forgot a pair of parenthesis, and that second line should look like this:
gopigo3_joystick.y_axis = Number.parseFloat((jsdata.axes[1]).toFixed(2));
Problem solved - at least with respect to that problem.
I figured it out and it had nothing to do with jquery.
Apparently two things are true:
The state of the gpg_data object's structure is "computed", (snapshot taken), the first time the JavaScript engine sees the structure and that is the state that is saved, (even though the value may change later on). In other words, that value is likely totally bogus.
Note: This may only be true for Chrome. Previous experiments with Firefox showed that these structures were updated each time they were encountered and the values seen in the console were valid. Since Firefox now absolutely requires a secure context to use the gamepad API, I could not use Firefox for debugging.
I was trying to be "too clever". Given the following code snippet:
function is_something_happening(old_time, gopigo3_joystick) {
if (gopigo3_joystick.trigger_1 == 1 || gopigo3_joystick.head_enable == 1) {
if (old_time != Number.parseFloat((gopigo3_joystick.time_stamp).toFixed(0))) {
send_data(gopigo3_joystick)
old_time = gopigo3_joystick.time_stamp
}
}
return;
}
The idea behind this particular construction was to determine if "something interesting" is happening, where "something interesting" is defined as:
A keypress, (handled separately)
A joystick movement if either the primary trigger or the pinky trigger is pressed.
Movement without any trigger pressed is ignored so that if the user accidentally bumps against the joystick, the robot doesn't go running around.
Therefore the joystick data only gets updated if the trigger is pressed. In other words, trigger "release" events - the trigger is now = 0 - are not recorded.
The combination of these two events - Chrome taking a "snapshot" of object variables once and once only, (or not keeping them current) - and the trigger value persisting, lead me to believe that jquery was the problem since the values appeared to be different on each side of the jquery call.

Is it possible to send a key code to an application that is not in front?

I'm writing a simple Automator script in Javascript.
I want to send a key-code(or key-storke) to an OS X application that is not in front.
Basically, I want to run this code and do my things while the script opens a certain application, write text, and hit enter - all of this without bothering my other work.
I want something like this:
Application("System Events").processes['someApp'].windows[0].textFields[0].keyCode(76);
In Script Dictionary, there is keyCode method under Processes Suite.
The above code, however, throws an error that follows:
execution error: Error on line 16: Error: Named parameters must be passed as an object. (-2700)
I understand that the following code works fine, but it require the application to be running in front:
// KeyCode 76 => "Enter"
Application("System Events").keyCode(76);
UPDATE: I'm trying to search something on iTunes(Apple Music). Is this possible without bringing iTunes app upfront?
It's possible to write text in application that is not in front with the help of the GUI Scripting (accessibility), but :
You need to know what UI elements are in the window of your specific
application, and to know the attributes and properties of the
specific element.
You need to add your script in the System Preferences --> Security
& Privacy --> Accessibility.
Here's a sample script (tested on macOS Sierra) to write some text at the position of the cursor in the front document of the "TextEdit" application.
Application("System Events").processes['TextEdit'].windows[0].scrollAreas[0].textAreas[0].attributes["AXSelectedText"].value = "some text" + "\r" // r is the return KEY
Update
To send some key code to a background application, you can use the CGEventPostToPid() method of the Carbon framework.
Here's the script to search some text in iTunes (Works on my computer, macOS Sierra and iTunes Version 10.6.2).
ObjC.import('Carbon')
iPid = Application("System Events").processes['iTunes'].unixId()
searchField = Application("System Events").processes['iTunes'].windows[0].textFields[0]
searchField.buttons[0].actions['AXPress'].perform()
delay(0.1) // increase it, if no search
searchField.focused = true
delay(0.3) // increase it, if no search
searchField.value = "world" // the searching text
searchField.actions["AXConfirm"].perform()
delay(0.1) // increase it, if no search
// ** carbon methods to send the enter key to a background application ***
enterDown = $.CGEventCreateKeyboardEvent($(), 76, true);
enterUp = $.CGEventCreateKeyboardEvent($(), 76, false);
$.CGEventPostToPid(iPid, enterDown);
delay(0.1)
$.CGEventPostToPid(iPid, enterUp);

Cannot find source of javascript function call

Ok, so I need to find the source code of a particular javascript function on a website. (The specifics do not really matter unless there is no way to do what it is that I am asking)
I can see the function call in a link of html code
onclick="inbox.sendMessage();"
I know that the function does work because if I use a plugin a can call the function on that page, however, I have searched every .js file is referenced in that page, and none of them contain a function called sendMessage.
What I am asking is, is there a way to follow the code back to the source, perhaps if there was a way to debug the html and break when the onclick is triggered and then step into the function to see its source, but I do not know how I can do that or if it is even possible. Any help will be greatly appreciated, Thanks.
I guess you could do :
inbox.sendMessage
In the webconsole. (the function name without the parenthesis)
It will print out the source code of the function.
I usually use Opera, and in that at least this is what I do:
Open Opera Dragonfly (Ctrl + Shift + I).
Click on the HTML tag with the onclick handler.
Go to the listeners tab in the right hand side column.
See the listener for the click event. It shows you the file and line number.
sendMessage could be declared as:
var inbox{
sendMesssage:function(){
}
}
//or
function inbox(){
this.sendMessage=function(){
}
}
// or
inbox.sendMessage=function(){}
// or ...
So looking for "sendMessage(" or "function sendMessage" will not find you anything.
In chrome, Internet Explorer and Firefox (with firebug) you can hit F12 and go to debug, there you can check the scripts that have been loaded as there might have been scripts loaded dynamically.
#!/usr/bin/env ruby
Dir::glob("*").each do |name|
lineCount = 1
File.open(name, "r").each do |line|
puts "\nFile name: " + name + "\nline: " + lineCount.to_s if line =~ /inbox.sendMessage/ && name != "findfunction.rb"
lineCount += 1
end
end
Wrote a quick ruby script to help you out. To execute, first make sure you have a ruby interpreter on your machine then place the script in the directory with all your relevant files. load up a command line terminal, navigate to said directory and type "ruby findfunction.rb".
It will tell you all instances (files + line number) of "inbox.sendMessage".

how to execute javascript in delphi?

I am coding a small app ,in middle i struck at some point where i have to execute javascript to get my data ?
in my process ,i have to login to some url and then go to some page and have to get data from that . i done all this with indy idhttp ,i got all info except one column which needs javascript to get value ,then i tried using twebbowser to make it work for me ,but how can i use cookies to enabled to webbrowser ?
i navigated browserto('http://mysite.com/login.php user and pass ') ,well its loged in and then i tried to access next link like ('http://mysite.com/link1/example.php')but it directing to login page :(
any help appreciated :)
What is your question now? In the title you ask how to execute JavaScript. Try the following:
uses
MSHTML_TLB, SHDocVw, ShellAPI;
function ExecuteScript(doc: IHTMLDocument2; script: string; language: string): Boolean;
var
win: IHTMLWindow2;
Olelanguage: Olevariant;
begin
if doc <> nil then
begin
try
win := doc.parentWindow;
if win <> nil then
begin
try
Olelanguage := language;
win.ExecScript(script, Olelanguage);
finally
win := nil;
end;
end;
finally
doc := nil;
end;
end;
end;
Sample usage:
IDoc: IHTMLDocument2;
Webbrowser1.Document.QueryInterface(IHTMLDocument2, iDoc);
ExecuteScript(iDoc, 'document.login.submit()', 'JavaScript');
(This, and more, can be found here).
Then in the text you ask how to use cookies (when using TWebBrowser this should happen automatically). When using Indy HTTP, you just have to attach a TIdCookieManager to your TIdHTTPClient instance, thats all (but you probably don't want to use that anyway, due to the script requirement....)
Your best bet would be to automate IE itself. Grab a copy of embeddedwb, drop on a form and navigate to the url which you need to execute something. There is a document property of the component which returns an OLEVariant, use this to execute a DHTML style statement.. something like document.form.submit;.
You can easily hide the window used for automation, one technique I have used is to place it on a new page on a page control, add a second page to display the status, then show the status page and hide the tabs.

Categories

Resources