A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Runtime.InteropServices;
5using UnityEngine.InputSystem.Utilities;
6
7namespace UnityEngine.InputSystem.LowLevel
8{
9 /// <summary>
10 /// A specialized event that contains the current IME Composition string, if IME is enabled and active.
11 /// This event contains the entire current string to date, and once a new composition is submitted will send a blank string event.
12 /// </summary>
13 [StructLayout(LayoutKind.Explicit, Size = InputEvent.kBaseEventSize + sizeof(int) + (sizeof(char) * kIMECharBufferSize))]
14 public struct IMECompositionEvent : IInputEventTypeInfo
15 {
16 // These needs to match the native ImeCompositionStringInputEventData settings
17 internal const int kIMECharBufferSize = 64;
18 public const int Type = 0x494D4553;
19
20 [FieldOffset(0)]
21 public InputEvent baseEvent;
22
23 [FieldOffset(InputEvent.kBaseEventSize)]
24 public IMECompositionString compositionString;
25
26 public FourCC typeStatic => Type;
27
28 public static IMECompositionEvent Create(int deviceId, string compositionString, double time)
29 {
30 var inputEvent = new IMECompositionEvent();
31 inputEvent.baseEvent = new InputEvent(Type, InputEvent.kBaseEventSize + sizeof(int) + (sizeof(char) * kIMECharBufferSize), deviceId, time);
32 inputEvent.compositionString = new IMECompositionString(compositionString);
33 return inputEvent;
34 }
35 }
36
37 /// <summary>
38 /// A struct representing an string of characters generated by an IME for text input.
39 /// </summary>
40 /// <remarks>
41 /// This is the internal representation of character strings in the event stream. It is exposed to user content through the
42 /// <see cref="ITextInputReceiver.OnIMECompositionChanged"/> method. It can easily be converted to a normal C# string using
43 /// <see cref="ToString"/>, but is exposed as the raw struct to avoid allocating memory by default.
44 /// </remarks>
45 [StructLayout(LayoutKind.Explicit, Size = sizeof(int) + sizeof(char) * LowLevel.IMECompositionEvent.kIMECharBufferSize)]
46 public unsafe struct IMECompositionString : IEnumerable<char>
47 {
48 internal struct Enumerator : IEnumerator<char>
49 {
50 IMECompositionString m_CompositionString;
51 char m_CurrentCharacter;
52 int m_CurrentIndex;
53
54 public Enumerator(IMECompositionString compositionString)
55 {
56 m_CompositionString = compositionString;
57 m_CurrentCharacter = '\0';
58 m_CurrentIndex = -1;
59 }
60
61 public bool MoveNext()
62 {
63 int size = m_CompositionString.Count;
64
65 m_CurrentIndex++;
66
67 if (m_CurrentIndex == size)
68 return false;
69
70 fixed(char* ptr = m_CompositionString.buffer)
71 {
72 m_CurrentCharacter = *(ptr + m_CurrentIndex);
73 }
74
75 return true;
76 }
77
78 public void Reset()
79 {
80 m_CurrentIndex = -1;
81 }
82
83 public void Dispose()
84 {
85 }
86
87 public char Current => m_CurrentCharacter;
88
89 object IEnumerator.Current => Current;
90 }
91
92 public int Count => size;
93
94 public char this[int index]
95 {
96 get
97 {
98 if (index >= Count || index < 0)
99 throw new ArgumentOutOfRangeException(nameof(index));
100
101 fixed(char* ptr = buffer)
102 {
103 return *(ptr + index);
104 }
105 }
106 }
107
108 [FieldOffset(0)]
109 int size;
110
111 [FieldOffset(sizeof(int))]
112 fixed char buffer[IMECompositionEvent.kIMECharBufferSize];
113
114 public IMECompositionString(string characters)
115 {
116 if (string.IsNullOrEmpty(characters))
117 {
118 size = 0;
119 return;
120 }
121
122 Debug.Assert(characters.Length < IMECompositionEvent.kIMECharBufferSize);
123 size = characters.Length;
124 for (var i = 0; i < size; i++)
125 buffer[i] = characters[i];
126 }
127
128 public override string ToString()
129 {
130 fixed(char* ptr = buffer)
131 {
132 return new string(ptr, 0, size);
133 }
134 }
135
136 public IEnumerator<char> GetEnumerator()
137 {
138 return new Enumerator(this);
139 }
140
141 IEnumerator IEnumerable.GetEnumerator()
142 {
143 return GetEnumerator();
144 }
145 }
146}