Creating a wrapper for interception.dll (fixed and working!) Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

21 Jul 2017, 07:35

Ok so the entire screen flashes with the flasher, I wasn't aware of that, I was under the impression it flashed locally wherever the gun was pointed and the rest of the screen was normal. What you've shown changed above shouldn't matter in that case, but I suspect it still shoots bottom right corner and I have a fair Idea of what is causing the behaviour.

I should have thought of this earlier but well didn't, It's likely that fakemouse is using relative coordinates. When a device is captured (i.e. the while loop using the Interception_Receive function) it sets the stroke info (key or mouse stroke) from the device, hence the lightguns report in absolute coordinates. But when a stroke is made up and not captured first (like fakemouse is), it's got nothing in it and so yeah, it needs to be told to use absolute coordinates. So in the SendMousePosition() function, or in the area before the hotkeys but after the line where the fakemouse variable is created, you'll probably need to add:

Code: Select all

fakemouse.flags := 0x001 ; MOUSE_MOVE_ABSOLUTE
if this doesn't work, which I'm pretty confidient it will, the next step is to figure out exactly what flags the device has set when it's captured and recreate them in for the fakemouse variable.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

21 Jul 2017, 11:02

Many thanks, It worked, but I'm having the same problem as before, the flasher gets fired, but over dark areas, the shoot goes to the last shot to a light area, as is the last read.

The flasher whites all the screen. In my testings with the other script I'm using, that works nice (it only fires the flasher and delays the trigger, without blocking the mouse movement), and needs between 15 -30 ms of delaying the trigger after the flashing to be shoot to the correct coordinates in a dark area. That means the shot is fired just while the screen is white.

I can control its duration, I'm using between 15-60 ms deppending on the time the game/emulator needs to read the button. (faster the flash, is better as is less noticeable, when you fast-fire, It is pretty annoying).

Don't know what is the problem, I'll give it another try...
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

21 Jul 2017, 14:55

Many thanks Noesis for the C# wrapper skeleton, it saved me a bunch of time.
I just had a fiddle - in a couple of hours, I managed to write a basic C# wrapper for Interception.

As a proof-of-concept, I mimicked AHK's hotkey functionality - you can register a hotkey and it fires a callback when it changes state. For now, no send or remapping.

Declare a hotkey to X (x:: equivalent):

Code: Select all

#SingleInstance force
#Persistent

; Load CLR library that allows us to load C# DLLs
#include CLR.ahk

; Instantiate class from C# DLL
asm := CLR_LoadLibrary("InterceptionWrapper.dll")
global Interception := asm.CreateInstance("InterceptionWrapper")

; Param 1: Code for key
; Param 2: Block (true/false)
; Param 3: Callback
Interception.SubscribeKey(0x2D, true, Func("KeyEvent"))
return

KeyEvent(state){
	ToolTip % "State: " state
}

^Esc::
	ExitApp
For easy reference, here is the meat of the C# wrapper:

Code: Select all

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;

public class InterceptionWrapper
{
    private IntPtr deviceContext;
    private Thread watcherThread;

    private List<Mapping> Mappings = new List<Mapping>();

    public InterceptionWrapper()
    {
        deviceContext = CreateContext();
        SetFilter(deviceContext, IsKeyboard, Filter.KeyDown | Filter.KeyUp);


        watcherThread = new Thread(WatcherThread);
        watcherThread.Start();
    }

    public bool SubscribeKey(uint code, bool block, dynamic callback)
    {
        Mappings.Add(new Mapping() { code = Convert.ToUInt16(code), block = block, callback = callback });
        return true;
    }

    ~InterceptionWrapper()
    {
        DestroyContext(deviceContext);
    }

    private void WatcherThread()
    {
        Stroke stroke = new Stroke();
        int device = Wait(deviceContext);

        while (true)
        {
            while (Receive(deviceContext, device, ref stroke, 1) > 0)
            {
                if (stroke.key.code == 0x01)
                {
                    break;
                }

                bool block = false;

                foreach (var mapping in Mappings)
                {
                    if (stroke.key.code == mapping.code)
                    {
                        if (mapping.block)
                        {
                            block = true;
                        }
                        mapping.callback(1 - stroke.key.state);
                        break;
                    }
                }
                if (!block)
                {
                    Send(deviceContext, device, ref stroke, 1);
                }
            }
            Thread.Sleep(10);
        }
    }

    private class Mapping
    {
        public ushort code;
        public bool block = false;
        public dynamic callback;
    }
}
C# source code as a Visual Studio SLN is attached.
Demo (Demo script + Pre-built DLLs + CLR.ahk) also attached
Attachments
InterceptionWrapper Source.zip
(78.89 KiB) Downloaded 133 times
InterceptionWrapper Demo.zip
(12.52 KiB) Downloaded 157 times
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

14 Aug 2017, 14:05

FYI, I noticed what appears to be an error in the demo script:

Code: Select all

	if (a_ptrsize > 4)
		DllCall(dll . "\interception_get_hardware_id","Ptr",context,"int",device,"str",buffer,"Uint",500,"Cdecl Int")
	else if (a_ptrsize < 4)
  	DllCall(dll . "\interception_get_hard
A_PtrSize will not be <4 in 32-bit, it will be 4
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

16 Aug 2017, 04:19

Nicely spotted. I must have had my eyes closed when I changed that function locally (or perhaps I can blame search & replace ;) ) either way thanks for the heads up.

Also been meaning to play around with the C# version, but haven't gotten around to it, but looks like it'd work without a problem. Main things it would need to be useful IMO is being able to subscribe based on specific device keys/buttons/movements and also a way of exiting without a hard coded key (i.e. via subscripton for key/button would work but with mouse movements only, this could be an issue, perhaps a way of saying stop now would work. My thoughts are something like, via a function that sets a flag in the C# part that is read each iteration of the loop, and breaks or continues based on the value.)
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

16 Aug 2017, 05:27

I have developed the code I posted some more. Have sending and receiving of buttons working now - you can do it all totally separately of each other - ie you do not need to receive in order to send.
When you start up, call get_hardware_id on numbers 1-20 and you get a complete list of attached devices. It seems that interception only supports 20 devices - 10 keyboards and 10 mice.
ravena1
Posts: 62
Joined: 06 Sep 2017, 15:13

Re: Creating a wrapper for interception.dll (fixed and working!)

16 Sep 2017, 12:41

evilC wrote:Many thanks Noesis for the C# wrapper skeleton, it saved me a bunch of time.
I just had a fiddle - in a couple of hours, I managed to write a basic C# wrapper for Interception.

As a proof-of-concept, I mimicked AHK's hotkey functionality - you can register a hotkey and it fires a callback when it changes state. For now, no send or remapping.

Declare a hotkey to X (x:: equivalent):

Code: Select all

#SingleInstance force
#Persistent

; Load CLR library that allows us to load C# DLLs
#include CLR.ahk

; Instantiate class from C# DLL
asm := CLR_LoadLibrary("InterceptionWrapper.dll")
global Interception := asm.CreateInstance("InterceptionWrapper")

; Param 1: Code for key
; Param 2: Block (true/false)
; Param 3: Callback
Interception.SubscribeKey(0x2D, true, Func("KeyEvent"))
return

KeyEvent(state){
	ToolTip % "State: " state
}

^Esc::
	ExitApp
For easy reference, here is the meat of the C# wrapper:

Code: Select all

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;

public class InterceptionWrapper
{
    private IntPtr deviceContext;
    private Thread watcherThread;

    private List<Mapping> Mappings = new List<Mapping>();

    public InterceptionWrapper()
    {
        deviceContext = CreateContext();
        SetFilter(deviceContext, IsKeyboard, Filter.KeyDown | Filter.KeyUp);


        watcherThread = new Thread(WatcherThread);
        watcherThread.Start();
    }

    public bool SubscribeKey(uint code, bool block, dynamic callback)
    {
        Mappings.Add(new Mapping() { code = Convert.ToUInt16(code), block = block, callback = callback });
        return true;
    }

    ~InterceptionWrapper()
    {
        DestroyContext(deviceContext);
    }

    private void WatcherThread()
    {
        Stroke stroke = new Stroke();
        int device = Wait(deviceContext);

        while (true)
        {
            while (Receive(deviceContext, device, ref stroke, 1) > 0)
            {
                if (stroke.key.code == 0x01)
                {
                    break;
                }

                bool block = false;

                foreach (var mapping in Mappings)
                {
                    if (stroke.key.code == mapping.code)
                    {
                        if (mapping.block)
                        {
                            block = true;
                        }
                        mapping.callback(1 - stroke.key.state);
                        break;
                    }
                }
                if (!block)
                {
                    Send(deviceContext, device, ref stroke, 1);
                }
            }
            Thread.Sleep(10);
        }
    }

    private class Mapping
    {
        public ushort code;
        public bool block = false;
        public dynamic callback;
    }
}
C# source code as a Visual Studio SLN is attached.
Demo (Demo script + Pre-built DLLs + CLR.ahk) also attached

thanks for this
but can i send mouseclicks, mousemove, keyboard press, etc?
simillar to this dd_class like winring https://autohotkey.com/boards/viewtopic.php?t=27007
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

18 Sep 2017, 03:49

Yes you can, but regarding the C# wrapper for interception, I think evilC has only done keyboard stuff in the wrapper at this stage, and hasn't done the mouse stuff, so it's keys only unless you use the ahk wrapper (which would require you to read up on how it would be done via interception natively in order to do it, i.e. it's more bare bones and less user friendly).
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: Creating a wrapper for interception.dll (fixed and working!)

18 Sep 2017, 07:41

When we release our pre-alpha (Am hoping next weekend), I aim to have support for keyboard keys, mouse buttons and mouse movement.
Mouse wheel may or may not be in the initial alpha, as it is a slightly special case.
The ability to turn on/off blocking of inputs will probably not be in the initial version.
The ability to quickly enable / disable subscriptions probably will be in the initial version.

Bear in mind though that we are aiming for a complete end-to-end application, not a library for AHK.
However, it is entirely possible that a wrapper could be written for AHK to let it use our back-end
ravena1
Posts: 62
Joined: 06 Sep 2017, 15:13

Re: Creating a wrapper for interception.dll (fixed and working!)

19 Sep 2017, 06:01

evilC wrote:When we release our pre-alpha (Am hoping next weekend), I aim to have support for keyboard keys, mouse buttons and mouse movement.
Mouse wheel may or may not be in the initial alpha, as it is a slightly special case.
The ability to turn on/off blocking of inputs will probably not be in the initial version.
The ability to quickly enable / disable subscriptions probably will be in the initial version.

Bear in mind though that we are aiming for a complete end-to-end application, not a library for AHK.
However, it is entirely possible that a wrapper could be written for AHK to let it use our back-end

looking forward for this! im so excited :)
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

08 Oct 2017, 18:28

Hi, after some more testing, now I think I knwo what is the problem with the code Noesis helped me with:
At first I though that whenever I used MOUSE_MOVE there was some lag causing my flash not to concur with the click.
But I'm pretty sure the problem is that the coordinates are not gotten when I want:

Code: Select all

  else if is_mouse(device)
	{
		get_keyname(mouse,name,state) ; MAYBE COORDINATES ARE GOTTEN FROM HERE?

		if  (device = gun1id || device = gun2id)
		{
			if name=LButton
			{
				if (state = 1)
				{	
					if  (device = gun1id)
						flasher := gun1flasher
					if  (device = gun2id)
						flasher := gun2flasher
						
					send %flasher%
					sleep, %triggerdelay%
					send(context,device,mouse,1); ACTUALLY I NEED GET COORDINATES IN THIS MOMENT
					sleep, %triggerlength%
					mouse.state := 2
					send(context,device,mouse,1)
				}
			}
			else
			send(context,device,mouse,1)
			}
		else
		send(context,device,mouse,1)
	}
So, how can I get the mouse coordinates in that time?
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

08 Oct 2017, 23:05

Mouse coordinates are gotten from where you have the comment, but they aren't only coordinates, they are events, so it may be a movement event or may be button press or may be a different mouse device, hence the checks afterwards.

The actions associated with movement (after filtering on device) are located in the else, along with anything that is NOT a LButton press but is one of the devices you're interested in, i.e. "if name=LButton {....} else { ... move mouse or do anything that isn't a LButton ... }.

Only one event happens at a time, there is never two things happening at exactly the same time, and remember each button press is one event i.e. button down and there is another event for releasing the button (i.e. button up), hence there is the line "mouse.state := 2", then another line sending the mouse again with that state. So when the button is pressed, it is automatically released.

Where you have the comment about needing to get the coordinates at a particular moment, you quite frankly can't get them there, the coordinates aren't present in that particular event as it's a mouse button press (moves don't happen at exactly the same time as button presses or releases, they happen slightly before/after).

Where the lag is likely happening is with the sleeps. This isn't the code I last gave you btw, and I would expect the above code to lag as it's sleeping during the event processing. What that means is that while it's processing events, (receiving them, then doing stuff with them), there are times it sleeps. When those sleeps happen, the entire event handling for the computer is also sleeping, NOTHING new can be received, and NOTHING new is processed, and NOTHING new is sent. For all intents and purpose, the computers mice & keyboards are no longer connected to your computer during those sleeps, and are only functional again when the sleep is over.

Have another look at the Latest code I posted, you'll see there are multiple scripts, one for event handling which does little more than report to another script. That other script basically tracks what is reported by the first and does the actions required when the reports come in, and it does it using more than one script to avoid the situation given above.

Another possibility is to look at the interception filters and consider what actually needs to be filtered. It may be that the mouse move filter isn't actually needed (as I think you said after I asked you to isolate what was happening, that the gun shot went to wherever the mouse was without scripts running). If you don't filter on mouse move, then those events will be ignored by interception and so won't be captured or reported, so that may be what you need to do, i.e. filter on Left Mouse Button "down" and/or "up" events only.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

09 Oct 2017, 12:33

This isn't the code I last gave you btw,
It's true, but as it is simpler and I notice the main problem is not the lag i used this. If I can solve It, I will return to the last codes you did, were working but I have this same problem.
It may be that the mouse move filter isn't actually needed (as I think you said after I asked you to isolate what was happening, that the gun shot went to wherever the mouse was without scripts running)
I do need filter mous_move, because guns are always tracking, so I need to block them and only unblock the one wich shot, else shots gets crossed between them indistinctly.
I also would need to take the coordinates on when the flash is running, else the gun shoots and the screen is dark, and an offscreen shoot gets returned.
It's not easy to explain...

maybe something like this? simulating a mousebutton4 click "0x040" when the flash is launched and wait for it "if (state = 0x040)", would force to get coordinates in that moment?

Code: Select all

  else if is_mouse(device)
	{
		get_keyname(mouse,name,state)

		if  (device = gun1id || device = gun2id)
		{
			;if name=LButton 
			;{
				if (state = 1)
				{	
					if  (device = gun1id)
						flasher := gun1flasher
					if  (device = gun2id)
						flasher := gun2flasher
						
					send %flasher%
					sleep, %triggerdelay%
					mouse.state := 0x040
					send(context,device,mouse,1)
				}
				if (state = 0x040)
				{	
					mouse.state := 1
					send(context,device,mouse,1)
					sleep, %triggerlength%
					mouse.state := 2
					send(context,device,mouse,1)
				}
				;else (NOT NEEDED, ELSE MOVEMENT GETS UNLOCKED)
				;send(context,device,mouse,1)
			;}
		}
	}
	
	
I'll try this night and share results.
thanks for the help!
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

10 Oct 2017, 10:52

It seems the simulated button4 is not read "mouse.state := 0x040". Do you think I can something similar with your last scripts? the point is to get the coordinates just after the flash
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

12 Oct 2017, 00:53

Yes, the last scripts essentially track mouse movements until the trigger is pulled. When that happens that device isn't tracked again until the trigger is released. It does this by sending a message to the other script, which stores the coordinates, but the message only sends when the trigger is released, so in the script "lighgun.ahk" where the actual keys and mouse moves are sent when the trigger is pressed, is where you need to change this. Currently it sends the mouse position before the flash key, you could change it there, and it's what I expected you to do as I was only guessing the actual order the events needed to be generated in, but the code should be pretty self explanatory as to what action each line is doing, the mouse postion is sent with the SendMousePosition() function for example, just leave the arguments the same, and move or copy the line to another spot, to change the order of the events, or send the same coordinates more than once in the event chain.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

12 Oct 2017, 04:42

Sorry for being almost repetitive, but it's a little complicated to explain lightguns behavior.
the mouse postion is sent with the SendMousePosition()
yes, I have already tried changing this line position, but there is no change.
I'm pretty confident the problem is when I'm getting the coordinates not when I'm using them.
so although I'm having LightGun.ahk this way:

Code: Select all

FirePressed(flasher,trigger,gun)
{
	Global

	send, %flasher%
	sleep(15)
	SendMousePosition(Dev.Gun[gun],GunPos[gun].x,GunPos[gun].y); COORDINATES USED AFTER THE FLASH
	Send, {%trigger% down}
	sleep(60)
	Send, {%trigger% up}

	Return
}
this mouse position is taken from before the flashing, so if I'm pointing a dark area, it is incorrect ( it returns the last shot on a light area position).
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

13 Oct 2017, 00:56

Try putting the same line both before and after the flasher, the issue IMO is the flasher needs to be given coordinates to flash (I guess) so put it before flasher, then I'm not sure what the issue is if it's only before the flasher, but if there is an issue, and you think it needs a report after the flasher put it there too, it's only going to do say mouse is move to exactly the same spot, but perhaps it does need to be spammed a bit. i.e. Copy the line.
phasermaniac
Posts: 74
Joined: 09 Apr 2017, 14:05

Re: Creating a wrapper for interception.dll (fixed and working!)

14 Oct 2017, 05:22

No changes, I think I tried this already.
In my understanding, when I press trigger it unlocks these gun inputs, and get the coords, then launch the flash and use these coordinates, but as they are get before the flash, they are incorrect, I would need to unlock this gun inputs in this moment, and then launch the click
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Creating a wrapper for interception.dll (fixed and working!)

14 Oct 2017, 06:42

The gun inputs are never actually unblocked, they are only ever sent via proxy, at the timings that I was led to believe they needed to be.

If the coordinates are incorrect, then you'll have to work out why (I can't test any of this, I don't have a light gun or any other device that resembles one, or any device that uses absolute coordinates.) The flasher program is a black box to me, again I can't see it and don't know what it does or where it does it other than at the mouse position, in dark areas, but apparently at the wrong spot. There were posts from helgef that might help if you need to do some sort of conversion with the position of the mouse coordinates reported, but to be honest only you can see the coordinates being reported and where they should actually be, nobody else has your hardware and is capable of seeing or testing what is happening.

The bottom line is you need to do repeatable tests and work out exactly what is going on without any vague guesses (i.e. put in diagnostics to see figures of what is being reported as the mouse position, plug in arbitrary coordinates to work out where the flasher programs flash is actually occurring compared to what it "should" be, i.e test & troubleshoot it). I have trouble understanding how the flasher isn't flashing at the right spot when the shot is in a dark area, but the shot is in the correct spot when it's a light area, surely the flasher is simply always flashing the wrong spot, it's just it doesn't matter to the game unless it's a dark area. It suggests to me the flasher is using different coordinates to what the game is using hence you probably need to put in some sort of conversion so the flasher flashes the same spot as the game sees the shot regardless of whether the shot is on a dark or light area. But nobody other than you can work that out.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: garry, Google [Bot], wilkster and 137 guests