1 // TSF のデバッグ表示を行うかどうか?
2 //#define TSF_DEBUG_OUTPUT
3 //#define TSF_DEBUG_OUTPUT_DISPLAY_ATTR
5 using System.Collections.Generic;
8 using System.Diagnostics;
9 using System.Reflection;
10 using System.Runtime.CompilerServices;
11 using System.Runtime.InteropServices;
12 using System.Globalization;
14 using DotNetTextStore.UnmanagedAPI.TSF;
15 using DotNetTextStore.UnmanagedAPI.TSF.TextStore;
16 using DotNetTextStore.UnmanagedAPI.WinDef;
17 using DotNetTextStore.UnmanagedAPI.WinError;
19 namespace DotNetTextStore
22 /// <summary>コールスタックの階層にあわせてインデントしてデバッグ表示するクラス。</summary>
23 public class DebugOut : IDisposable
25 public DebugOut(string i_string, params object[] i_params)
27 _text = string.Format(i_string, i_params);
31 Debug.WriteLine(string.Format("{0, 4} : ↓↓↓ ", s_callCount) + _text);
34 public static void Print(string i_string, params object[] i_params)
36 Debug.WriteLine(i_string, i_params);
42 Debug.WriteLine(string.Format("{0, 4} : ↑↑↑ ", s_callCount) + _text);
45 public static string GetCaller([CallerMemberName] string caller="")
51 static int s_callCount = 0;
55 //=============================================================================================
58 public struct TextDisplayAttribute
60 public int startIndex;
62 public TF_DISPLAYATTRIBUTE attribute;
65 //========================================================================================
68 /// <summary>Dispose() で TextStore のロック解除を行うクラス。</summary>
69 public class Unlocker : IDisposable
71 /// <summary>コンストラクタ</summary>
72 public Unlocker(TextStoreBase io_textStore)
74 _textStore = io_textStore;
76 /// <summary>ロックが成功したかどうか調べる。</summary>
79 get { return _textStore != null; }
81 /// <summary>アンロックを行う。</summary>
82 void IDisposable.Dispose()
84 if (_textStore != null)
86 _textStore.UnlockDocument();
91 /// <summary>アンロックを行うテキストストア</summary>
92 TextStoreBase _textStore;
95 public abstract class TextStoreBase
97 public delegate bool IsReadOnlyHandler();
98 public event IsReadOnlyHandler IsReadOnly;
100 public delegate bool IsLoadingHandler();
101 public event IsLoadingHandler IsLoading;
103 public delegate int GetStringLengthHandler();
104 public event GetStringLengthHandler GetStringLength;
106 public delegate void GetSelectionIndexHandler(out int o_start, out int o_end);
107 public event GetSelectionIndexHandler GetSelectionIndex;
109 public delegate void SetSelectionIndexHandler(int i_start, int i_end);
110 public event SetSelectionIndexHandler SetSelectionIndex;
112 public delegate string GetStringHandler(int start, int length);
113 public event GetStringHandler GetString;
115 public delegate void InsertAtSelectionHandler(string i_value,ref int o_startIndex,ref int o_endIndex);
116 public event InsertAtSelectionHandler InsertAtSelection;
118 public delegate void GetScreenExtentHandler(
119 out POINT o_pointTopLeft,
120 out POINT o_pointBottomRight
122 public event GetScreenExtentHandler GetScreenExtent;
124 public delegate void GetStringExtentHandler(
127 out POINT o_pointTopLeft,
128 out POINT o_pointBottomRight
130 public event GetStringExtentHandler GetStringExtent;
132 public delegate bool CompositionStartedHandler();
133 public event CompositionStartedHandler CompositionStarted;
135 public delegate void CompostionUpdateHandler(int start, int end);
136 public event CompostionUpdateHandler CompositionUpdated;
138 public delegate void CompositionEndedHandler();
139 public event CompositionEndedHandler CompositionEnded;
142 public TextStoreBase()
145 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
155 CreateDisplayAttributeMgr();
158 _threadMgr.CreateDocumentMgr(out _documentMgr);
162 _threadMgr.Activate(out clientId);
165 _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);
168 _documentMgr.Push(_context);
170 // ファンクションプロバイダーを取得する。
171 Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;
172 _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);
174 // ITfReconversion オブジェクトを取得する。
175 var guidNull = new Guid();
176 var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5"); //ITfFnReconversionの定義から
177 object reconversion = null;
178 _functionProvider.GetFunction(
180 ref guidReconversion,
183 _reconversion = reconversion as ITfFnReconversion;
187 Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;
188 _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);
189 _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;
190 _attributeInfo[0].flags = AttributeInfoFlags.None;
191 _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;
192 _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;
193 _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;
195 catch (Exception exception)
197 Debug.WriteLine(exception.Message);
204 /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります
206 /// <param name="flag"></param>
207 protected void Dispose(bool flag)
212 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
215 ReleaseComObject("_reconversion", ref _reconversion);
216 ReleaseComObject("_functionProvider", ref _functionProvider);
217 ReleaseComObject("_context", ref _context);
218 DestroyDocumentMgr();
219 DestroyDisplayAttributeMgr();
220 DestroyCategoryMgr();
223 GC.SuppressFinalize(this);
228 /// スレッドマネージャの生成。このメソッドの実装は必須です
231 /// <exception cref="COMException">
232 /// スレッドマネージャーの生成に失敗した場合。
234 protected virtual void CreateThreadMgr()
236 throw new NotImplementedException();
242 void DestroyThreadMgr()
244 if (_threadMgr != null)
246 try { _threadMgr.Deactivate(); }
247 catch (Exception) { }
249 ReleaseComObject("_threadMgr", ref _threadMgr);
257 /// <exception cref="COMException">
258 /// カテゴリマネージャーの生成に失敗した場合。
260 void CreateCategoryMgr()
262 if (_categoryMgr == null)
264 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);
265 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;
267 if (_categoryMgr == null)
269 const string message = "カテゴリマネージャーの生成に失敗しました。";
270 Debug.WriteLine(message);
271 throw new COMException(message, HRESULT.E_NOTIMPL);
279 void DestroyCategoryMgr()
281 ReleaseComObject("_categoryMgr", ref _categoryMgr);
288 /// <exception cref="COMException">
289 /// 表示属性マネージャーの生成に失敗した場合。
291 void CreateDisplayAttributeMgr()
293 if (_displayAttributeMgr == null)
295 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);
296 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;
298 if (_displayAttributeMgr == null)
300 const string message = "表示属性マネージャーの生成に失敗しました。";
301 Debug.WriteLine(message);
302 throw new COMException(message, HRESULT.E_NOTIMPL);
310 void DestroyDisplayAttributeMgr()
312 ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);
318 void DestroyDocumentMgr()
320 if (_documentMgr != null)
322 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }
323 catch (Exception) { }
325 ReleaseComObject("_documentMgr", ref _documentMgr);
330 /// COM オブジェクトのリリースとデバッグメッセージ出力。
332 protected static void ReleaseComObject<ComObject>(
334 ref ComObject io_comObject
337 if (io_comObject != null)
339 var refCount = Marshal.ReleaseComObject(io_comObject);
342 "Marshal.ReleaseComObject({0}) returns {1}.",
348 io_comObject = default(ComObject);
353 #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
355 /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
357 public void NotifySelectionChanged()
362 DebugOut.Print(DebugOut.GetCaller());
364 if ((_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0)
365 _sink.OnSelectionChange();
370 //=========================================================================================
374 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
376 void NotifyTextChanged(TS_TEXTCHANGE textChange)
381 DebugOut.Print(DebugOut.GetCaller());
383 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
384 _sink.OnTextChange(0, ref textChange);
385 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
390 //=========================================================================================
393 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
395 /// <param name="start">開始位置</param>
396 /// <param name="oldend">更新前の終了位置</param>
397 /// <param name="newend">更新後の終了位置</param>
399 /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください
401 public void NotifyTextChanged(int start,int oldend,int newend)
406 DebugOut.Print(DebugOut.GetCaller());
408 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
410 var textChange = new TS_TEXTCHANGE();
411 textChange.start = start;
412 textChange.oldEnd = oldend;
413 textChange.newEnd = newend;
415 _sink.OnTextChange(0, ref textChange);
417 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
422 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
424 /// <param name="i_oldLength"></param>
425 /// <param name="i_newLength"></param>
426 public void NotifyTextChanged(int i_oldLength, int i_newLength)
431 DebugOut.Print(DebugOut.GetCaller());
433 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
435 var textChange = new TS_TEXTCHANGE();
436 textChange.start = 0;
437 textChange.oldEnd = i_oldLength;
438 textChange.newEnd = i_newLength;
440 _sink.OnTextChange(0, ref textChange);
442 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
448 //=========================================================================================
451 /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>
452 public void SetFocus()
455 DebugOut.Print(DebugOut.GetCaller());
457 if (_threadMgr != null)
458 _threadMgr.SetFocus(_documentMgr);
460 #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
466 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
467 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
468 public Unlocker LockDocument(bool i_writable)
471 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
477 if( this._lockFlags == 0 )
480 this._lockFlags = LockFlags.TS_LF_READWRITE;
482 this._lockFlags = LockFlags.TS_LF_READ;
485 Debug.WriteLine("LockDocument is succeeded.");
488 return new Unlocker(this);
493 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
503 //========================================================================================
509 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
510 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
511 public Unlocker LockDocument(LockFlags i_flags)
514 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
520 if( this._lockFlags == 0 )
522 this._lockFlags = i_flags;
525 Debug.WriteLine("LockDocument is succeeded.");
528 return new Unlocker(this);
533 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
543 //========================================================================================
549 public void UnlockDocument()
552 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
560 if( _pendingLockUpgrade )
562 _pendingLockUpgrade = false;
564 RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);
570 //========================================================================================
574 /// 指定されたフラグでロックしている状態かどうか調べる。
576 /// <param name="i_lockFlags"></param>
577 /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>
578 public bool IsLocked(LockFlags i_lockFlags)
581 using(var dbgout = new DebugOut("{0}({1})",
582 DebugOut.GetCaller(), i_lockFlags) )
587 "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)
590 return (this._lockFlags & i_lockFlags) == i_lockFlags;
597 /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>
598 public bool IsLocked()
601 using(var dbgout = new DebugOut("{0}",
602 DebugOut.GetCaller()) )
605 bool retval = this._lockFlags != 0;
608 "IsLocked() returns " + retval
616 #region ITextStroeACP,ITextStoreACP2の共通部分
621 public void InsertTextAtSelection(string s)
623 TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();
625 using (var unlocker = LockDocument(true))
627 if (unlocker != null)
629 int startIndex, endIndex;
631 InsertTextAtSelection(
632 UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,
642 // シンクの OnSelectionChange() をコール。
643 NotifySelectionChanged();
644 NotifyTextChanged(textChange);
647 public void InsertEmbeddedAtSelection(
648 InsertAtSelectionFlags flags,
652 out TS_TEXTCHANGE change
656 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
659 throw new NotImplementedException();
663 public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)
666 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
669 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より
671 throw new COMException(
672 "ITextStoreACPSink 以外のIIDが渡されました。",
673 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
678 if (_sink == i_unknown)
680 _adviseFlags = i_mask;
683 else if (_sink != null)
685 throw new COMException(
687 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT
693 _services = (ITextStoreACPServices)i_unknown;
694 _sink = (ITextStoreACPSink)i_unknown;
695 _adviseFlags = i_mask;
700 public void UnadviseSink(object i_unknown)
703 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
706 if (_sink == null || _sink != i_unknown)
708 throw new COMException(
710 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
720 public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)
723 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
726 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;
730 throw new COMException(
732 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
736 if (_lockFlags != 0) // すでにロックされた状態の場合。
738 if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)
740 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
744 if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ
745 && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)
747 _pendingLockUpgrade = true;
748 o_sessionResult = TsResult.TS_S_ASYNC;
752 throw new COMException();
755 using (var unlocker = LockDocument(i_lockFlags))
757 // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。
758 if (unlocker == null)
760 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
762 // ロックに成功した場合は OnLockGranted() を呼び出す。
767 o_sessionResult = _sink.OnLockGranted(i_lockFlags);
769 catch (COMException comException)
771 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
772 Debug.WriteLine(" " + comException.Message);
773 o_sessionResult = comException.HResult;
775 catch (Exception exception)
777 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
778 Debug.WriteLine(" " + exception.Message);
785 public void GetStatus(out TS_STATUS o_documentStatus)
788 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
791 if (IsReadOnly != null && IsReadOnly())
792 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;
793 if (IsLoading != null && IsLoading())
794 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;
796 o_documentStatus.dynamicFlags = 0;
797 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;
801 public void QueryInsert(
805 out int o_startIndex,
810 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
813 if (GetStringLength == null)
814 throw new NotImplementedException();
816 int documentLength = GetStringLength();
819 || i_startIndex > i_endIndex
820 || i_endIndex > documentLength)
822 throw new COMException(
824 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
827 o_startIndex = i_startIndex;
828 o_endIndex = i_endIndex;
831 DebugOut.Print("o_startIndex:{0} o_endIndex:{1}", i_startIndex, i_endIndex);
836 public void GetSelection(
838 int i_selectionBufferLength,
839 TS_SELECTION_ACP[] o_selections,
840 out int o_fetchedLength
844 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
847 if (GetSelectionIndex == null)
848 throw new NotImplementedException();
852 if (IsLocked(LockFlags.TS_LF_READ) == false)
854 throw new COMException(
860 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、
861 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。
862 if (i_index != -1 && i_index > 0)
864 throw new COMException(
865 "選択は1つだけしかサポートしていません。",
866 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
870 if (i_selectionBufferLength > 0)
872 int start = 0, end = 0;
873 GetSelectionIndex(out start, out end);
876 o_selections[0].start = start;
877 o_selections[0].end = end;
878 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;
879 o_selections[0].style.interimChar = false;
883 o_selections[0].start = end;
884 o_selections[0].end = start;
885 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;
886 o_selections[0].style.interimChar = false;
892 DebugOut.Print("sel start:{0} end:{1}", start, end);
898 public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)
901 using(var dbgout = new DebugOut("{0}({1}, {2})",
902 DebugOut.GetCaller(),
903 i_selections[0].start,
904 i_selections[0].end))
907 if (SetSelectionIndex == null)
908 throw new NotImplementedException();
912 throw new COMException(
913 "選択は1つだけしかサポートしていません。",
914 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
918 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)
920 throw new COMException(
926 SetSelectionIndex(i_selections[0].start, i_selections[0].end);
929 DebugOut.Print("set selection startIndex:{0} endIndex:{1}", i_selections[0].start, i_selections[0].end);
938 int i_plainTextLength,
939 out int o_plainTextLength,
940 TS_RUNINFO[] o_runInfos,
942 out int o_runInfoLength,
943 out int o_nextUnreadCharPos
947 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
950 if (GetStringLength == null || GetString == null)
951 throw new NotImplementedException();
953 if (IsLocked(LockFlags.TS_LF_READ) == false)
955 throw new COMException(
961 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
962 || i_startIndex < 0 || i_startIndex > GetStringLength()
963 || i_endIndex > GetStringLength())
965 throw new COMException(
967 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
974 if (i_endIndex == -1)
975 textLength = GetStringLength() - i_startIndex;
977 textLength = i_endIndex - i_startIndex;
978 copyLength = Math.Min(i_plainTextLength, textLength);
981 var text = GetString(i_startIndex, copyLength);
983 DebugOut.Print("got text:{0} from {1} length {2}", text,i_startIndex,copyLength);
985 for (int i = 0; i < copyLength; i++)
987 o_plainText[i] = text[i];
991 o_plainTextLength = copyLength;
993 if (i_runInfoLength > 0)
995 o_runInfos[0].type = TsRunType.TS_RT_PLAIN;
996 o_runInfos[0].length = copyLength;
1001 o_nextUnreadCharPos = i_startIndex + copyLength;
1005 public void SetText(
1006 SetTextFlags i_flags,
1011 out TS_TEXTCHANGE o_textChange
1014 #if TSF_DEBUG_OUTPUT
1015 using(var dbgout = new DebugOut("{0}({1}, {2})",
1016 DebugOut.GetCaller(),
1017 i_startIndex, i_endIndex) )
1020 var selections = new TS_SELECTION_ACP[]
1022 new TS_SELECTION_ACP
1024 start = i_startIndex,
1026 style = new TS_SELECTIONSTYLE
1028 ase = TsActiveSelEnd.TS_AE_END,
1034 int startIndex = 0, endIndex = 0;
1035 SetSelection(1, selections);
1036 InsertTextAtSelection(
1037 InsertAtSelectionFlags.TF_IAS_NOQUERY,
1047 public void GetFormattedText(int i_start, int i_end, out object o_obj)
1049 #if TSF_DEBUG_OUTPUT
1050 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1053 throw new NotImplementedException();
1057 public void GetEmbedded(
1059 ref Guid i_guidService,
1064 #if TSF_DEBUG_OUTPUT
1065 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1068 throw new NotImplementedException();
1072 public void QueryInsertEmbedded(
1073 ref Guid i_guidService,
1075 out bool o_insertable
1078 #if TSF_DEBUG_OUTPUT
1079 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1082 throw new NotImplementedException();
1086 public void InsertEmbedded(
1087 InsertEmbeddedFlags i_flags,
1091 out TS_TEXTCHANGE o_textChange
1094 #if TSF_DEBUG_OUTPUT
1095 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1098 throw new NotImplementedException();
1102 public void InsertTextAtSelection(
1103 InsertAtSelectionFlags i_flags,
1106 out int o_startIndex,
1108 out TS_TEXTCHANGE o_textChange
1111 #if TSF_DEBUG_OUTPUT
1112 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1115 if (GetSelectionIndex == null || InsertAtSelection == null)
1116 throw new NotImplementedException();
1118 int selectionStart = 0, selectionEnd = 0;
1119 GetSelectionIndex(out selectionStart, out selectionEnd);
1121 // 問い合わせのみで実際には操作を行わない
1122 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)
1124 o_startIndex = Math.Min(selectionStart, selectionEnd);
1125 o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;
1127 o_textChange.start = o_startIndex;
1128 o_textChange.oldEnd = o_endIndex;
1129 o_textChange.newEnd = o_startIndex + i_length;
1133 var start = Math.Min(selectionStart, selectionEnd);
1134 var end = Math.Max(selectionStart, selectionEnd);
1136 #if TSF_DEBUG_OUTPUT
1137 DebugOut.Print("start: {0}, end: {1}, text: {2}", start, end, new string(i_text));
1140 o_startIndex = start;
1141 o_endIndex = start + i_length;
1143 InsertAtSelection(new string(i_text), ref o_startIndex, ref o_endIndex);
1145 o_textChange.start = start;
1146 o_textChange.oldEnd = end;
1147 o_textChange.newEnd = o_endIndex;
1148 // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。
1150 // SetSelectionIndex(start, start + i_length);
1155 public void GetEndACP(out int o_length)
1157 #if TSF_DEBUG_OUTPUT
1158 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1161 if (GetStringLength == null)
1162 throw new NotImplementedException();
1164 if (IsLocked(LockFlags.TS_LF_READ) == false)
1166 throw new COMException(
1168 TsResult.TS_E_NOLOCK
1172 o_length = GetStringLength();
1176 public void GetActiveView(out int o_viewCookie)
1178 #if TSF_DEBUG_OUTPUT
1179 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1186 public void GetACPFromPoint(
1189 GetPositionFromPointFlags i_flags,
1193 #if TSF_DEBUG_OUTPUT
1194 using (var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1197 throw new NotImplementedException();
1201 public void GetTextExt(
1206 out bool o_isClipped
1209 #if TSF_DEBUG_OUTPUT
1210 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1213 if (GetStringLength == null)
1214 throw new NotImplementedException();
1217 if (IsLocked(LockFlags.TS_LF_READ) == false)
1219 throw new COMException(
1221 TsResult.TS_E_NOLOCK
1225 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
1226 || i_startIndex < 0 || i_startIndex > GetStringLength()
1227 || i_endIndex > GetStringLength())
1229 throw new COMException(
1231 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
1235 if (i_endIndex == -1)
1236 i_endIndex = GetStringLength();
1238 var pointTopLeft = new POINT();
1239 var pointBotttomRight = new POINT();
1240 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);
1242 o_rect.left = (int)(pointTopLeft.x);
1243 o_rect.top = (int)(pointTopLeft.y);
1244 o_rect.bottom = (int)(pointBotttomRight.y);
1245 o_rect.right = (int)(pointBotttomRight.x);
1246 o_isClipped = false;
1247 #if TSF_DEBUG_OUTPUT
1248 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
1253 public void GetScreenExt(int i_viewCookie, out RECT o_rect)
1255 #if TSF_DEBUG_OUTPUT
1256 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1259 if (GetScreenExtent == null)
1260 throw new NotImplementedException();
1262 POINT pointTopLeft, pointBottomRight;
1264 GetScreenExtent(out pointTopLeft, out pointBottomRight);
1266 o_rect.left = (int)(pointTopLeft.x);
1267 o_rect.top = (int)(pointTopLeft.y);
1268 o_rect.bottom = (int)(pointBottomRight.y);
1269 o_rect.right = (int)(pointBottomRight.x);
1270 #if TSF_DEBUG_OUTPUT
1271 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
1276 public void RequestSupportedAttrs(
1277 AttributeFlags i_flags,
1279 Guid[] i_filterAttributes
1282 #if TSF_DEBUG_OUTPUT
1283 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1286 for (int i = 0; i < i_length; i++)
1288 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
1290 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
1291 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
1293 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
1297 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
1304 public void RequestAttrsAtPosition(
1307 Guid[] i_filterAttributes,
1308 AttributeFlags i_flags
1311 #if TSF_DEBUG_OUTPUT
1312 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1315 for (int i = 0; i < i_length; i++)
1317 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
1319 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
1320 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
1322 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
1326 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
1333 public void RequestAttrsTransitioningAtPosition(
1336 Guid[] i_filterAttributes,
1337 AttributeFlags i_flags
1340 #if TSF_DEBUG_OUTPUT
1341 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1348 public void FindNextAttrTransition(
1352 Guid[] i_filterAttributes,
1353 AttributeFlags i_flags,
1354 out int o_nextIndex,
1356 out int o_foundOffset
1359 #if TSF_DEBUG_OUTPUT
1360 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1363 throw new NotImplementedException();
1367 public void RetrieveRequestedAttrs(
1369 TS_ATTRVAL[] o_attributeVals,
1370 out int o_fetchedLength
1373 #if TSF_DEBUG_OUTPUT
1374 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1377 o_fetchedLength = 0;
1378 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)
1380 if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)
1382 o_attributeVals[o_fetchedLength].overlappedId = 0;
1383 o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;
1384 o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;
1386 if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)
1387 _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;
1390 _attributeInfo[i].flags = AttributeInfoFlags.None;
1397 #region "ITfContextOwnerCompositionSink インターフェイスの実装"
1398 /// <summary>コンポジション入力が開始された時の処理。</summary>
1399 public void OnStartComposition(ITfCompositionView view, out bool ok)
1401 #if TSF_DEBUG_OUTPUT
1402 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1405 if( CompositionStarted != null )
1406 ok = CompositionStarted();
1413 //========================================================================================
1416 /// <summary>コンポジションが変更された時の処理。</summary>
1417 public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)
1419 #if TSF_DEBUG_OUTPUT
1420 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1423 if (rangeNew == null)
1428 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;
1430 rangeAcp.GetExtent(out start, out count);
1432 if (this.CompositionUpdated != null)
1433 this.CompositionUpdated(start, start + count);
1438 //========================================================================================
1441 /// <summary>コンポジション入力が終了した時の処理。</summary>
1442 public void OnEndComposition(ITfCompositionView view)
1444 #if TSF_DEBUG_OUTPUT
1445 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1448 if( CompositionEnded != null )
1452 #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"
1455 /// <summary>表示属性の取得</summary>
1456 public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)
1458 ITfRangeACP allRange;
1459 _services.CreateRange(start, end, out allRange);
1461 foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))
1464 ReleaseComObject("allRange", ref allRange);
1467 IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)
1469 #if TSF_DEBUG_OUTPUT
1470 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1473 ITfProperty property = null; // プロパティインターフェイス
1474 IEnumTfRanges enumRanges; // 範囲の列挙子
1475 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;
1477 if (_context == null || _services == null)
1480 // GUID_PROP_ATTRIBUTE プロパティを取得。
1481 _context.GetProperty(ref guidPropAttribute, out property);
1482 if (property == null)
1485 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。
1486 property.EnumRanges((int)_editCookie, out enumRanges, range);
1488 ITfRange[] ranges = new ITfRange[1];
1489 int fetchedLength = 0;
1490 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))
1491 && fetchedLength > 0)
1493 // ItfRange から ItfRangeACP を取得。
1494 ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;
1495 if (rangeACP == null)
1496 continue; // 普通はあり得ない
1500 rangeACP.GetExtent(out start, out count);
1502 // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。
1503 VARIANT value = new VARIANT();
1504 property.GetValue((int)_editCookie, ranges[0], ref value);
1505 if (value.vt == (short)VarEnum.VT_I4)
1508 ITfDisplayAttributeInfo info;
1509 TF_DISPLAYATTRIBUTE attribute;
1511 // GUID ATOM から GUID を取得する。
1512 _categoryMgr.GetGUID((int)value.data1, out guid);
1513 // その GUID から IDisplayAttributeInfo インターフェイスを取得。
1514 _displayAttributeMgr.GetDisplayAttributeInfo(
1519 // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。
1520 info.GetAttributeInfo(out attribute);
1521 ReleaseComObject("info", ref info);
1523 yield return new TextDisplayAttribute
1526 endIndex = start + count,
1527 attribute = attribute
1530 #if TSF_DEBUG_OUTPUT_DISPLAY_ATTR
1532 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",
1533 start, start + count
1535 Debug.WriteLine(attribute.bAttr);
1537 "LineColorType: {0}, {1}",
1538 attribute.crLine.type, attribute.crLine.indexOrColorRef
1541 "TextColorType: {0}, {1}",
1542 attribute.crText.type, attribute.crText.indexOrColorRef
1545 "BackColorType: {0}, {1}",
1546 attribute.crBk.type, attribute.crBk.indexOrColorRef
1549 "Bold, Style : {0}, {1}",
1550 attribute.fBoldLine, attribute.lsStyle
1555 ReleaseComObject("rangeACP", ref rangeACP);
1558 ReleaseComObject("ranges[0]", ref ranges[0]);
1559 ReleaseComObject("enumRanges", ref enumRanges);
1560 ReleaseComObject("property", ref property);
1566 protected ITfThreadMgr2 _threadMgr;
1568 protected ITfThreadMgr _threadMgr;
1570 protected ITfDocumentMgr _documentMgr;
1571 protected ITfFunctionProvider _functionProvider;
1572 protected ITfFnReconversion _reconversion;
1573 protected ITfContext _context;
1574 protected ITfCategoryMgr _categoryMgr;
1575 protected ITfDisplayAttributeMgr _displayAttributeMgr;
1576 protected ITextStoreACPSink _sink;
1577 protected uint _editCookie = 0;
1578 protected ITextStoreACPServices _services;
1579 protected AdviseFlags _adviseFlags = 0;
1580 protected LockFlags _lockFlags = 0;
1581 protected bool _pendingLockUpgrade = false;
1584 /// AttributeInfo で使用されるフラグ。各属性の状態を示す。
1586 protected enum AttributeInfoFlags
1588 /// <summary>何もない。</summary>
1590 /// <summary>デフォルト値の要求。</summary>
1592 /// <summary>要求された。</summary>
1596 protected struct AttributeInfo
1599 public AttributeInfoFlags flags;
1600 public VARIANT currentValue;
1601 public VARIANT defaultValue;
1604 protected AttributeInfo[] _attributeInfo = new AttributeInfo[1];