├── JxqyWpf.sln ├── JxqyWpf ├── App.config ├── App.xaml ├── App.xaml.cs ├── ConfigFile.cs ├── Docusments │ ├── JX3Assist功能设计计划表.xlsx │ ├── Jx3Assist软件设计说明书.docx │ └── Jx3Assist需求分析说明书.docx ├── Interception │ ├── Input.cs │ ├── InterceptionDriver.cs │ ├── Interceptor.csproj │ ├── KeyPressedEventArgs.cs │ ├── Keys.cs │ ├── MousePressedEventArgs.cs │ └── ScrollDirection.cs ├── Jx3AssistConfig.cfg ├── JxqyWpf.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MyApp.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ └── AppIcon.ico ├── Update.cs ├── UpdateWindow.xaml ├── UpdateWindow.xaml.cs └── misc │ ├── AppConfig.ini │ ├── ReadMe.docx │ ├── Release.zip │ ├── ServerUpdate.ini │ ├── Sword Online 3 Assist WPF.exe │ ├── Update.ini │ ├── install-interception.exe │ └── interception.dll ├── README.md └── _config.yml /JxqyWpf.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26206.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JxqyWpf", "JxqyWpf\JxqyWpf.csproj", "{3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Release|Any CPU = Release|Any CPU 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Debug|x64.ActiveCfg = Debug|x64 19 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Debug|x64.Build.0 = Debug|x64 20 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Release|x64.ActiveCfg = Release|x64 23 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /JxqyWpf/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /JxqyWpf/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /JxqyWpf/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace JxqyWpf 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /JxqyWpf/ConfigFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Runtime.InteropServices; 7 | using System.IO; 8 | 9 | namespace JxqyWpf 10 | { 11 | public class ConfigFile 12 | { 13 | [DllImport("kernel32")] 14 | private static extern long GetPrivateProfileString(string section, string key, string defValue, StringBuilder retValue, int size, string filePath); 15 | 16 | 17 | [DllImport("kernel32")] 18 | private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); 19 | 20 | 21 | 22 | public ConfigFile(string inFileName) 23 | { 24 | this.fileName = inFileName; 25 | } 26 | 27 | public void WriteValue(string section, string key, string value) 28 | { 29 | if(File.Exists(fileName)) 30 | { 31 | WritePrivateProfileString(section, key, value, fileName); 32 | } 33 | else 34 | { 35 | ///Do something. 36 | } 37 | } 38 | 39 | public string ReadValue(string section, string key) 40 | { 41 | if(File.Exists(fileName)) 42 | { 43 | StringBuilder ret = new StringBuilder(255); 44 | long i = GetPrivateProfileString(section, key, string.Empty, ret, 255, fileName); 45 | return ret.ToString(); 46 | } 47 | else 48 | { 49 | ///Wrong. 50 | return string.Empty; 51 | } 52 | } 53 | 54 | public bool SetFileName(string inFIleName) 55 | { 56 | this.fileName = inFIleName; 57 | return true; 58 | } 59 | 60 | public string GetFileName() 61 | { 62 | return fileName; 63 | } 64 | 65 | protected string fileName; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /JxqyWpf/Docusments/JX3Assist功能设计计划表.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPG3D/JX3Assist/4310107c59d9d0c1f828f28ab6cbc70a2c21e335/JxqyWpf/Docusments/JX3Assist功能设计计划表.xlsx -------------------------------------------------------------------------------- /JxqyWpf/Docusments/Jx3Assist软件设计说明书.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPG3D/JX3Assist/4310107c59d9d0c1f828f28ab6cbc70a2c21e335/JxqyWpf/Docusments/Jx3Assist软件设计说明书.docx -------------------------------------------------------------------------------- /JxqyWpf/Docusments/Jx3Assist需求分析说明书.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPG3D/JX3Assist/4310107c59d9d0c1f828f28ab6cbc70a2c21e335/JxqyWpf/Docusments/Jx3Assist需求分析说明书.docx -------------------------------------------------------------------------------- /JxqyWpf/Interception/Input.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Runtime.InteropServices; 8 | using System.Windows; 9 | using System.Windows.Input; 10 | 11 | namespace Interceptor 12 | { 13 | public class Input 14 | { 15 | 16 | [DllImport("user32.dll")] 17 | static extern bool SetCursorPos(int x, int y); 18 | 19 | private IntPtr context; 20 | private Thread callbackThread; 21 | 22 | /// 23 | /// Determines whether the driver traps no keyboard events, all events, or a range of events in-between (down only, up only...etc). Set this before loading otherwise the driver will not filter any events and no keypresses can be sent. 24 | /// 25 | public KeyboardFilterMode KeyboardFilterMode { get; set; } 26 | 27 | /// 28 | /// Determines whether the driver traps no events, all events, or a range of events in-between. Set this before loading otherwise the driver will not filter any events and no mouse clicks can be sent. 29 | /// 30 | public MouseFilterMode MouseFilterMode { get; set; } 31 | 32 | public bool IsLoaded { get; set; } 33 | 34 | /// 35 | /// Gets or sets the delay in milliseconds after each key stroke down and up. Pressing a key requires both a key stroke down and up. A delay of 0 (inadvisable) may result in no keys being apparently pressed. A delay of 20 - 40 milliseconds makes the key presses visible. 36 | /// 37 | public int KeyPressDelay { get; set; } 38 | 39 | /// 40 | /// Gets or sets the delay in milliseconds after each mouse event down and up. 'Clicking' the cursor (whether left or right) requires both a mouse event down and up. A delay of 0 (inadvisable) may result in no apparent click. A delay of 20 - 40 milliseconds makes the clicks apparent. 41 | /// 42 | public int ClickDelay { get; set; } 43 | 44 | public int ScrollDelay { get; set; } 45 | 46 | public event EventHandler OnKeyPressed; 47 | public event EventHandler OnMousePressed; 48 | 49 | private int deviceId; /* Very important; which device the driver sends events to */ 50 | 51 | public Input() 52 | { 53 | context = IntPtr.Zero; 54 | 55 | KeyboardFilterMode = KeyboardFilterMode.None; 56 | MouseFilterMode = MouseFilterMode.None; 57 | 58 | KeyPressDelay = 1; 59 | ClickDelay = 1; 60 | ScrollDelay = 15; 61 | } 62 | 63 | /* 64 | * Attempts to load the driver. You may get an error if the C++ library 'interception.dll' is not in the same folder as the executable and other DLLs. MouseFilterMode and KeyboardFilterMode must be set before Load() is called. Calling Load() twice has no effect if already loaded. 65 | */ 66 | public bool Load() 67 | { 68 | if (IsLoaded) return false; 69 | 70 | context = InterceptionDriver.CreateContext(); 71 | 72 | if (context != IntPtr.Zero) 73 | { 74 | callbackThread = new Thread(new ThreadStart(DriverCallback)); 75 | callbackThread.Priority = ThreadPriority.Highest; 76 | callbackThread.IsBackground = true; 77 | callbackThread.Start(); 78 | 79 | IsLoaded = true; 80 | 81 | return true; 82 | } 83 | else 84 | { 85 | IsLoaded = false; 86 | 87 | return false; 88 | } 89 | } 90 | 91 | /* 92 | * Safely unloads the driver. Calling Unload() twice has no effect. 93 | */ 94 | public void Unload() 95 | { 96 | if (!IsLoaded) return; 97 | 98 | if (context != IntPtr.Zero) 99 | { 100 | callbackThread.Abort(); 101 | InterceptionDriver.DestroyContext(context); 102 | IsLoaded = false; 103 | } 104 | } 105 | 106 | private void DriverCallback() 107 | { 108 | InterceptionDriver.SetFilter(context, InterceptionDriver.IsKeyboard, (Int32) KeyboardFilterMode); 109 | InterceptionDriver.SetFilter(context, InterceptionDriver.IsMouse, (Int32) MouseFilterMode); 110 | 111 | Stroke stroke = new Stroke(); 112 | 113 | while (InterceptionDriver.Receive(context, deviceId = InterceptionDriver.Wait(context), ref stroke, 1) > 0) 114 | { 115 | if (InterceptionDriver.IsMouse(deviceId) > 0) 116 | { 117 | if (OnMousePressed != null) 118 | { 119 | var args = new MousePressedEventArgs() { X = stroke.Mouse.X, Y = stroke.Mouse.Y, State = stroke.Mouse.State, Rolling = stroke.Mouse.Rolling }; 120 | OnMousePressed(this, args); 121 | 122 | if (args.Handled) 123 | { 124 | continue; 125 | } 126 | stroke.Mouse.X = args.X; 127 | stroke.Mouse.Y = args.Y; 128 | stroke.Mouse.State = args.State; 129 | stroke.Mouse.Rolling = args.Rolling; 130 | } 131 | } 132 | 133 | if (InterceptionDriver.IsKeyboard(deviceId) > 0) 134 | { 135 | if (OnKeyPressed != null) 136 | { 137 | var args = new KeyPressedEventArgs() { Key = stroke.Key.Code, State = stroke.Key.State}; 138 | OnKeyPressed(this, args); 139 | 140 | if (args.Handled) 141 | { 142 | continue; 143 | } 144 | stroke.Key.Code = args.Key; 145 | stroke.Key.State = args.State; 146 | } 147 | } 148 | 149 | InterceptionDriver.Send(context, deviceId, ref stroke, 1); 150 | } 151 | 152 | Unload(); 153 | throw new Exception("Interception.Receive() failed for an unknown reason. The driver has been unloaded."); 154 | } 155 | 156 | public void SendKey(Keys key, KeyState state) 157 | { 158 | Stroke stroke = new Stroke(); 159 | KeyStroke keyStroke = new KeyStroke(); 160 | 161 | keyStroke.Code = key; 162 | keyStroke.State = state; 163 | 164 | stroke.Key = keyStroke; 165 | 166 | InterceptionDriver.Send(context, deviceId, ref stroke, 1); 167 | 168 | if (KeyPressDelay > 0) 169 | Thread.Sleep(KeyPressDelay); 170 | } 171 | 172 | /// 173 | /// Warning: Do not use this overload of SendKey() for non-letter, non-number, or non-ENTER keys. It may require a special KeyState of not KeyState.Down or KeyState.Up, but instead KeyState.E0 and KeyState.E1. 174 | /// 175 | public void SendKey(Keys key) 176 | { 177 | SendKey(key, KeyState.Down); 178 | 179 | if (KeyPressDelay > 0) 180 | Thread.Sleep(KeyPressDelay); 181 | 182 | SendKey(key, KeyState.Up); 183 | } 184 | 185 | public void SendKeys(params Keys[] keys) 186 | { 187 | foreach (Keys key in keys) 188 | { 189 | SendKey(key); 190 | } 191 | } 192 | 193 | /// 194 | /// Warning: Only use this overload for sending letters, numbers, and symbols (those to the right of the letters on a U.S. keyboard and those obtained by pressing shift-#). Do not send special keys like Tab or Control or Enter. 195 | /// 196 | /// 197 | public void SendText(string text) 198 | { 199 | foreach (char letter in text) 200 | { 201 | var tuple = CharacterToKeysEnum(letter); 202 | 203 | if (tuple.Item2 == true) // We need to press shift to get the next character 204 | SendKey(Keys.LeftShift, KeyState.Down); 205 | 206 | SendKey(tuple.Item1); 207 | 208 | if (tuple.Item2 == true) 209 | SendKey(Keys.LeftShift, KeyState.Up); 210 | } 211 | } 212 | 213 | /// 214 | /// Converts a character to a Keys enum and a 'do we need to press shift'. 215 | /// 216 | private Tuple CharacterToKeysEnum(char c) 217 | { 218 | switch (Char.ToLower(c)) 219 | { 220 | case 'a': 221 | return new Tuple(Keys.A, false); 222 | case 'b': 223 | return new Tuple(Keys.B, false); 224 | case 'c': 225 | return new Tuple(Keys.C, false); 226 | case 'd': 227 | return new Tuple(Keys.D, false); 228 | case 'e': 229 | return new Tuple(Keys.E, false); 230 | case 'f': 231 | return new Tuple(Keys.F, false); 232 | case 'g': 233 | return new Tuple(Keys.G, false); 234 | case 'h': 235 | return new Tuple(Keys.H, false); 236 | case 'i': 237 | return new Tuple(Keys.I, false); 238 | case 'j': 239 | return new Tuple(Keys.J, false); 240 | case 'k': 241 | return new Tuple(Keys.K, false); 242 | case 'l': 243 | return new Tuple(Keys.L, false); 244 | case 'm': 245 | return new Tuple(Keys.M, false); 246 | case 'n': 247 | return new Tuple(Keys.N, false); 248 | case 'o': 249 | return new Tuple(Keys.O, false); 250 | case 'p': 251 | return new Tuple(Keys.P, false); 252 | case 'q': 253 | return new Tuple(Keys.Q, false); 254 | case 'r': 255 | return new Tuple(Keys.R, false); 256 | case 's': 257 | return new Tuple(Keys.S, false); 258 | case 't': 259 | return new Tuple(Keys.T, false); 260 | case 'u': 261 | return new Tuple(Keys.U, false); 262 | case 'v': 263 | return new Tuple(Keys.V, false); 264 | case 'w': 265 | return new Tuple(Keys.W, false); 266 | case 'x': 267 | return new Tuple(Keys.X, false); 268 | case 'y': 269 | return new Tuple(Keys.Y, false); 270 | case 'z': 271 | return new Tuple(Keys.Z, false); 272 | case '1': 273 | return new Tuple(Keys.One, false); 274 | case '2': 275 | return new Tuple(Keys.Two, false); 276 | case '3': 277 | return new Tuple(Keys.Three, false); 278 | case '4': 279 | return new Tuple(Keys.Four, false); 280 | case '5': 281 | return new Tuple(Keys.Five, false); 282 | case '6': 283 | return new Tuple(Keys.Six, false); 284 | case '7': 285 | return new Tuple(Keys.Seven, false); 286 | case '8': 287 | return new Tuple(Keys.Eight, false); 288 | case '9': 289 | return new Tuple(Keys.Nine, false); 290 | case '0': 291 | return new Tuple(Keys.Zero, false); 292 | case '-': 293 | return new Tuple(Keys.DashUnderscore, false); 294 | case '+': 295 | return new Tuple(Keys.PlusEquals, false); 296 | case '[': 297 | return new Tuple(Keys.OpenBracketBrace, false); 298 | case ']': 299 | return new Tuple(Keys.CloseBracketBrace, false); 300 | case ';': 301 | return new Tuple(Keys.SemicolonColon, false); 302 | case '\'': 303 | return new Tuple(Keys.SingleDoubleQuote, false); 304 | case ',': 305 | return new Tuple(Keys.CommaLeftArrow, false); 306 | case '.': 307 | return new Tuple(Keys.PeriodRightArrow, false); 308 | case '/': 309 | return new Tuple(Keys.ForwardSlashQuestionMark, false); 310 | case '{': 311 | return new Tuple(Keys.OpenBracketBrace, true); 312 | case '}': 313 | return new Tuple(Keys.CloseBracketBrace, true); 314 | case ':': 315 | return new Tuple(Keys.SemicolonColon, true); 316 | case '\"': 317 | return new Tuple(Keys.SingleDoubleQuote, true); 318 | case '<': 319 | return new Tuple(Keys.CommaLeftArrow, true); 320 | case '>': 321 | return new Tuple(Keys.PeriodRightArrow, true); 322 | case '?': 323 | return new Tuple(Keys.ForwardSlashQuestionMark, true); 324 | case '\\': 325 | return new Tuple(Keys.BackslashPipe, false); 326 | case '|': 327 | return new Tuple(Keys.BackslashPipe, true); 328 | case '`': 329 | return new Tuple(Keys.Tilde, false); 330 | case '~': 331 | return new Tuple(Keys.Tilde, true); 332 | case '!': 333 | return new Tuple(Keys.One, true); 334 | case '@': 335 | return new Tuple(Keys.Two, true); 336 | case '#': 337 | return new Tuple(Keys.Three, true); 338 | case '$': 339 | return new Tuple(Keys.Four, true); 340 | case '%': 341 | return new Tuple(Keys.Five, true); 342 | case '^': 343 | return new Tuple(Keys.Six, true); 344 | case '&': 345 | return new Tuple(Keys.Seven, true); 346 | case '*': 347 | return new Tuple(Keys.Eight, true); 348 | case '(': 349 | return new Tuple(Keys.Nine, true); 350 | case ')': 351 | return new Tuple(Keys.Zero, true); 352 | case ' ': 353 | return new Tuple(Keys.Space, true); 354 | default: 355 | return new Tuple(Keys.ForwardSlashQuestionMark, true); 356 | } 357 | } 358 | 359 | public void SendMouseEvent(MouseState state) 360 | { 361 | Stroke stroke = new Stroke(); 362 | MouseStroke mouseStroke = new MouseStroke(); 363 | 364 | mouseStroke.State = state; 365 | 366 | if (state == MouseState.ScrollUp) 367 | { 368 | mouseStroke.Rolling = 120; 369 | } 370 | else if (state == MouseState.ScrollDown) 371 | { 372 | mouseStroke.Rolling = -120; 373 | } 374 | 375 | stroke.Mouse = mouseStroke; 376 | 377 | InterceptionDriver.Send(context, 12, ref stroke, 1); 378 | } 379 | 380 | public void SendLeftClick() 381 | { 382 | SendMouseEvent(MouseState.LeftDown); 383 | Thread.Sleep(ClickDelay); 384 | SendMouseEvent(MouseState.LeftUp); 385 | } 386 | 387 | public void SendRightClick() 388 | { 389 | SendMouseEvent(MouseState.RightDown); 390 | Thread.Sleep(ClickDelay); 391 | SendMouseEvent(MouseState.RightUp); 392 | } 393 | 394 | public void ScrollMouse(ScrollDirection direction) 395 | { 396 | switch (direction) 397 | { 398 | case ScrollDirection.Down: 399 | SendMouseEvent(MouseState.ScrollDown); 400 | break; 401 | case ScrollDirection.Up: 402 | SendMouseEvent(MouseState.ScrollUp); 403 | break; 404 | } 405 | } 406 | 407 | /// 408 | /// Warning: This function, if using the driver, does not function reliably and often moves the mouse in unpredictable vectors. An alternate version uses the standard Win32 API to get the current cursor's position, calculates the desired destination's offset, and uses the Win32 API to set the cursor to the new position. 409 | /// 410 | public void MoveMouseBy(int deltaX, int deltaY, bool useDriver = false) 411 | { 412 | if (useDriver) 413 | { 414 | Stroke stroke = new Stroke(); 415 | MouseStroke mouseStroke = new MouseStroke(); 416 | 417 | mouseStroke.X = deltaX; 418 | mouseStroke.Y = deltaY; 419 | 420 | stroke.Mouse = mouseStroke; 421 | stroke.Mouse.Flags = MouseFlags.MoveRelative; 422 | 423 | InterceptionDriver.Send(context, 12, ref stroke, 1); 424 | } 425 | else 426 | { 427 | var currentPos = Mouse.GetPosition(null); 428 | //var currentPos = Cursor.Position; 429 | 430 | SetCursorPos((int)currentPos.X + deltaX, (int)currentPos.Y - deltaY); 431 | //Cursor.Position = new Point(currentPos.X + deltaX, currentPos.Y - deltaY); // Coordinate system for y: 0 begins at top, and bottom of screen has the largest number 432 | } 433 | } 434 | 435 | /// 436 | /// Warning: This function, if using the driver, does not function reliably and often moves the mouse in unpredictable vectors. An alternate version uses the standard Win32 API to set the cursor's position and does not use the driver. 437 | /// 438 | public void MoveMouseTo(int x, int y, bool useDriver = false) 439 | { 440 | if (useDriver) 441 | { 442 | Stroke stroke = new Stroke(); 443 | MouseStroke mouseStroke = new MouseStroke(); 444 | 445 | mouseStroke.X = x; 446 | mouseStroke.Y = y; 447 | 448 | stroke.Mouse = mouseStroke; 449 | stroke.Mouse.Flags = MouseFlags.MoveAbsolute; 450 | 451 | InterceptionDriver.Send(context, 12, ref stroke, 1); 452 | } 453 | { 454 | SetCursorPos(x, y); 455 | //Cursor.Position = new Point(x, y); 456 | } 457 | } 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/InterceptionDriver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace Interceptor 8 | { 9 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 10 | public delegate int Predicate(int device); 11 | 12 | [Flags] 13 | public enum KeyState : ushort 14 | { 15 | Down = 0x00, 16 | Up = 0x01, 17 | E0 = 0x02, 18 | E1 = 0x04, 19 | TermsrvSetLED = 0x08, 20 | TermsrvShadow = 0x10, 21 | TermsrvVKPacket = 0x20 22 | } 23 | 24 | [Flags] 25 | public enum KeyboardFilterMode : ushort 26 | { 27 | None = 0x0000, 28 | All = 0xFFFF, 29 | KeyDown = KeyState.Up, 30 | KeyUp = KeyState.Up << 1, 31 | KeyE0 = KeyState.E0 << 1, 32 | KeyE1 = KeyState.E1 << 1, 33 | KeyTermsrvSetLED = KeyState.TermsrvSetLED << 1, 34 | KeyTermsrvShadow = KeyState.TermsrvShadow << 1, 35 | KeyTermsrvVKPacket = KeyState.TermsrvVKPacket << 1 36 | } 37 | 38 | [Flags] 39 | public enum MouseState : ushort 40 | { 41 | LeftDown = 0x01, 42 | LeftUp = 0x02, 43 | RightDown = 0x04, 44 | RightUp = 0x08, 45 | MiddleDown = 0x10, 46 | MiddleUp = 0x20, 47 | LeftExtraDown = 0x40, 48 | LeftExtraUp = 0x80, 49 | RightExtraDown = 0x100, 50 | RightExtraUp = 0x200, 51 | ScrollVertical = 0x400, 52 | ScrollUp = 0x400, 53 | ScrollDown = 0x400, 54 | ScrollHorizontal = 0x800, 55 | ScrollLeft = 0x800, 56 | ScrollRight = 0x800, 57 | } 58 | 59 | [Flags] 60 | public enum MouseFilterMode : ushort 61 | { 62 | None = 0x0000, 63 | All = 0xFFFF, 64 | LeftDown = 0x01, 65 | LeftUp = 0x02, 66 | RightDown = 0x04, 67 | RightUp = 0x08, 68 | MiddleDown = 0x10, 69 | MiddleUp = 0x20, 70 | LeftExtraDown = 0x40, 71 | LeftExtraUp = 0x80, 72 | RightExtraDown = 0x100, 73 | RightExtraUp = 0x200, 74 | MouseWheelVertical = 0x400, 75 | MouseWheelHorizontal = 0x800, 76 | MouseMove = 0x1000, 77 | } 78 | 79 | [Flags] 80 | public enum MouseFlags : ushort 81 | { 82 | MoveRelative = 0x000, 83 | MoveAbsolute = 0x001, 84 | VirtualDesktop = 0x002, 85 | AttributesChanged = 0x004, 86 | MoveWithoutCoalescing = 0x008, 87 | TerminalServicesSourceShadow = 0x100 88 | } 89 | 90 | [StructLayout(LayoutKind.Sequential)] 91 | public struct MouseStroke 92 | { 93 | public MouseState State; 94 | public MouseFlags Flags; 95 | public Int16 Rolling; 96 | public Int32 X; 97 | public Int32 Y; 98 | public UInt16 Information; 99 | } 100 | 101 | [StructLayout(LayoutKind.Sequential)] 102 | public struct KeyStroke 103 | { 104 | public Keys Code; 105 | public KeyState State; 106 | public UInt32 Information; 107 | } 108 | 109 | [StructLayout(LayoutKind.Explicit)] 110 | public struct Stroke 111 | { 112 | [FieldOffset(0)] public MouseStroke Mouse; 113 | 114 | [FieldOffset(0)] public KeyStroke Key; 115 | } 116 | 117 | /// 118 | /// The .NET wrapper class around the C++ library interception.dll. 119 | /// 120 | public static class InterceptionDriver 121 | { 122 | [DllImport("interception.dll", EntryPoint = "interception_create_context", CallingConvention = CallingConvention.Cdecl)] 123 | public static extern IntPtr CreateContext(); 124 | 125 | [DllImport("interception.dll", EntryPoint = "interception_destroy_context", CallingConvention = CallingConvention.Cdecl)] 126 | public static extern void DestroyContext(IntPtr context); 127 | 128 | [DllImport("interception.dll", EntryPoint = "interception_get_precedence", CallingConvention = CallingConvention.Cdecl)] 129 | public static extern void GetPrecedence(IntPtr context, Int32 device); 130 | 131 | [DllImport("interception.dll", EntryPoint = "interception_set_precedence", CallingConvention = CallingConvention.Cdecl)] 132 | public static extern void SetPrecedence(IntPtr context, Int32 device, Int32 Precedence); 133 | 134 | [DllImport("interception.dll", EntryPoint = "interception_get_filter", CallingConvention = CallingConvention.Cdecl)] 135 | public static extern void GetFilter(IntPtr context, Int32 device); 136 | 137 | [DllImport("interception.dll", EntryPoint = "interception_set_filter", CallingConvention = CallingConvention.Cdecl)] 138 | public static extern void SetFilter(IntPtr context, Predicate predicate, Int32 keyboardFilterMode); 139 | 140 | [DllImport("interception.dll", EntryPoint = "interception_wait", CallingConvention = CallingConvention.Cdecl)] 141 | public static extern Int32 Wait(IntPtr context); 142 | 143 | [DllImport("interception.dll", EntryPoint = "interception_wait_with_timeout", CallingConvention = CallingConvention.Cdecl)] 144 | public static extern Int32 WaitWithTimeout(IntPtr context, UInt64 milliseconds); 145 | 146 | [DllImport("interception.dll", EntryPoint = "interception_send", CallingConvention = CallingConvention.Cdecl)] 147 | public static extern Int32 Send(IntPtr context, Int32 device, ref Stroke stroke, UInt32 numStrokes); 148 | 149 | [DllImport("interception.dll", EntryPoint = "interception_receive", CallingConvention = CallingConvention.Cdecl)] 150 | public static extern Int32 Receive(IntPtr context, Int32 device, ref Stroke stroke, UInt32 numStrokes); 151 | 152 | [DllImport("interception.dll", EntryPoint = "interception_get_hardware_id", CallingConvention = CallingConvention.Cdecl)] 153 | public static extern Int32 GetHardwareId(IntPtr context, Int32 device, String hardwareIdentifier, UInt32 sizeOfString); 154 | 155 | [DllImport("interception.dll", EntryPoint = "interception_is_invalid", CallingConvention = CallingConvention.Cdecl)] 156 | public static extern Int32 IsInvalid(Int32 device); 157 | 158 | [DllImport("interception.dll", EntryPoint = "interception_is_keyboard", CallingConvention = CallingConvention.Cdecl)] 159 | public static extern Int32 IsKeyboard(Int32 device); 160 | 161 | [DllImport("interception.dll", EntryPoint = "interception_is_mouse", CallingConvention = CallingConvention.Cdecl)] 162 | public static extern Int32 IsMouse(Int32 device); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/Interceptor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {C451A00E-77F1-4F3F-B7EE-27DC712EA316} 9 | Library 10 | Properties 11 | Interceptor 12 | Interceptor 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | x64 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | true 36 | bin\x64\Debug\ 37 | DEBUG;TRACE 38 | full 39 | x64 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | 43 | 44 | bin\x64\Release\ 45 | TRACE 46 | true 47 | pdbonly 48 | x64 49 | prompt 50 | MinimumRecommendedRules.ruleset 51 | 52 | 53 | true 54 | bin\x86\Debug\ 55 | DEBUG;TRACE 56 | full 57 | x86 58 | prompt 59 | MinimumRecommendedRules.ruleset 60 | 61 | 62 | bin\x86\Release\ 63 | TRACE 64 | true 65 | pdbonly 66 | x86 67 | prompt 68 | MinimumRecommendedRules.ruleset 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 98 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/KeyPressedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Interceptor 7 | { 8 | public class KeyPressedEventArgs : EventArgs 9 | { 10 | public Keys Key { get; set; } 11 | public KeyState State { get; set; } 12 | public bool Handled { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/Keys.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Interceptor 7 | { 8 | /// 9 | /// A list of scancodes. 10 | /// 11 | /// Scancodes change according to keyboard layout...so this may be inaccurate. 12 | public enum Keys : ushort 13 | { 14 | Escape = 1, 15 | One = 2, 16 | Two = 3, 17 | Three = 4, 18 | Four = 5, 19 | Five = 6, 20 | Six = 7, 21 | Seven = 8, 22 | Eight = 9, 23 | Nine = 10, 24 | Zero = 11, 25 | DashUnderscore = 12, 26 | PlusEquals = 13, 27 | Backspace = 14, 28 | Tab = 15, 29 | Q = 16, 30 | W = 17, 31 | E = 18, 32 | R = 19, 33 | T = 20, 34 | Y = 21, 35 | U = 22, 36 | I = 23, 37 | O = 24, 38 | P = 25, 39 | OpenBracketBrace = 26, 40 | CloseBracketBrace = 27, 41 | Enter = 28, 42 | Control = 29, 43 | A = 30, 44 | S = 31, 45 | D = 32, 46 | F = 33, 47 | G = 34, 48 | H = 35, 49 | J = 36, 50 | K = 37, 51 | L = 38, 52 | SemicolonColon = 39, 53 | SingleDoubleQuote = 40, 54 | Tilde = 41, 55 | LeftShift = 42, 56 | BackslashPipe = 43, 57 | Z = 44, 58 | X = 45, 59 | C = 46, 60 | V = 47, 61 | B = 48, 62 | N = 49, 63 | M = 50, 64 | CommaLeftArrow = 51, 65 | PeriodRightArrow = 52, 66 | ForwardSlashQuestionMark = 53, 67 | RightShift = 54, 68 | RightAlt = 56, 69 | Space = 57, 70 | CapsLock = 58, 71 | F1 = 59, 72 | F2 = 60, 73 | F3 = 61, 74 | F4 = 62, 75 | F5 = 63, 76 | F6 = 64, 77 | F7 = 65, 78 | F8 = 66, 79 | F9 = 67, 80 | F10 = 68, 81 | F11 = 87, 82 | F12 = 88, 83 | Up = 72, 84 | Down = 80, 85 | Right = 77, 86 | Left = 75, 87 | Home = 71, 88 | End = 79, 89 | Delete = 83, 90 | PageUp = 73, 91 | PageDown = 81, 92 | Insert = 82, 93 | PrintScreen = 55, // And break key is 42 94 | NumLock = 69, 95 | ScrollLock = 70, 96 | Menu = 93, 97 | WindowsKey = 91, 98 | NumpadDivide = 53, 99 | NumpadAsterisk = 55, 100 | Numpad7 = 71, 101 | Numpad8 = 72, 102 | Numpad9 = 73, 103 | Numpad4 = 75, 104 | Numpad5 = 76, 105 | Numpad6 = 77, 106 | Numpad1 = 79, 107 | Numpad2 = 80, 108 | Numpad3 = 81, 109 | Numpad0 = 82, 110 | NumpadDelete = 83, 111 | NumpadEnter = 28, 112 | NumpadPlus = 78, 113 | NumpadMinus = 74, 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/MousePressedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Interceptor 7 | { 8 | public class MousePressedEventArgs : EventArgs 9 | { 10 | public MouseState State { get; set; } 11 | public bool Handled { get; set; } 12 | public int X { get; set; } 13 | public int Y { get; set; } 14 | public short Rolling { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /JxqyWpf/Interception/ScrollDirection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Interceptor 7 | { 8 | public enum ScrollDirection 9 | { 10 | Down, 11 | Up 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /JxqyWpf/Jx3AssistConfig.cfg: -------------------------------------------------------------------------------- 1 | HotKey = 41 2 | MacroKey = 44 -------------------------------------------------------------------------------- /JxqyWpf/JxqyWpf.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3B662F2F-0DA0-4F57-A728-A07F33DE6ABA} 8 | WinExe 9 | JxqyWpf 10 | Sword Online 3 Assist WPF 11 | v4.5.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | true 38 | bin\x64\Debug\ 39 | DEBUG;TRACE 40 | full 41 | x64 42 | prompt 43 | MinimumRecommendedRules.ruleset 44 | true 45 | 46 | 47 | bin\x64\Release\ 48 | TRACE 49 | true 50 | pdbonly 51 | x64 52 | prompt 53 | MinimumRecommendedRules.ruleset 54 | true 55 | 56 | 57 | 58 | Resources\AppIcon.ico 59 | 60 | 61 | true 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 4.0 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | MSBuild:Compile 86 | Designer 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | UpdateWindow.xaml 99 | 100 | 101 | MSBuild:Compile 102 | Designer 103 | 104 | 105 | App.xaml 106 | Code 107 | 108 | 109 | MainWindow.xaml 110 | Code 111 | 112 | 113 | Designer 114 | MSBuild:Compile 115 | 116 | 117 | 118 | 119 | Code 120 | 121 | 122 | True 123 | True 124 | Resources.resx 125 | 126 | 127 | True 128 | Settings.settings 129 | True 130 | 131 | 132 | ResXFileCodeGenerator 133 | Resources.Designer.cs 134 | 135 | 136 | SettingsSingleFileGenerator 137 | Settings.Designer.cs 138 | 139 | 140 | 141 | 142 | Designer 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /JxqyWpf/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 |