Skip to content

Commit

Permalink
Added safe pointer class, arranged a bit the code.
Browse files Browse the repository at this point in the history
-- Ready for 1.3 pre-release.
  • Loading branch information
JLChnToZ committed Feb 1, 2014
1 parent 290c73c commit 1fc7811
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 65 deletions.
4 changes: 2 additions & 2 deletions IMEHelper/CharMessageFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public bool PreFilterMessage(ref Message m) {
Marshal.StructureToPtr(m, intPtr, true);
IMM.TranslateMessage(intPtr);
return false;
case 0x020A:
case IMM.MouseWheel:
// Mouse wheel is not correct if the IME helper is used, thus it is needed to grab the value here.
MouseWheel += (int)(short)((uint)(int)m.WParam >> 16);
MouseWheel += m.WParam.ToInt32() >> 16;
return false;
}
return false;
Expand Down
1 change: 1 addition & 0 deletions IMEHelper/IMEHelper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CharMessageFilter.cs" />
<Compile Include="SafePointer.cs" />
<Compile Include="TSF\CTfThreadMgr.cs" />
<Compile Include="IME.cs" />
<Compile Include="IMENativeWindow.cs" />
Expand Down
38 changes: 14 additions & 24 deletions IMEHelper/IMENativeWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,15 @@ private void onTSFUpdate(object sender, EventArgs e) {
/// </summary>
public void enableIME() {
IsEnabled = true;
IMM.ImmAssociateContext(Handle, _context);
IMM.AssociateContext(Handle, _context);
}

/// <summary>
/// Disable the IME
/// </summary>
public void disableIME() {
IsEnabled = false;
IMM.ImmAssociateContext(Handle, IntPtr.Zero);
IMM.AssociateContext(Handle, IntPtr.Zero);
}

/// <summary>
Expand Down Expand Up @@ -288,7 +288,7 @@ private void ClearResult() {
#region IME Message Handlers
private void IMESetContext(ref Message msg) {
if (msg.WParam.ToInt32() == 1) {
IntPtr ptr = IMM.ImmGetContext(Handle);
IntPtr ptr = IMM.GetContext(Handle);
if (_context == IntPtr.Zero)
_context = ptr;
else if (ptr == IntPtr.Zero && IsEnabled)
Expand Down Expand Up @@ -324,28 +324,18 @@ private void IMEChangeCandidate() {
hasTSFUpdate = false;
return;
}
uint length = IMM.ImmGetCandidateList(_context, 0, IntPtr.Zero, 0);
if (length > 0) {
IntPtr pointer = Marshal.AllocHGlobal((int)length);
length = IMM.ImmGetCandidateList(_context, 0, pointer, length);
IMM.CandidateList cList =
(IMM.CandidateList)Marshal.PtrToStructure(pointer, typeof(IMM.CandidateList));
CandidatesSelection = cList.dwSelection;
CandidatesPageStart = cList.dwPageStart;
CandidatesPageSize = cList.dwPageSize;
if (cList.dwCount > 1) {
Candidates = new string[cList.dwCount];
for (int i = 0; i < cList.dwCount; i++) {
int sOffset = Marshal.ReadInt32(pointer, 24 + 4 * i);
Candidates[i] = Marshal.PtrToStringUni((IntPtr)(pointer.ToInt32() + sOffset));
}
if (onCandidatesReceived != null)
onCandidatesReceived(this, EventArgs.Empty);
} else
IMECloseCandidate();
Marshal.FreeHGlobal(pointer);
} else
IMM.CandidateList cList = IMM.GetCandidateList(_context, 0);
CandidatesSelection = cList.Selection;
CandidatesPageStart = cList.PageStart;
CandidatesPageSize = cList.PageSize;
if (cList.Candidates == null) {
Candidates = new string[0];
IMECloseCandidate();
} else {
Candidates = cList.Candidates;
if (onCandidatesReceived != null)
onCandidatesReceived(this, EventArgs.Empty);
}
}

private void IMECloseCandidate() {
Expand Down
13 changes: 3 additions & 10 deletions IMEHelper/IMMCompositionResultHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,8 @@ internal void Clear() {
}

internal override void Update() {
Length = IMM.ImmGetCompositionString(IMEHandle, Flag, IntPtr.Zero, 0);
IntPtr pointer = Marshal.AllocHGlobal(Length);
try {
IMM.ImmGetCompositionString(IMEHandle, Flag, pointer, Length);
_values = new byte[Length];
Marshal.Copy(pointer, _values, 0, Length);
} finally {
Marshal.FreeHGlobal(pointer);
}
_values = IMM.GetCompositionString(IMEHandle, Flag);
Length = _values.Length;
}
}

Expand All @@ -98,7 +91,7 @@ public override string ToString() {
}

internal override void Update() {
Value = IMM.ImmGetCompositionString(IMEHandle, Flag, IntPtr.Zero, 0);
Value = IMM.GetCompositionInt(IMEHandle, Flag);
}
}
}
90 changes: 61 additions & 29 deletions IMEHelper/IMMNativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@
namespace JLChnToZ.IMEHelper {

internal static class IMM {

#region Constants
public const int
KeyDown = 0x0100,
Char = 0x0102;

public const int
Char = 0x0102,
MouseWheel = 0x020A,
GCSCompReadStr = 0x0001,
GCSCompReadAttr = 0x0002,
GCSCompReadClause = 0x0004,
Expand All @@ -40,9 +39,8 @@ public const int
GCSResultReadStr = 0x0200,
GCSResultReadClause = 0x0400,
GCSResultStr = 0x0800,
GCSResultClause = 0x1000;

public const int
GCSResultClause = 0x1000,

ImeStartCompostition = 0x010D,
ImeEndComposition = 0x010E,
ImeComposition = 0x010F,
Expand All @@ -55,9 +53,8 @@ public const int
ImeChar = 0x286,
ImeRequest = 0x0288,
ImeKeyDown = 0x0290,
ImeKeyUp = 0x0291;

public const int
ImeKeyUp = 0x0291,

ImnCloseStatusWindow = 0x0001,
ImnOpenStatusWindow = 0x0002,
ImnChangeCandidate = 0x0003,
Expand All @@ -71,36 +68,71 @@ public const int
ImnSetCompositionWindow = 0x000B,
ImnSetStatusWindowPos = 0x000C,
ImnGuideLine = 0x000D,
ImnPrivate = 0x000E;

public const int InputLanguageChange = 0x0051;
ImnPrivate = 0x000E,
InputLanguageChange = 0x0051;
#endregion

[DllImport("imm32.dll", SetLastError = true)]
public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("imm32.dll", SetLastError = true, EntryPoint = "ImmAssociateContext")]
public static extern IntPtr AssociateContext(IntPtr hWnd, IntPtr hIMC);

[DllImport("imm32.dll", CharSet = CharSet.Unicode)]
public static extern uint ImmGetCandidateList(IntPtr hIMC, uint deIndex, IntPtr candidateList, uint dwBufLen);
[DllImport("imm32.dll", CharSet = CharSet.Unicode, EntryPoint = "ImmGetCandidateList")]
private static extern uint _GetCandidateList(IntPtr hIMC, uint dwIndex, IntPtr candidateList, uint dwBufLen);

[DllImport("imm32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int ImmGetCompositionString(IntPtr hIMC, int CompositionStringFlag, IntPtr buffer, int bufferLength);
[DllImport("imm32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "ImmGetCompositionString")]
private static extern int _GetCompositionString(IntPtr hIMC, int CompositionStringFlag, IntPtr buffer, int bufferLength);

[DllImport("imm32.dll", SetLastError = true)]
public static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("imm32.dll", SetLastError = true, EntryPoint = "ImmGetContext")]
public static extern IntPtr GetContext(IntPtr hWnd);

[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern bool TranslateMessage(IntPtr message);

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct CandidateList {
public uint dwSize;
public uint dwStyle;
public uint dwCount;
public uint dwSelection;
public uint dwPageStart;
public uint dwPageSize;
private struct _candidateList {
public uint sz, style, cnt, sel, pgstart, pgsz;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.U4)]
public uint[] dwOffset;
public uint[] offset;
}

public struct CandidateList {
public uint Style, Selection, PageStart, PageSize;
public string[] Candidates;
}

public static CandidateList GetCandidateList(IntPtr hIMC, uint index) {
uint _length = _GetCandidateList(hIMC, index, IntPtr.Zero, 0);
CandidateList output = new CandidateList();
if (_length > 0)
using (SafePointer _ptr = new SafePointer((int)_length)) {
_length = _GetCandidateList(hIMC, index, _ptr.Pointer, _length);
_candidateList _list = _ptr.ToStructure<_candidateList>();
output.PageSize = _list.pgsz;
output.PageStart = _list.pgstart;
output.Selection = _list.sel;
output.Style = _list.style;
output.Candidates = new string[_list.cnt];
for (int i = 0; i < _list.cnt; i++) {
int sOffset = Marshal.ReadInt32(_ptr.Pointer, 24 + 4 * i);
output.Candidates[i] = Marshal.PtrToStringUni(_ptr.GetOffsetPointer(sOffset));
}
}
return output;
}

public static int GetCompositionInt(IntPtr hIMC, int CompositionStringFlag) {
return _GetCompositionString(hIMC, CompositionStringFlag, IntPtr.Zero, 0);
}

public static byte[] GetCompositionString(IntPtr hIMC, int CompositionStringFlag) {
int _length = GetCompositionInt(hIMC, CompositionStringFlag);
byte[] output = new byte[0];
if (_length > 0)
using (SafePointer _ptr = new SafePointer(_length)) {
_length = _GetCompositionString(hIMC, CompositionStringFlag, _ptr.Pointer, _length);
output = _ptr.GetBytes();
}
return output;
}
}
}
52 changes: 52 additions & 0 deletions IMEHelper/SafePointer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace JLChnToZ.IMEHelper {
public class SafePointer: IDisposable {
private IntPtr _pointer;
private int _length;
private bool disposed;

public IntPtr Pointer { get { return _pointer; } }

public int Length { get { return _length; } }

public SafePointer(int length) {
_length = length;
_pointer = Marshal.AllocHGlobal(_length);
disposed = false;
}

~SafePointer() {
Dispose();
}

public void Dispose() {
if (!disposed) {
Marshal.FreeHGlobal(_pointer);
disposed = true;
}
}

public T ToStructure<T>() {
return (T)Marshal.PtrToStructure(_pointer, typeof(T));
}

public override string ToString() {
return Marshal.PtrToStringAuto(_pointer);
}

public IntPtr GetOffsetPointer(int Offset) {
return (IntPtr)(_pointer.ToInt32() + Offset);
}

public byte[] GetBytes(int start = 0) {
byte[] b = new byte[_length - start];
Marshal.Copy(_pointer, b, start, _length - start);
return b;
}
}
}

0 comments on commit 1fc7811

Please sign in to comment.