TaranVH / 2nd-keyboard

ALL of Taran's scripts - not just for the 2nd keyboard.
https://www.youtube.com/watch?v=O6ERELse_QY
1.65k stars 538 forks source link

Intercept, but done with callbacks #45

Open evilC opened 6 years ago

evilC commented 6 years ago

Hi y'all, just to let you know that I shamelessly stole your idea of wrapping keys to set an AHK context, but I found a sneakier way to do it.
I wrote a C# DLL which wraps interception that you call from AHK via CLR, and pass it an AHK function object, along with a VID / PID.
Any time Interception sees input on that device, it fires that AHK function object, which sets the context variable, then it sends the key, then it fires the code again to unset the context variable.
https://github.com/evilC/AutoHotInterception
See "Context Mode".
I also have a mode where you can register a callback for each key ("Subscription Mode")

TaranVH commented 6 years ago

Uh huh. Uh huh. I understood some of those words.

This looks brilliant. And good on you for taking and modifying one of my ideas! That's why I share them in the first place. Sometimes I hear about other people using AHK to do really cool shit, but they don't share their code, so I can't see how they did it.

I'll definitely mention this in the next "adding additional keyboards" video that i make.

BUT, my key wrapping trick has been remarkably effective -- only failing if you mash several keys at once (it gets confused with so many up and down key events for F23 or whatever)

So, why do you think that it's better to wrap in a variable, rather than a keystroke? I'm sure you must have a good reason...

ONE THING that you might NOT be able to do with your solution, is use modifier keys effectively. https://youtu.be/vhPLhfP1b_s?t=4m29s Look closely at the current state of my K120. Notice the "CTRL" key where Numpad5 is supposed to be? By using interception.exe to modify the up AND down key events of numpad 5, I was able to convert it into a true CTRL key. I'm also going to do the same thing with the S key. In this way, I can hold down that key, and press any other key, to achieve a different result. It's a temporary layer. So, with the wipes, I can have them with hard edges if there is no modifier keys, but use soft, blurry edges if I am holding down CTRL (which has been moved to the S key.) Can your clever script do THAT?? It also doesn't have to be CTRL... it could be anything, really. It's just one additional 'wrapper.'

ALSO, This is still reliant on interception... which, while great, has two serious drawbacks:

Good work, though! Keep on keepin on!

evilC commented 6 years ago

So, why do you think that it's better to wrap in a variable, rather than a keystroke? I'm sure you must have a good reason...

When you press a keyboard key using Intercept, it sends eg F24, which triggers an AHK hotkey, which sets a variable, which enables some hotkeys.
With AHI, it fires a method which sets the variable - you cut out sending a key and the AHK hotkey detection code.
Also, wrapping keys in other keys will most likely break hotstrings (Because the sequence is broken by a key - eg F23 not in the sequence.

I am not sure about the remapping keys to CTRL, I think it will work, I will try when I get home.
However, AHI does have a second mode (Called "Subscription Mode") where you WILL be able to do this. This mode can completely block the key from ever being sent, and fire your own code instead, which you use to set the state of the CTRL key.

This is still reliant on interception... which, while great, has two serious drawbacks

We have entered negotiation with Francisco Lopez to buy a full Interception license, fix this issue, then release a new version. Nefarius (Of ViGEm and SCPToolkit fame) has stepped up to the plate on this one and has volunteered to do the coding and sign the new driver.
We have no plans to charge for the new version.
If the plan is a goer, we will need to crowdfund ~$2000 - can we count on your assistance to help put out the word on this?

As a side note, I have plans to add support for the Elgato StreamDeck to my remapping application UCR - the StreamDeck has an API - we are hoping we can allow binding of stuff to StreamDeck keys, and control the images on the buttons in response.

BTW if you want to chat, you can find me in the HidWizards Discord Channel

evilC commented 6 years ago

I just tried the remap key to ctrl test with the "context" mode and you are indeed correct, it does not work properly.
Thinking about it, in order to do this properly, you must use interception to do the transformation, as if you do it with AHK hotkeys, then $ prefixed hotkeys would not see Ctrl change state.
Currently, AHI has no way of "Sending" via Interception, so I guess I will have to add that.
Also, currently AHI does not support a mix of Context mode and Subscription mode, but that is just because I was lazy while writing the POC - I think it's entirely possible.
Going to sit down now and see if I can alter my C# code to handle these scenarios.

TaranVH commented 6 years ago

You're doing WHAAAAAAAAAAAAAAAAAAAAAAAAAAATTTTTT Paying for the drivers? Making them available?? That's amazing. This could be it. The golden ticket. The ultimate solution. Driver based, works with ANY keyboard, and (hopefully??) not too much of a PITA to set up. This might even be worth another LTT video. I might have to work a bit to convince Linus about this, but I can see it now: A thumbnail with 4 keyboards, and the title:

"∞ keyboards, 1 PC"

If it is EASIER to set this up than luamacros+autohotkey (https://www.youtube.com/watch?v=Arn8ExQ2Gjg) AND it can automatically start itself up when you launch Windows... then, it's the bomb diggity.

Also, that stuff about the stream deck? U da real MVP. Amazing. I really need to learn C++ or whatever, so I can do all this cool stuff myself. I just never have the time...

Yeah, being able to still assign a normal keystroke or hotstring or macro... to a key on a secondary keyboard... is pretty important. I wouldn't wanna give that up.

TaranVH commented 6 years ago

Yes, that kind of remap must be done using interception. Here's where I do it to numpad5 in my keyremap.ini file: https://github.com/TaranVH/2nd-keyboard/blob/5e18c0d1ea5f73e3925dbb7a7a97d126348ec2b8/Intercept/keyremap.ini#L437 See? Very simple, and 100% effective so far. Just one bit of code to change the down event, and another to change the up event.

evilC commented 6 years ago

New release of AutoHotInterception!
You can now mix Context and Subscription modes
Added SendKeyEvent() method to send keys as a specific keyboard.
Sample script included which hard remaps 2 key to Ctrl on a specific keyboard (OS never sees 2 pressed on that keyboard, sees Ctrl instead from that specific keyboard).

Interception.SubscribeKey(GetKeySC("2"), true, Func("KeyEvent"), VID, PID)
keyboardId := Interception.GetDeviceId(VID, PID)
[...]
KeyEvent(state){
    static ctrlCode := GetKeySC("Ctrl")
    global keyboardId
    Interception.SendKeyEvent(ctrlCode, state, keyboardId)
}

Note that with your method, you need to hard-code what the remapping is, but with my method, you can dynamically send any key as a replacement (Or simply just blackhole the key)

evilC commented 6 years ago

AND it can automatically start itself up when you launch Windows... then, it's the bomb diggity

This gives me nightmares.
If I get it wrong, it's entirely possible to lock someone out of their PC.
I think you could save yourself thru safe mode, but obv if they only had one PC, this would mean a "broken" PC that they could not use to look for help on the internet to find out how to enter Safe Mode.

evilC commented 6 years ago

And to be clear, I am not proposing that I pay for the driver, I am proposing that we (The community of people that badly want it) pay for it via crowdfunding. Which is why I am hoping that Linus and yourself are resources that I can draw on, as you have access to a large audience with a proven interest.
Not saying I won't chip into the pot myself, just that I ain't gonna cover it on my own ;)

TaranVH commented 6 years ago

Yes, I understand. I'd chip in, and I'd tweet it out and/or make a video. I'm not sure that Linus would want to post it on social or anything. Also, I thought it was $2200, not $2000.

The way I run my AHK scripts upon startup, (well, upon login to my user account) is to just place a shortcut to the scripts in my startup folder. I guess your thing is a lot more complex, though?

evilC commented 6 years ago

I said ~$2000 ;)
No, placing in the startup folder is all I would do, but with interception, you set a "Predicate" that tells it which keyboards to filter, then all input from that keyboard must be read by your code and (optionally) passed on for that keyboard to do anything (This is what I think is maybe happening with the >10 devices bug - the Predicate still matches, but the processing loop only processes 10 devices)
So therefore, if I mess that up, it could totally block any given keyboard (CTRL+ALT+DEL will not help you, you need to reset or kill the process).
This is less of an issue at the moment, as AHI only supports keyboards, but I can support mouse (Buttons and movement) too, and if/when I expanded to that, it would be possible for ALL input to totally lock up.
So something like that in someone's Startup folder (Especially when the code is new and unproven) makes me a little nervous.

evilC commented 6 years ago

OK off to bed now, I updated the documentation some to add a big fat warning, plus have pinged Lexikos to see if I can find out why I need that Sleep 0 to make hotstrings work.
I also updated the Issue Tracker with a number of known issues and planned enhancements.
By the way, if you are any good at coding, what I am doing is really not hard. In fact, AHI is really simple.
Look, this is the loop that handles key processing for Subscription and Context mode - it's just arrays holding the boundfuncs!

   private void PollThread()
    {
        Stroke stroke = new Stroke();

        while (true)
        {
            for (var i = 1; i < 11; i++)
            {
                var isMonitoredKeyboard = IsMonitoredKeyboard(i) == 1;
                var hasSubscription = false;
                var hasContext = _contextCallbacks.ContainsKey(i);

                while (Receive(_deviceContext, i, ref stroke, 1) > 0)
                {
                    var block = false;
                    if (isMonitoredKeyboard)
                    {
                        // Process Subscription Mode
                        foreach (var mapping in _mappings[i])
                        {
                            if (stroke.key.code != mapping.code) continue;
                            hasSubscription = true;
                            if (mapping.block)
                            {
                                block = true;
                            }
                            mapping.callback(1 - stroke.key.state);
                            break;
                        }
                        // If this key had no subscriptions, but Context Mode is set for this keyboard...
                        // ... then set the Context before sending the key
                        if (!hasSubscription && hasContext)
                        {
                            // Set Context
                            _contextCallbacks[i](1);
                        }
                    }
                    // If the key was not blocked by Subscription Mode, then send it now
                    if (!block)
                    {
                        Send(_deviceContext, i, ref stroke, 1);
                    }
                    // If we are processing Context Mode, then Unset the context variable after sending the key
                    if (!hasSubscription && hasContext)
                    {
                        // Unset Context
                        _contextCallbacks[i](0);
                    }
                }
            }
            Thread.Sleep(10);
        }
    }
evilC commented 6 years ago

Well something. It seems he has set a goal of $400 a month to up the device limit, but no mention of us getting access to the source. Not sure how open I am to ~$5k a year for no guarantee of getting what we want (eg he may address the max limit, but not address what happens if you exceed it).
I was also hoping that if Nefarius got access to the source, he could maybe convert it to being a filter driver, rather than replacing keyboard.sys, which is what Interception does AFAIK, and that scares me somewhat.

oblitum commented 6 years ago

@evilC Dude you have no idea you're talking about, keyboard.sys and mouse.sys are filter drivers, and never replaced anything on Windows. If you had at least listed them with driverquery.exe you would see their descriptions....

oblitum commented 6 years ago

Sharing project ownership with some unknown also doesn't make much sense.

evilC commented 6 years ago

keyboard.sys and mouse.sys are filter drivers, and never replaced anything on Windows

I was basing this on sometimes seeing this error when trying to uninstall Interception: Error deleting \system32\drivers\keyboard.sys
I made the assumption that these were normal windows files, clearly I was wrong. If they are interception-specific, then maybe they should be named as such? It seems this misconception maybe stems from my DOS days when keyboard.sys was a Microsoft file.

Sharing project ownership with some unknown also doesn't make much sense.

I said nothing about "sharing ownership". Could you not release it to him under a license that requires that he keep the source private, and feed back any modifications to you?

oblitum commented 6 years ago

The only kind of full source licenses are already available, that's not negotiable. I can change the drivers just fine myself, better than anyone else, it solely need the required funding (you alone don't need to fund the full $400/month, that doesn't make sense, it's about tipping), it's not because of this that I'll, instead, figure out another license model, while also expending my time on that, for someone else to do it on my behalf.

oblitum commented 6 years ago

@TaranVH Sorry for commenting over this matter here, I think it doesn't make sense for your project, your issue tracker, I'll leave it at that.

TaranVH commented 6 years ago

Nope, totally fine. Keep it going, if need be! Or, link to another thread where we can continue the discussion.

To provide context to anyone else reading this thread: My multi-keyboard video series: https://www.youtube.com/playlist?list=PLH1gH0v9E3ruYrNyRbHhDe6XDfw4sZdZr (The newest video, "An Open Letter to Corsair" is what recently got people interested in Interception)

Initial thread with my comments on Interception's Github: https://github.com/oblitum/Interception/issues/25#issuecomment-308619787

Francisco Lopes crowdfunding: https://liberapay.com/oblita https://www.patreon.com/oblita

oblitum commented 6 years ago

Nope, totally fine.

OK.

Keep it going, if need be!

Sorry, no, thanks.

Or, link to another thread where we can continue the discussion.

To provide context to anyone else reading this thread: My multi-keyboard video series: https://www.youtube.com/playlist?list=PLH1gH0v9E3ruYrNyRbHhDe6XDfw4sZdZr (The newest video, "An Open Letter to Corsair" is what recently got people interested in Interception)

I didn't notice the Corsair video existence until now... I thought interest was due to the previous videos. I even came to know due another one when it was linked here.

Initial thread with my comments on Interception's Github: oblitum/Interception#25 (comment)

Francisco Lopes crowdfunding: https://liberapay.com/oblita https://www.patreon.com/oblita

I guess Patreon should be seen as first, it's the more well known platform for this, but I wanted to leave options. I couldn't set multiple goals on Liberapay as I was able on Patreon, so the Patreon page is also more descriptive on that.

evilC commented 6 years ago

you alone don't need to fund the full $400/month, that doesn't make sense, it's about tipping

What do you think I am, rolling in cash? That was never an option ;)

if I reach my initial goal of $400/month I'll have device limitation extended or removed and will look to buy a new certificate for signing the driver

Until you are pulling in $400 a month, what do Patrons get for their money?
As stated on the Patreon page, $400 covers infrastructure costs
No mention of any work until $800 I can work half-time
Can you clarify the statement "look to buy a new certificate"?

I would not be comfortable driving a fund-raising effort based solely on the existing proposal, it's all too non-committal.
Plus, as I previously noted, there is a "trivial" (Your own words) amount of dev effort involved in making a >10 device limit version of Interception, you helped a customer do it.
Link

As can be read at https://github.com/oblitum/Interception#license. There's a license that gives access to all source code including drivers. With access to them, increasing the limit and doing a custom build is trivial. The only remaining issue is signing, which requires acquiring a certificate to run it on any machine, or using the updated drivers through a self-signed certificate in a machine that's started with TESTSIGNING on. I currently assume it as solved because I've licensed the drivers to companies and helped them doing exactly that. They needed more devices, they licensed drivers sources, signed with their own certificate, and the limit was trivially increased.

So by the current proposed deal, you are perfectly entitled to sit on what we want, and you already effectively have, until you get the costs paid for some projects which we have no interest in (When others like myself and Nefarius burden our own costs, and give away everything free), then you will "look to" buying the cert needed to release the increased device limit Interception.
Seriously, I did not expect this. I would have been comfortable with "You pay for my cert, I release the new version", but not this.

evilC commented 6 years ago

@TaranVH Hi, made a bunch of progress with AutoHotInterception, it's getting pretty mature now.
Also started tinkering with a new technique I thought you might be interested in... basically I am trying to implement per-keyboard hotstrings with autocomplete / predictive text type features and arbitrary text input.
For example, things like OP<Numbers>, eg OP50 to set Opacity to 50%.
https://autohotkey.com/boards/viewtopic.php?p=214420#p214420
Any thoughts?

evilC commented 5 years ago

@TaranVH FYI, we are currently looking into reverse-engineering Interception, and we think we have found out how to remove the 10 device limit. I don't have >10 devices to test with at the moment though, are you interested in helping out?

TaranVH commented 5 years ago

You don't actually need 10 keyboards. Just unplug and re-plug a normal keyboard 10 times! Also, I've moved on from interception, and now use a USB QMK converter thingy. Installing/uninstalling interception and worrying about not being able to plug in my ubikey was just too much of a PITA. Super cool that you're still developing this, though! Best of luck! I hear that reverse engineering a driver is no easy task.

slimpikins commented 5 years ago

im trying to figure out how to make it trigger a string of presses over and over (i.E.) for when afk in game and dont want to get afk kicked. ive look around and theres not much info on this. also im no using hotkey just intercept, as it triggers the key combos i want. but how to have it hit a key wait say a sec and hit the key again? even if it was infinite i could end the program when done and restart it.

anyways thanks to anyone that can help me

Matesaktesak commented 5 years ago

im trying to figure out how to make it trigger a string of presses over and over (i.E.) for when afk in game and dont want to get afk kicked. ive look around and theres not much info on this. also im no using hotkey just intercept, as it triggers the key combos i want. but how to have it hit a key wait say a sec and hit the key again? even if it was infinite i could end the program when done and restart it.

anyways thanks to anyone that can help me

Hey @slimpikins , What you're trying to achieve is MUCH simpler with AHK, in fact, I don't even think you can do that with just interception... So AHK it is! This is an example of an AHK script you can use: F23:: doAnAFKLoop() ` doAnAFKLoop(){ StartPoint: Send W ; Go forward Sleep 1000 ; Sleep for an actual SEC Send S ; Go back Goto StartPoint }`

evilC commented 5 years ago

1) @Matesaktesak That's not a loop, that's a GOTO. This is a loop:

doAnAFKLoop(){
    Loop {
        Send W ; Go forward
        Sleep 1000 ; Sleep for an actual SEC
        Send S ; Go back
    }
}

2) Infinite loops in AHK are bad, as they tie up the one and only thread. You should use SetTimer instead.

SetKeyDelay, 0, 50
keys := ["w", "s"]
idx := 1
return

F12::
toggle := !toggle
if (toggle)
SetTimer, DoLoop, 1000
else
SetTimer, DoLoop, Off
return

DoLoop:
Send % keys[idx]
idx++
if (idx > keys.Length())
idx := 1
return

3) The code will probably hardly move the player, if at all, as you are holding the key for 0 time.
The game will quite possibly only see intermittent keystrokes, as games poll on a loop. Each key should be held for 20-50ms for the game to be able to see it.
Add SetKeyDelay, 0, 50 to the start of the script to fix this

4) The user quite possibly does not need interception at all. If AHK hotkeys do not fire while the game is active (Or the game does not see keys sent by the AHK script), you need to run the script as admin

slimpikins commented 5 years ago

Thank yall. Looks like im installing AHK :( owell. Thanks again for the help.