 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Sat Oct 16, 2004 8:58 pm Post subject: |
|
|
| Quote: | could you look into supporting container variables? At the very least, a dynamic linked list of strings. Something you can use like a dynamic array...
ListAdd, strList, 'SomeNewString'
ListRemove, strList, index
ListSearch, strList, 'string', returnedindex
ListCount, strList, returnedcount
ListIterator, strList, returnediterator
ListIterate, strList, iterator
ListValue, strList, iterator, returnedstring | I think most of this can be done fairly easily with a parsing loop. To add an item, concatenate it with a delimiter: | Code: | | MyList = %MyList%`nNextItem |
To search the list: | Code: | Loop, parse, MyList, `n
if A_LoopField = SearchTerm
MsgBox Found the item at position #%A_Index% |
| Quote: | | he too said that the limited type of variables had him fumbling with an otherwise simple script language. | I think having everything be a string makes things easier in the long run. The type of a variable's contents can be determined via "if MyVar is number..." if it is ever needed. But for both this and the above point, if you still see inadequacies please feel free to cite them, preferably with a specific real world example to help me see the benefits.
| Quote: | | By the way, that friend ended up using quite an ingenious solution himself. He had an X45 Saitek joystick. The software for it comes with 2 virtual drivers to add to the driver stack, for keyboard and mouse, which allows the joystick to be programmed to react like the mouse or keyboard. More interestingly, the software supported chain of events, so you could setup repeated chains to simulate mouse and keyboard. | The above is interesting because I'm reluctant to distribute anything with AutoHotkey that replaces or modifies system drivers. At the very least, doing so might prevent hotfixes and service packs from being installed properly. By contrast, a "supplemental" driver or a "filter" driver sounds much safer. It could be an optional component distributed with the product or (if you or I prefer) downloadable as a separate component.
Thanks for continuing in the face of so many dead ends and frustrations. It sounds like you are close to a eureka. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Sat Oct 16, 2004 9:56 pm Post subject: |
|
|
I see your point, with regards to simply concatenating strings and parsing them with a delimiter. Again, this is where someone coming from C/C++ and other tightly type defined languages would fumble a bit. But it's a perfectly acceptable solution.
While I cannot site a real world example to demonstrate a use where string parsing couldn't be used, it's a lot less code than having to create a loop anytime you want to work with the string list. I think it would be beneficial to support a generic container type internall. Since you already support strings, and is number checks, you could support a simple string container, and treat the data the same.
The reason I find this useful, for example, let's use a game script. Dropping morality for a moment, let's consider a pretty complicated automation script. We want it to reply to private communications (log parsing), and respond accordingly. Some actions through private communications may require the script to delay before processing additional communication. In more complicated languages with lists, I would continue to process the communications, queue them into a list of strings, and when the script isn't busy with a simulated delay, it pops the next command of the queue and processes it.
Now, of course, you COULD do this with string lists, but consider the overwhelming code required to loop, check, concatenate on, strip off the head of the string, and so on. What would be a few lines of code as I described, becomes a number of loops, which each contain a bunch of repeated code.
I digress on this point, because strings CAN be used, but in terms of functionality, using string concatenation to simulate a list is not something most people would consider. I see a great benefit in adding the list support, but it's only by personal opinion. I would like to hear other users opinions on this before either of us could say whether it's a good idea or not.
Now, back on the more important subject of input. I've looked into moufiltr, and there is a function, MouFilter_ServiceCallback, which suggests data could be inserted into the stream. However, this is a callback, that is called internally, I don't think this is the right place to work with.
Having done as much research as I have, I've concluded with all my failures, that DeviceIoControl is the best way to have an EXE talk to a device directly. This means it interacts with mouclass and kbdclass. This can be determined by a quick search in your registry for PointerClass0, which should render a key pointing to mouclass.
Through trial and much error, I can determine that replacing mouclass.sys is possible. However, as you suggested, service packs may wish to update this in the future. The only solution I can provide to this, is once I get the keyboard and mouse class drivers working, I can write a small patch that can easily be incorporated into later versions of DDK source. I can only assume that the Win2003DDK contains the latest code for mouclass. I make this assumption on the fact that mouclass works just fine, unless I start playing with DeviceIoControl and the IO CTL that I have added to mouclass. Otherwise, things work like normal.
I am in full agreement to release the drivers as a separate component, that AutoHotkey can use if present. It's not hard, simply try using IOCTL_MOUSE_INSERT_DATA, and if it fails, it's not supported. At least, that's how I intend to test.
However, I've run into something of a brick wall. Chris, I've added you to my ICQ, I'm waiting to see you pop online. However, I'll cover the current issue now.
Within mouclass.c, there is a function:
| Code: |
NTSTATUS
MouseClassDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
|
This function is called when DeviceIoControl is called on the driver. The arguments are, obviously a pointer to the device object itself, and an IRP. As far as I understand it, an IRP is an internal structure for handling generic IO to devices. The IRP contains a control code, a status, a value for the bytes written, and the input/output buffers. Most of this is passed in from DeviceIoControl.
I got to this point, because I was searching for IOCTL_MOUSE_INSERT_DATA, but the only definition at the same place as it, was IOCTL_MOUSE_QUERY_ATTRIBUTES. And this I managed to find in a switch statement in this function.
| Code: |
switch (ioctl = stack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_MOUSE_QUERY_ATTRIBUTES:
|
So my next step, was to look at how default case statements are handled, along with a number of other generic HID based IOCTL codes like IOCTL_HID_GET_DRIVER_CONFIG... They all pass like this:
| Code: |
... more above...
case IOCTL_HID_GET_INDEXED_STRING:
if (deviceExtension->PnP && (deviceExtension != Globals.GrandMaster)) {
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (deviceExtension->TopPort, Irp);
break;
}
default:
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
|
So, according to this, I assumed that if I set status to STATUS_SUCCESS, that instead of failing DeviceIoControl, it would return successful. The IoSkipCurrentIrpStackLocation and IoCallDriver refer to passing the IOCTL code to the next driver, which I believe, if anything, is vendor supplied drivers, maybe some other internal windows driver.
Now, with this default setup, passing IOCTL_MOUSE_INSERT_DATA would render GetLastError returning an error of "Incorrect function.", which, after sending random control codes in, I assumed this is the return of the default handler.
So, I setup my own case for IOCTL_MOUSE_INSERT_DATA as follows:
| Code: |
case IOCTL_MOUSE_INSERT_DATA:
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
|
So, the only difference between here, and the default case handler, is that status is STATUS_SUCCESS instead of STATUS_INVALID_DEVICE_REQUEST. However, now when I run the same call with DeviceIoControl, instead of failing, I get an unhandled exception thrown by kernel32.dll, or at least that's as far as the debugger is seeing it thrown from (DeviceIoControl).
So the problem I'm first facing right now, is figuring out how to have my special case for INSERT_DATA, to return successfully without doing anything except handling an empty IRP. This is where I'm struggling at the moment. I've tried 5 or 6 variations of the driver, with no luck so far.
The exception cannot be caught with try/catch either it seems.
Here is the exact error produced:
Unhandled exception at 0x7c578542 in PTBot.exe: 0xC0000005: Access violation writing location 0x00000000.
This suggests that because of STATUS_SUCCESS, when calling IoCompleteRequest, some different logic is being called and it's expecting something it's not getting. I'm thinking it might be the output buffer, which I'm passing in as NULL, as follows:
| Code: |
if(DeviceIoControl(m_hMouse, IOCTL_MOUSE_INSERT_DATA, (LPVOID)&midInject, sizeof(MOUSE_INPUT_DATA), NULL, 0, NULL, NULL))
bReturn = true;
|
So the only thing I can do is try to populate the NULL arguments one by one now and see if the error changes... That's my next archaic attempt to find my eureka
Hope to see you on ICQ soon Chris. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Sat Oct 16, 2004 10:40 pm Post subject: |
|
|
Well, some good news. By adding the missing NULL arguments, it seemed to work, despite the MSDN documentation saying NULL is okay when you don't use the buffers.
Anyway, the buffers end up empty when returned, so what I think it was trying to do was set the bytesReturned to 0, and it was NULL.
Now the program will run, and successfully calls DeviceIoControl for IOCTL_MOUSE_INSERT_DATA. The next step, is to figure out, in the mouclass.sys file, where to put the data, and I think I know where it goes. I'll be back with more news hopefully soon. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Sat Oct 16, 2004 11:37 pm Post subject: |
|
|
Eureka!
God made the world in 7 days, I make low level macro'd mouse movement in 30, okay, so I'm not god
That's right, I got it working. After all the blood and sweat put into it, my last recompilation of of the mouclass.sys, my first attempt at actually injecting the input into the stream, seems to be moving the cursor. Preliminary numbers of 50x50 put it right by the top left, practically 0x0. This tells me most likely that the value is screen twips, which makes sense for uniform resolution movements. A value of 10000x10000 on a screen resolution of 1280x1024 moved it less than the top quarter of the screen, and 65000x65000 puts it near the bottom right. This solves mouse movements.
And my preliminary tests of mouse clicking works as well. I have not yet tested it with the game, but it works within windows and that gives me a lot of hope.
Another hour or so and I'll be able to test it in the game.
I'll be back with the results soon. |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Sun Oct 17, 2004 12:11 am Post subject: |
|
|
I just read your latest posts and I'm glad you've got your proof of concept working. Here is a reply to that unrelated idea you brought up:
| Quote: | While I cannot site a real world example to demonstrate a use where string parsing couldn't be used, it's a lot less code than having to create a loop anytime you want to work with the string list. I think it would be beneficial to support a generic container type internall. Since you already support strings, and is number checks, you could support a simple string container, and treat the data the same.
...
...queue them into a list of strings, and when the script isn't busy with a simulated delay, it pops the next command of the queue and processes it. |
I'm unclear on the concept of a "container". It may be that the existing support for arrays is enough for what you have in mind. An array can have any number of dimensions and objects, though of course 1-dimensional arrays (i.e. simple stacks, queues, or lists of strings) are the most common.
The particular example you mentioned above can be handled by using SetTimer (which creates a separate thread) or by having multiple scripts running in parellel. It's not elegant, but it keeps the complexity down.
I know it's not as nice as other languages. The current syntax is partially to blame for that: It makes certain things -- such as complex expressions and easier array syntax -- difficult to implement. But in exchange, this same simple syntax is easier to use and remember than that of a more complex language. I feel the trade-off is well worth it, but I know it is a matter of taste and opinion; I wouldn't fault anyone for preferring a real language such as C++ or Python. |
|
| Back to top |
|
 |
Guest Guest
|
Posted: Sun Oct 24, 2004 7:32 pm Post subject: |
|
|
| I'm not really sure how relevant this is, I'm not much of a programmer so I'm not really sure what you guys are talking about, but ZSNES (Super Nintendo Emulator) doesn't work with AutoHotKey either. The only reason I bring it up is because it's open source (it's on sourceforge), so you could see how they do it. At the very least it could be used as another test for you fix. It also hasn't worked with at least one other emulator I've tried it with. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Sun Oct 24, 2004 9:43 pm Post subject: |
|
|
Hey Chris,
I've been using my solution for some time now, when suddenly it's stopped working. Well, that's not entirely accurate.
I have 2 machines I've been running it on. The first machine, this one, opening the handles to keyboard and pointer class work fine, always have (which is why I thought all was well).
Then I started using it on another machine nearby. It worked great for a while, then I tried to open the keyboard handle and I was getting errors that didn't occur on this machine. Basically stating the device is already open and cannot be opened. Sounds like some exclusive locking is going on.
Since I was primarily concerned with mouse, I simply disabled keyboard support and went about my business. Except that for no aparant reason, recently that machine is unable to open the pointer class handle now too. This came out of nowhere, as one night it worked, the next morning it wouldn't. Nothing was installed or updated to my knowledge, and the custom drivers are still in effect.
Thought I would share this issue in case you run into something similar.
In another discussion I was told it might be more user friendly to have the drivers loaded at startup/shutdown of the application, and this should be doable using OpenSCManager, CreateService, DestroyService, and ControlService. If I understand correctly, you could associate the new drivers with new class pointers. Instead of replacing mouclass.sys which is referred to for PointerClass0, you could make PointerClass1 refer to the custom driver, and hopefully that would resolve the issue I've come across in sharing the main pointer driver, as well as the issue you brought up with users having to install drivers as a negative side effect. If the program could create, start, stop, and destroy a pointer class service, I think you'd have the problem solved since in theory, only the first pointer class should be opened by anything since it'd be the only physical mouse driver in use (no physical mouse attached to PointerClass1).
Anyway, I leave you to your work, I hope it'll make it into AutoHotkey, but in truth I've set out what I wanted to accomplish, and don't even think I'll be playing that particular game much longer with World of Warcraft hitting Open Beta soon.
As for the guests suggestion to check out the emulators, I can almost make an assumption that they are using WH_KEYBOARD_LL and WH_MOUSE_LL. It makes sense for emulators, and if they do, it's very possible AutoHotkey couldn't inject input. Though in the case of an emulator where they shouldn't specifically be checking for falsified input, I'd guess it's unrelated to the INJECTED bit and involves something else.
None the less, I'm certain that when these drivers work, they can fool anything running under Windows NT/2000/XP into believing it's real input.
Good luck. |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Mon Oct 25, 2004 12:36 am Post subject: |
|
|
Thanks for the additional info. Given your recent problems with the drivers, I'm less inclined to give the separate/optional driver component a high priority. I still want to look into it, but it's hard to justify spending many days -- and quite probably a week or more -- learning how to do drivers, services, etc. when there are so many other priority items pending.
Much of this is probably just due to fear of the unknown. I've never done it, so it's natural to think that these driver level things are hard and time-consuming. I know you've proved otherwise with your prototype, but you also made a big investment to learn all the intricacies.
As I've said before, I expect the work you've done will benefit myself and/or others -- whoever resumes the work -- in the months to come. So thanks. |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Mon Oct 25, 2004 12:49 am Post subject: |
|
|
| Guest wrote: | | The only reason I bring it up is because it's open source (it's on sourceforge), so you could see how they do it. At the very least it could be used as another test for you fix. It also hasn't worked with at least one other emulator I've tried it with. | Thanks, I've made a note to check it out. |
|
| Back to top |
|
 |
tomcat Guest
|
Posted: Thu Jan 20, 2005 2:32 pm Post subject: MU Online game, autohotkey and DirectInput |
|
|
I don't know if anyone tried to use autohotkey with MU Online or not. But yesterday I wrote a simple script to test with that game and it doesn't work in the game (although when I exit, I see it has effect on other programs). I guess it relates to DirectInput (MU Online using DIrectX). So if the program can support DirectInput, that will be a great help.
BTW, thanks for your program. It's very user-friendly!!! The sad thing is I haven't been able to run it with my favorite game  |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Thu Jan 20, 2005 10:43 pm Post subject: |
|
|
| I don't know how to use DirectInput to inject keystrokes or mouse-clicks into other applications. If an easy way is ever discovered, it would be a high priority to implement it. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Fri Jan 21, 2005 1:15 am Post subject: DirectInput |
|
|
| Chris wrote: | | I don't know how to use DirectInput to inject keystrokes or mouse-clicks into other applications. If an easy way is ever discovered, it would be a high priority to implement it. |
I believe I have some code sitting around somewhere that used madCodeHook to do this. Of course, I'm not an expert in hooking API calls, so madCodeHook was perfect for me, but if you can provide similar mechanisms withing AutoHotkey, I'm certain I could help with the code to hook DirectInput.
Right now, I'm in the process of writing a script engine for WoW, that involves decrypted packets, so my attention is not entirely towards Autohotkey anymore, but if you're interested I'd be willing to write some prototype code using madCodeHook that shows how you can hook DirectInput, I did it once for Everquest in the past, I'm sure it would work with MU (though I hate to be cynical, but MU really isn't worth it). None the less, you could use the same code in a reusable fashion to hook any DirectInput I believe.
Catch you later, sorry I'm not much into this anymore, new ideas lead to new projects  |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Fri Jan 21, 2005 12:37 pm Post subject: |
|
|
Thanks for the info; I hope to look into it more someday.
Given the high demand to simulate DirectInput keystrokes and mouse clicks, I'm surprised no one has come up with a program to do it. Maybe it's just further evidence that there is no easy way. |
|
| Back to top |
|
 |
Astaelan
Joined: 23 Sep 2004 Posts: 34 Location: Canada
|
Posted: Sat Jan 22, 2005 12:04 am Post subject: |
|
|
| Chris wrote: | Thanks for the info; I hope to look into it more someday.
Given the high demand to simulate DirectInput keystrokes and mouse clicks, I'm surprised no one has come up with a program to do it. Maybe it's just further evidence that there is no easy way. |
In my experience it wasn't that difficult, like any other API method, the hard part is actually hooking the code. madCodeHook makes this incredibly easy, perhaps the driving code behind hooking API calls can be written into Autohotkey in your own way.
Basically though, the actual process wasn't that hard. It's been a while, but I remember I hooked the Direct device creation, and from that, hooked the API call involved in creating the DirectInput devices. From there, I was only a short bit of work away from hooking the raw methods that return the input for mice, joysticks and keyboards.
Right now I'm knee deep in another project, but if I ever get bored, I'll come back and try to write a program to hook DirectInput... The downside is, without someone writing some free code similar to madCodeHook, I don't know that I'll be able to figure out the HookAPI() and HookCode equivilent code on my own. |
|
| Back to top |
|
 |
Guest
|
Posted: Sat Jan 22, 2005 2:32 am Post subject: |
|
|
| the same thing happens for me when i tried to implement locking my zonealarm firewall (sending mouse or keyboard strokes failed..) |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|