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  }