Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	C#/AutoHotInterception/Manager.cs
#	C#/AutoHotInterception/Monitor.cs
#	CHANGELOG.md
pull/32/head
Jovan Nikolov 5 years ago
commit d9f1460c3f

@ -46,7 +46,7 @@ namespace AutoHotInterception.Helpers
/// <param name="btn">0 = LMB, 1 = RMB etc</param>
/// <param name="state">1 = Press, 0 = Release</param>
/// <returns>A State value for a Mouse Stroke</returns>
public static ManagedWrapper.Stroke ButtonAndStateToStroke(int btn, int state)
public static ManagedWrapper.Stroke MouseButtonAndStateToStroke(int btn, int state)
{
var stroke = new ManagedWrapper.Stroke();
var power = btn < 5 ? btn * 2 + (state == 0 ? 1 : 0) : btn + 5;
@ -55,7 +55,7 @@ namespace AutoHotInterception.Helpers
return stroke;
}
public static ButtonState StrokeStateToButtonState(ManagedWrapper.Stroke stroke)
public static ButtonState MouseStrokeToButtonState(ManagedWrapper.Stroke stroke)
{
int state = stroke.mouse.state;
ushort btn = 0;
@ -79,6 +79,50 @@ namespace AutoHotInterception.Helpers
return new ButtonState {Button = btn, State = state};
}
public static KeyboardState KeyboardStrokeToKeyboardState(ManagedWrapper.Stroke stroke)
{
var code = stroke.key.code;
var state = stroke.key.state;
var retVal = new KeyboardState();
if (code == 54) code = 310;
// If state is shifted up by 2 (1 or 2 instead of 0 or 1), then this is an "Extended" key code
if (state > 1)
{
if (code == 42 || state > 3)
{
// code == 42
// Shift (42/0x2a) with extended flag = the key after this one is extended.
// Example case is Delete (The one above the arrow keys, not on numpad)...
// ... this generates a stroke of 0x2a (Shift) with *extended flag set* (Normal shift does not do this)...
// ... followed by 0x53 with extended flag set.
// We do not want to fire subsriptions for the extended shift, but *do* want to let the key flow through...
// ... so that is handled here.
// When the extended key (Delete in the above example) subsequently comes through...
// ... it will have code 0x53, which we shift to 0x153 (Adding 256 Dec) to signify extended version...
// ... as this is how AHK behaves with GetKeySC()
// state > 3
// Pause sends code 69 normally as state 0/1, but also LCtrl (29) as state 4/5
// Ignore the LCtrl in this case
// Set flag to indicate ignore
retVal.Ignore = true;
}
else
{
// Extended flag set
// Shift code up by 256 (0x100) to signify extended code
code += 256;
state -= 2;
}
}
retVal.Code = code;
retVal.State = (ushort) (1 - state);
return retVal;
}
public class DeviceInfo
{
public int Id { get; set; }
@ -93,5 +137,12 @@ namespace AutoHotInterception.Helpers
public ushort Button { get; set; }
public int State { get; set; }
}
public class KeyboardState
{
public ushort Code { get; set; }
public ushort State { get; set; }
public bool Ignore { get; set; }
}
}
}

@ -315,7 +315,7 @@ namespace AutoHotInterception
{
IsValidDeviceId(true, id);
var stroke = ButtonAndStateToStroke(btn, state);
var stroke = MouseButtonAndStateToStroke(btn, state);
ManagedWrapper.Send(_deviceContext, id, ref stroke, 1);
}
@ -329,7 +329,7 @@ namespace AutoHotInterception
/// <param name="y"></param>
public void SendMouseButtonEventAbsolute(int id, int btn, int state, int x, int y)
{
var stroke = ButtonAndStateToStroke(btn, state);
var stroke = MouseButtonAndStateToStroke(btn, state);
stroke.mouse.x = x;
stroke.mouse.y = y;
stroke.mouse.flags = (ushort) ManagedWrapper.MouseFlag.MouseMoveAbsolute;
@ -544,49 +544,25 @@ namespace AutoHotInterception
if (isMonitoredKeyboard && _keyboardMappings.ContainsKey(i))
{
// Process Subscription Mode
var code = stroke.key.code;
var state = stroke.key.state;
#region KeyCode, State, Extended Flag translation
// Begin translation of incoming key code, state, extended flag etc...
var processMappings = true;
// Interception seems to report Right Shift as 54 / 0x36 with state 0/1...
// ... this code is normally unused (Alt-SysRq according to linked page) ...
// ... and AHK uses 54 + 256 = 310 (0x36 + 0x100 = 0x136)...
// ... so change the code, but leave the state as 0/1
if (code == 54) code = 310;
// If state is shifted up by 2 (1 or 2 instead of 0 or 1), then this is an "Extended" key code
if (state > 1)
var processedState = KeyboardStrokeToKeyboardState(stroke);
#endregion
if (processedState.Ignore)
{
if (code == 42)
{
// Shift (42/0x2a) with extended flag = the key after this one is extended.
// Example case is Delete (The one above the arrow keys, not on numpad)...
// ... this generates a stroke of 0x2a (Shift) with *extended flag set* (Normal shift does not do this)...
// ... followed by 0x53 with extended flag set.
// We do not want to fire subscriptions for the extended shift, but *do* want to let the key flow through...
// ... so that is handled here.
// When the extended key (Delete in the above example) subsequently comes through...
// ... it will have code 0x53, which we shift to 0x153 (Adding 256 Dec) to signify extended version...
// ... as this is how AHK behaves with GetKeySC()
// Set flag to stop Context Mode from firing
hasSubscription = true;
// Set flag to indicate disable mapping processing
processMappings = false;
}
else
{
// Extended flag set
// Shift code up by 256 (0x100) to signify extended code
code += 256;
state -= 2;
}
// Set flag to stop Context Mode from firing
hasSubscription = true;
// Set flag to indicate disable mapping processing
processMappings = false;
}
#endregion
var code = processedState.Code;
var state = processedState.State;
// Code and state now normalized, proceed with checking for subscriptions...
if (processMappings && _keyboardMappings[i].ContainsKey(code))
@ -633,7 +609,7 @@ namespace AutoHotInterception
{
// Mouse Button
//Debug.WriteLine($"AHK| Mouse {i} seen - flags: {stroke.mouse.flags}, raw state: {stroke.mouse.state}");
var btnState = StrokeStateToButtonState(stroke);
var btnState = MouseStrokeToButtonState(stroke);
if (_mouseButtonMappings[i].ContainsKey(btnState.Button))
{
hasSubscription = true;

@ -102,30 +102,102 @@ namespace AutoHotInterception
while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
{
ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
FireKeyboardCallback(i, stroke);
var processedState = KeyboardStrokeToKeyboardState(stroke);
if (processedState.Ignore)
FireKeyboardCallback(i, new KeyboardCallback
{
Id = i,
Code = stroke.key.code,
State = stroke.key.state,
Info = "Ignored - showing raw values"
});
else
FireKeyboardCallback(i, new KeyboardCallback
{
Id = i,
Code = processedState.Code,
State = processedState.State,
Info = stroke.key.code > 255 ? "Extended" : ""
});
}
for (var i = 11; i < 21; i++)
while (ManagedWrapper.Receive(_deviceContext, i, ref stroke, 1) > 0)
{
ManagedWrapper.Send(_deviceContext, i, ref stroke, 1);
FireMouseCallback(i, stroke);
if (stroke.mouse.state != 0)
{
// Mouse Button
var btnState = MouseStrokeToButtonState(stroke);
FireMouseCallback(new MouseCallback
{
Id = i,
Code = btnState.Button,
State = btnState.State,
Info = "Mouse Button"
});
}
else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveAbsolute) ==
(ushort) ManagedWrapper.MouseFlag.MouseMoveAbsolute)
{
// Absolute Mouse Move
FireMouseCallback(new MouseCallback
{
Id = i,
X = stroke.mouse.x,
Y = stroke.mouse.y,
Info = "Absolute Move"
});
}
else if ((stroke.mouse.flags & (ushort) ManagedWrapper.MouseFlag.MouseMoveRelative) ==
(ushort) ManagedWrapper.MouseFlag.MouseMoveRelative)
{
// Relative Mouse Move
FireMouseCallback(new MouseCallback
{
Id = i,
X = stroke.mouse.x,
Y = stroke.mouse.y,
Info = "Relative Move"
});
}
//FireMouseCallback(i, stroke);
}
Thread.Sleep(10);
}
}
private void FireKeyboardCallback(int id, ManagedWrapper.Stroke stroke)
private void FireKeyboardCallback(int id, KeyboardCallback data)
{
ThreadPool.QueueUserWorkItem(threadProc =>
_keyboardCallback(id, stroke.key.state, stroke.key.code, stroke.key.information));
_keyboardCallback(data.Id, data.Code, data.State, data.Info));
}
private void FireMouseCallback(int id, ManagedWrapper.Stroke stroke)
private void FireMouseCallback(MouseCallback data)
{
ThreadPool.QueueUserWorkItem(threadProc => _mouseCallback(id, stroke.mouse.state, stroke.mouse.flags,
stroke.mouse.rolling, stroke.mouse.x, stroke.mouse.y, stroke.mouse.information));
ThreadPool.QueueUserWorkItem(threadProc =>
_mouseCallback(data.Id, data.Code, data.State, data.X, data.Y, data.Info));
}
public class MouseCallback
{
public int Id { get; set; }
public int Code { get; set; }
public int State { get; set; }
public int X { get; set; }
public int Y { get; set; }
public string Info { get; set; } = "";
}
public class KeyboardCallback
{
public int Id { get; set; }
public int Code { get; set; }
public int State { get; set; }
public string Info { get; set; } = "";
}
#endregion

@ -10,7 +10,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- "Unsubscription Example.ahk" to demo Subscribe / Unsubscribe
### Changed
- By default the new concurrency switch will be set to false meaning that for every subscription there will be only a single worker thread and callbacks will be run sequentially.
- Monitor now outputs data as would be seen in Subscription mode, rather than as it comes raw from Interception
- Monitor now shows key names
### Deprecated
### Removed
### Fixed
- SubscribeMouseMove endpoint fixed to not return bool (Fix "Can not implicitly convert type Void to object" error)
- SubscribeMouseMove endpoint fixed to not return bool (Fix "Can not implicitly convert type Void to object" error)
- Pause button now works

@ -44,10 +44,11 @@ GuiControl, +g, % hCbFilterMove, % fn
Gui, Add, Button, xm w%colWidth% Center gClearKeyboard, Clear
Gui, Add, Button, x+5 yp w%colWidth% gClearMouse Center, Clear
Gui, Add, ListView, xm w%colWidth% h400 hwndhLvKeyboard, ID|State|Code|Info
Gui, Add, ListView, x+5 yp w%colWidth% h400 hwndhLvMouse, ID|State|Flags|Rolling|X|Y|Info
LV_ModifyCol(5, 50)
LV_ModifyCol(6, 50)
Gui, Add, ListView, xm w%colWidth% h400 hwndhLvKeyboard, ID|Code|State|Key Name|Info
LV_ModifyCol(4, 100)
LV_ModifyCol(5, 150)
Gui, Add, ListView, x+5 yp w%colWidth% h400 hwndhLvMouse, ID|Code|State|X|Y|Info
LV_ModifyCol(6, 200)
Gui, Show
@ -80,20 +81,22 @@ FormatHex(num){
return Format("{:04X}", num)
}
KeyboardEvent(id, state, code, info){
KeyboardEvent(id, code, state, info){
global hLvKeyboard
Gui, ListView, % hLvKeyboard
row := LV_Add(, id, state, code, info)
scanCode := Format("{:x}", code)
keyName := GetKeyName("SC" scanCode)
row := LV_Add(, id, code, state, keyName, info)
LV_Modify(row, "Vis")
;~ ToolTip % "Keybd: " id "`nState: " state ", Code: " code
}
MouseEvent(id, state, flags, rolling, x, y, info){
MouseEvent(id, code, state, x, y, info){
global hLvMouse, filterMouseMove
if (filterMouseMove && !state)
if (filterMouseMove && (x != 0 || y != 0))
return
Gui, ListView, % hLvMouse
row := LV_Add(, id, state, flags, rolling, x, y, info)
row := LV_Add(, id, code, state, x, y, info)
LV_Modify(row, "Vis")
;~ ToolTip % "Mouse: " id "`nX: " x ", Y: " y
}

@ -50,7 +50,9 @@ You will need to know the VID / PID of at least one of your devices in order to
DO NOT use the "Clone or Download" link on the main page.
This is the folder where (at least initially) you will be running scripts from.
It contains a number of sample `.ahk` scripts and a `lib` folder, which contains all the libraries and files needed for AHI.
3. Extract both `x86` and `x64` folders from the `library` folder in `interception.zip` into the `lib` folder that was created in step (2).
AHI comes with the latest x86 Interception dll, so as long as you are running x86 AHK (x86 Unicode is recommended), then you can probably skip step 3.
3. In the Interception installer zip, there is a `library` folder containing `x86` and `x64` folders.
From the folder that matches the bitness of AHK you have installed, take `interception.dll` and copy it to the AHI `lib` folder that was created in step (2).
4. Right-click `Unblocker.ps1` in the lib folder and select `Run as Admin`.
This is because downloaded DLLs are often blocked and will not work.
This can be done manually by right clicking the DLLs, selecting Properties, and checking a "Block" box if it exists.

Loading…
Cancel
Save