AutoHotkey Community

It is currently May 27th, 2012, 7:19 am

All times are UTC [ DST ]




Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 134 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7, 8, 9  Next
Author Message
 Post subject:
PostPosted: October 16th, 2004, 9:58 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 16th, 2004, 10:56 pm 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 16th, 2004, 11:40 pm 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 17th, 2004, 12:37 am 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 17th, 2004, 1:11 am 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 24th, 2004, 8:32 pm 
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.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: October 24th, 2004, 10:43 pm 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 25th, 2004, 1:36 am 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 25th, 2004, 1:49 am 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
PostPosted: January 20th, 2005, 3:32 pm 
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 :(


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 20th, 2005, 11:43 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: DirectInput
PostPosted: January 21st, 2005, 2:15 am 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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 :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 21st, 2005, 1:37 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 22nd, 2005, 1:04 am 
Offline

Joined: September 23rd, 2004, 4:56 pm
Posts: 34
Location: Canada
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 22nd, 2005, 3:32 am 
the same thing happens for me when i tried to implement locking my zonealarm firewall (sending mouse or keyboard strokes failed..)


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 134 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7, 8, 9  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 4 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group