DATA.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Diagnostics; 7 using System.Diagnostics.CodeAnalysis; 8 using System.Runtime.InteropServices; 9 10 // In X64, we are WOW 11 [module: SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Scope = "type", Target = "MouseWithoutBorders.Core.DATA", Justification = "Dotnet port with style preservation")] 12 13 // <summary> 14 // Package format/conversion. 15 // </summary> 16 // <history> 17 // 2008 created by Truong Do (ductdo). 18 // 2009-... modified by Truong Do (TruongDo). 19 // 2023- Included in PowerToys. 20 // </history> 21 namespace MouseWithoutBorders.Core; 22 23 // The beauty of "union" in C# 24 [StructLayout(LayoutKind.Explicit)] 25 internal sealed class DATA 26 { 27 [FieldOffset(0)] 28 internal PackageType Type; // 4 (first byte = package type, 1 = checksum, 2+3 = magic no.) 29 30 [FieldOffset(sizeof(PackageType))] 31 internal int Id; // 4 32 33 [FieldOffset(sizeof(PackageType) + sizeof(uint))] 34 internal ID Src; // 4 35 36 [FieldOffset(sizeof(PackageType) + (2 * sizeof(uint)))] 37 internal ID Des; // 4 38 39 [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))] 40 internal long DateTime; 41 42 [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)) + sizeof(long))] 43 internal KEYBDDATA Kd; 44 45 [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))] 46 internal MOUSEDATA Md; 47 48 [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))] 49 internal ID Machine1; 50 51 [FieldOffset(sizeof(PackageType) + (4 * sizeof(uint)))] 52 internal ID Machine2; 53 54 [FieldOffset(sizeof(PackageType) + (5 * sizeof(uint)))] 55 internal ID Machine3; 56 57 [FieldOffset(sizeof(PackageType) + (6 * sizeof(uint)))] 58 internal ID Machine4; 59 60 [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))] 61 internal ClipboardPostAction PostAction; 62 63 [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)))] 64 private long machineNameP1; 65 66 [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + sizeof(long))] 67 private long machineNameP2; 68 69 [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + (2 * sizeof(long)))] 70 private long machineNameP3; 71 72 [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + (3 * sizeof(long)))] 73 private long machineNameP4; 74 75 internal string MachineName 76 { 77 get 78 { 79 string name = Common.GetString(BitConverter.GetBytes(machineNameP1)) 80 + Common.GetString(BitConverter.GetBytes(machineNameP2)) 81 + Common.GetString(BitConverter.GetBytes(machineNameP3)) 82 + Common.GetString(BitConverter.GetBytes(machineNameP4)); 83 return name.Trim(); 84 } 85 86 set 87 { 88 byte[] machineName = Common.GetBytes(value.PadRight(32, ' ')); 89 machineNameP1 = BitConverter.ToInt64(machineName, 0); 90 machineNameP2 = BitConverter.ToInt64(machineName, 8); 91 machineNameP3 = BitConverter.ToInt64(machineName, 16); 92 machineNameP4 = BitConverter.ToInt64(machineName, 24); 93 } 94 } 95 96 public DATA() 97 { 98 } 99 100 public DATA(byte[] initialData) 101 { 102 Bytes = initialData; 103 } 104 105 internal byte[] Bytes 106 { 107 get 108 { 109 byte[] buf = new byte[IsBigPackage ? Package.PACKAGE_SIZE_EX : Package.PACKAGE_SIZE]; 110 Array.Copy(StructToBytes(this), buf, IsBigPackage ? Package.PACKAGE_SIZE_EX : Package.PACKAGE_SIZE); 111 112 return buf; 113 } 114 115 set 116 { 117 Debug.Assert(value.Length <= Package.PACKAGE_SIZE_EX, "Length > package size"); 118 byte[] buf = new byte[Package.PACKAGE_SIZE_EX]; 119 Array.Copy(value, buf, value.Length); 120 BytesToStruct(buf, this); 121 } 122 } 123 124 internal bool IsBigPackage 125 { 126 get => Type == 0 127 ? throw new InvalidOperationException("Package type not set.") 128 : Type switch 129 { 130 PackageType.Hello or PackageType.Awake or PackageType.Heartbeat or PackageType.Heartbeat_ex or PackageType.Handshake or PackageType.HandshakeAck or PackageType.ClipboardPush or PackageType.Clipboard or PackageType.ClipboardAsk or PackageType.ClipboardImage or PackageType.ClipboardText or PackageType.ClipboardDataEnd => true, 131 _ => (Type & PackageType.Matrix) == PackageType.Matrix, 132 }; 133 } 134 135 private byte[] StructToBytes(object structObject) 136 { 137 byte[] bytes = new byte[Package.PACKAGE_SIZE_EX]; 138 GCHandle bHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 139 Marshal.StructureToPtr(structObject, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), false); 140 bHandle.Free(); 141 return bytes; 142 } 143 144 private void BytesToStruct(byte[] value, object structObject) 145 { 146 GCHandle bHandle = GCHandle.Alloc(value, GCHandleType.Pinned); 147 Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(value, 0), structObject); 148 bHandle.Free(); 149 } 150 }