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 //========================================================================================
67 public struct TextSelection
71 public TextSelection(int start = 0,int end = 0)
79 /// <summary>Dispose() で TextStore のロック解除を行うクラス。</summary>
80 public class Unlocker : IDisposable
82 /// <summary>コンストラクタ</summary>
83 public Unlocker(TextStoreBase io_textStore)
85 _textStore = io_textStore;
87 /// <summary>ロックが成功したかどうか調べる。</summary>
90 get { return _textStore != null; }
92 /// <summary>アンロックを行う。</summary>
93 void IDisposable.Dispose()
95 if (_textStore != null)
97 _textStore.UnlockDocument();
102 /// <summary>アンロックを行うテキストストア</summary>
103 TextStoreBase _textStore;
106 public abstract class TextStoreBase
108 public delegate bool IsReadOnlyHandler();
109 public event IsReadOnlyHandler IsReadOnly;
111 public delegate bool IsLoadingHandler();
112 public event IsLoadingHandler IsLoading;
114 public event Func<int> GetSelectionCount;
116 public delegate int GetStringLengthHandler();
117 public event GetStringLengthHandler GetStringLength;
119 public delegate void GetSelectionIndexHandler(int start_index, int max_count, out TextSelection[] sel);
120 public event GetSelectionIndexHandler GetSelectionIndex;
122 public delegate void SetSelectionIndexHandler(TextSelection[] sel);
123 public event SetSelectionIndexHandler SetSelectionIndex;
125 public delegate string GetStringHandler(int start, int length);
126 public event GetStringHandler GetString;
128 public delegate void InsertAtSelectionHandler(string i_value,ref int o_startIndex,ref int o_endIndex);
129 public event InsertAtSelectionHandler InsertAtSelection;
131 public delegate void GetScreenExtentHandler(
132 out POINT o_pointTopLeft,
133 out POINT o_pointBottomRight
135 public event GetScreenExtentHandler GetScreenExtent;
137 public delegate void GetStringExtentHandler(
140 out POINT o_pointTopLeft,
141 out POINT o_pointBottomRight
143 public event GetStringExtentHandler GetStringExtent;
145 public delegate bool CompositionStartedHandler();
146 public event CompositionStartedHandler CompositionStarted;
148 public delegate void CompostionUpdateHandler(int start, int end);
149 public event CompostionUpdateHandler CompositionUpdated;
151 public delegate void CompositionEndedHandler();
152 public event CompositionEndedHandler CompositionEnded;
154 bool _allow_multi_sel = false;
157 public TextStoreBase(bool allow_multi_sel = false)
160 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
163 this._allow_multi_sel = allow_multi_sel;
171 CreateDisplayAttributeMgr();
174 _threadMgr.CreateDocumentMgr(out _documentMgr);
178 _threadMgr.Activate(out clientId);
181 _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);
184 _documentMgr.Push(_context);
186 // ファンクションプロバイダーを取得する。
187 Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;
188 _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);
190 // ITfReconversion オブジェクトを取得する。
191 var guidNull = new Guid();
192 var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5"); //ITfFnReconversionの定義から
193 object reconversion = null;
194 _functionProvider.GetFunction(
196 ref guidReconversion,
199 _reconversion = reconversion as ITfFnReconversion;
203 Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;
204 _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);
205 _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;
206 _attributeInfo[0].flags = AttributeInfoFlags.None;
207 _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;
208 _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;
209 _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;
211 catch (Exception exception)
213 Debug.WriteLine(exception.Message);
220 /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります
222 /// <param name="flag"></param>
223 protected void Dispose(bool flag)
228 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
231 ReleaseComObject("_reconversion", ref _reconversion);
232 ReleaseComObject("_functionProvider", ref _functionProvider);
233 ReleaseComObject("_context", ref _context);
234 DestroyDocumentMgr();
235 DestroyDisplayAttributeMgr();
236 DestroyCategoryMgr();
239 GC.SuppressFinalize(this);
244 /// スレッドマネージャの生成。このメソッドの実装は必須です
247 /// <exception cref="COMException">
248 /// スレッドマネージャーの生成に失敗した場合。
250 protected virtual void CreateThreadMgr()
252 throw new NotImplementedException();
258 void DestroyThreadMgr()
260 if (_threadMgr != null)
262 try { _threadMgr.Deactivate(); }
263 catch (Exception) { }
265 ReleaseComObject("_threadMgr", ref _threadMgr);
273 /// <exception cref="COMException">
274 /// カテゴリマネージャーの生成に失敗した場合。
276 void CreateCategoryMgr()
278 if (_categoryMgr == null)
280 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);
281 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;
283 if (_categoryMgr == null)
285 const string message = "カテゴリマネージャーの生成に失敗しました。";
286 Debug.WriteLine(message);
287 throw new COMException(message, HRESULT.E_NOTIMPL);
295 void DestroyCategoryMgr()
297 ReleaseComObject("_categoryMgr", ref _categoryMgr);
304 /// <exception cref="COMException">
305 /// 表示属性マネージャーの生成に失敗した場合。
307 void CreateDisplayAttributeMgr()
309 if (_displayAttributeMgr == null)
311 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);
312 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;
314 if (_displayAttributeMgr == null)
316 const string message = "表示属性マネージャーの生成に失敗しました。";
317 Debug.WriteLine(message);
318 throw new COMException(message, HRESULT.E_NOTIMPL);
326 void DestroyDisplayAttributeMgr()
328 ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);
334 void DestroyDocumentMgr()
336 if (_documentMgr != null)
338 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }
339 catch (Exception) { }
341 ReleaseComObject("_documentMgr", ref _documentMgr);
346 /// COM オブジェクトのリリースとデバッグメッセージ出力。
348 protected static void ReleaseComObject<ComObject>(
350 ref ComObject io_comObject
353 if (io_comObject != null)
355 var refCount = Marshal.ReleaseComObject(io_comObject);
358 "Marshal.ReleaseComObject({0}) returns {1}.",
364 io_comObject = default(ComObject);
369 #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
371 /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
373 public void NotifySelectionChanged()
378 DebugOut.Print(DebugOut.GetCaller());
380 if ((_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0)
381 _sink.OnSelectionChange();
386 //=========================================================================================
390 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
392 void NotifyTextChanged(TS_TEXTCHANGE textChange)
397 DebugOut.Print(DebugOut.GetCaller());
399 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
400 _sink.OnTextChange(0, ref textChange);
401 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
406 //=========================================================================================
409 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
411 /// <param name="start">開始位置</param>
412 /// <param name="oldend">更新前の終了位置</param>
413 /// <param name="newend">更新後の終了位置</param>
415 /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください
417 public void NotifyTextChanged(int start,int oldend,int newend)
422 DebugOut.Print(DebugOut.GetCaller());
424 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
426 var textChange = new TS_TEXTCHANGE();
427 textChange.start = start;
428 textChange.oldEnd = oldend;
429 textChange.newEnd = newend;
431 _sink.OnTextChange(0, ref textChange);
433 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
438 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
440 /// <param name="i_oldLength"></param>
441 /// <param name="i_newLength"></param>
442 public void NotifyTextChanged(int i_oldLength, int i_newLength)
447 DebugOut.Print(DebugOut.GetCaller());
449 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
451 var textChange = new TS_TEXTCHANGE();
452 textChange.start = 0;
453 textChange.oldEnd = i_oldLength;
454 textChange.newEnd = i_newLength;
456 _sink.OnTextChange(0, ref textChange);
458 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
464 //=========================================================================================
467 /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>
468 public void SetFocus()
471 DebugOut.Print(DebugOut.GetCaller());
473 if (_threadMgr != null)
474 _threadMgr.SetFocus(_documentMgr);
476 #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
482 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
483 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
484 public Unlocker LockDocument(bool i_writable)
487 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
493 if( this._lockFlags == 0 )
496 this._lockFlags = LockFlags.TS_LF_READWRITE;
498 this._lockFlags = LockFlags.TS_LF_READ;
501 Debug.WriteLine("LockDocument is succeeded.");
504 return new Unlocker(this);
509 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
519 //========================================================================================
525 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
526 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
527 public Unlocker LockDocument(LockFlags i_flags)
530 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
536 if( this._lockFlags == 0 )
538 this._lockFlags = i_flags;
541 Debug.WriteLine("LockDocument is succeeded.");
544 return new Unlocker(this);
549 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
559 //========================================================================================
565 public void UnlockDocument()
568 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
576 if( _pendingLockUpgrade )
578 _pendingLockUpgrade = false;
580 RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);
586 //========================================================================================
590 /// 指定されたフラグでロックしている状態かどうか調べる。
592 /// <param name="i_lockFlags"></param>
593 /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>
594 public bool IsLocked(LockFlags i_lockFlags)
597 using(var dbgout = new DebugOut("{0}({1})",
598 DebugOut.GetCaller(), i_lockFlags) )
603 "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)
606 return (this._lockFlags & i_lockFlags) == i_lockFlags;
613 /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>
614 public bool IsLocked()
617 using(var dbgout = new DebugOut("{0}",
618 DebugOut.GetCaller()) )
621 bool retval = this._lockFlags != 0;
624 "IsLocked() returns " + retval
632 #region ITextStroeACP,ITextStoreACP2の共通部分
637 public void InsertTextAtSelection(string s)
639 TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();
641 using (var unlocker = LockDocument(true))
643 if (unlocker != null)
645 int startIndex, endIndex;
647 InsertTextAtSelection(
648 UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,
658 // シンクの OnSelectionChange() をコール。
659 NotifySelectionChanged();
660 NotifyTextChanged(textChange);
663 public void InsertEmbeddedAtSelection(
664 InsertAtSelectionFlags flags,
668 out TS_TEXTCHANGE change
672 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
675 throw new NotImplementedException();
679 public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)
682 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
685 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より
687 throw new COMException(
688 "ITextStoreACPSink 以外のIIDが渡されました。",
689 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
694 if (_sink == i_unknown)
696 _adviseFlags = i_mask;
699 else if (_sink != null)
701 throw new COMException(
703 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT
709 _services = (ITextStoreACPServices)i_unknown;
710 _sink = (ITextStoreACPSink)i_unknown;
711 _adviseFlags = i_mask;
716 public void UnadviseSink(object i_unknown)
719 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
722 if (_sink == null || _sink != i_unknown)
724 throw new COMException(
726 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
736 public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)
739 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
742 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;
746 throw new COMException(
748 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
752 if (_lockFlags != 0) // すでにロックされた状態の場合。
754 if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)
756 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
760 if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ
761 && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)
763 _pendingLockUpgrade = true;
764 o_sessionResult = TsResult.TS_S_ASYNC;
768 throw new COMException();
771 using (var unlocker = LockDocument(i_lockFlags))
773 // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。
774 if (unlocker == null)
776 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
778 // ロックに成功した場合は OnLockGranted() を呼び出す。
783 o_sessionResult = _sink.OnLockGranted(i_lockFlags);
785 catch (COMException comException)
787 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
788 Debug.WriteLine(" " + comException.Message);
789 o_sessionResult = comException.HResult;
791 catch (Exception exception)
793 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
794 Debug.WriteLine(" " + exception.Message);
801 public void GetStatus(out TS_STATUS o_documentStatus)
804 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
807 if (IsReadOnly != null && IsReadOnly())
808 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;
809 if (IsLoading != null && IsLoading())
810 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;
812 o_documentStatus.dynamicFlags = 0;
813 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;
814 if (this._allow_multi_sel)
815 o_documentStatus.staticFlags |= StaticStatusFlags.TS_SS_DISJOINTSEL;
819 public void QueryInsert(
823 out int o_startIndex,
828 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
831 if (GetStringLength == null)
832 throw new NotImplementedException();
834 int documentLength = GetStringLength();
837 || i_startIndex > i_endIndex
838 || i_endIndex > documentLength)
840 throw new COMException(
842 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
845 o_startIndex = i_startIndex;
846 o_endIndex = i_endIndex;
849 DebugOut.Print("o_startIndex:{0} o_endIndex:{1}", i_startIndex, i_endIndex);
854 public void GetSelection(
856 int i_selectionBufferLength,
857 TS_SELECTION_ACP[] o_selections,
858 out int o_fetchedLength
862 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
865 if (GetSelectionIndex == null)
866 throw new NotImplementedException();
870 if (IsLocked(LockFlags.TS_LF_READ) == false)
872 throw new COMException(
878 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、
879 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。
880 if (i_index != -1 && i_index > 0 && !this._allow_multi_sel)
882 throw new COMException(
883 "選択は1つだけしかサポートしていません。",
884 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
888 if (i_selectionBufferLength > 0)
890 TextSelection[] sels;
891 GetSelectionIndex(i_index,i_selectionBufferLength,out sels);
893 throw new InvalidOperationException("selsはnull以外の値を返す必要があります");
894 for(int i = 0; i < sels.Length; i++)
896 int start = sels[i].start, end = sels[i].end;
900 o_selections[0].start = start;
901 o_selections[0].end = end;
902 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;
903 o_selections[0].style.interimChar = false;
907 o_selections[0].start = end;
908 o_selections[0].end = start;
909 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;
910 o_selections[0].style.interimChar = false;
914 o_fetchedLength = sels.Length;
917 DebugOut.Print("sel start:{0} end:{1}", start, end);
923 public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)
926 using(var dbgout = new DebugOut("{0}({1}, {2})",
927 DebugOut.GetCaller(),
928 i_selections[0].start,
929 i_selections[0].end))
932 if (SetSelectionIndex == null)
933 throw new NotImplementedException();
935 if (i_count != 1 && !this._allow_multi_sel)
937 throw new COMException(
938 "選択は1つだけしかサポートしていません。",
939 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
943 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)
945 throw new COMException(
951 TextSelection[] sels = new TextSelection[i_count];
952 for(int i = 0; i < i_count; i++)
954 sels[i] = new TextSelection(i_selections[i].start, i_selections[i].end);
957 SetSelectionIndex(sels);
960 DebugOut.Print("set selection startIndex:{0} endIndex:{1}", i_selections[0].start, i_selections[0].end);
969 int i_plainTextLength,
970 out int o_plainTextLength,
971 TS_RUNINFO[] o_runInfos,
973 out int o_runInfoLength,
974 out int o_nextUnreadCharPos
978 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
981 if (GetStringLength == null || GetString == null)
982 throw new NotImplementedException();
984 if (IsLocked(LockFlags.TS_LF_READ) == false)
986 throw new COMException(
992 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
993 || i_startIndex < 0 || i_startIndex > GetStringLength()
994 || i_endIndex > GetStringLength())
996 throw new COMException(
998 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
1005 if (i_endIndex == -1)
1006 textLength = GetStringLength() - i_startIndex;
1008 textLength = i_endIndex - i_startIndex;
1009 copyLength = Math.Min(i_plainTextLength, textLength);
1012 var text = GetString(i_startIndex, copyLength);
1013 #if TSF_DEBUG_OUTPUT
1014 DebugOut.Print("got text:{0} from {1} length {2}", text,i_startIndex,copyLength);
1016 for (int i = 0; i < copyLength; i++)
1018 o_plainText[i] = text[i];
1022 o_plainTextLength = copyLength;
1024 if (i_runInfoLength > 0)
1026 o_runInfos[0].type = TsRunType.TS_RT_PLAIN;
1027 o_runInfos[0].length = copyLength;
1029 o_runInfoLength = 1;
1032 o_nextUnreadCharPos = i_startIndex + copyLength;
1036 public void SetText(
1037 SetTextFlags i_flags,
1042 out TS_TEXTCHANGE o_textChange
1045 #if TSF_DEBUG_OUTPUT
1046 using(var dbgout = new DebugOut("{0}({1}, {2})",
1047 DebugOut.GetCaller(),
1048 i_startIndex, i_endIndex) )
1051 var selections = new TS_SELECTION_ACP[]
1053 new TS_SELECTION_ACP
1055 start = i_startIndex,
1057 style = new TS_SELECTIONSTYLE
1059 ase = TsActiveSelEnd.TS_AE_END,
1065 int startIndex = 0, endIndex = 0;
1066 SetSelection(1, selections);
1067 InsertTextAtSelection(
1068 InsertAtSelectionFlags.TF_IAS_NOQUERY,
1078 public void GetFormattedText(int i_start, int i_end, out object o_obj)
1080 #if TSF_DEBUG_OUTPUT
1081 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1084 throw new NotImplementedException();
1088 public void GetEmbedded(
1090 ref Guid i_guidService,
1095 #if TSF_DEBUG_OUTPUT
1096 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1099 throw new NotImplementedException();
1103 public void QueryInsertEmbedded(
1104 ref Guid i_guidService,
1106 out bool o_insertable
1109 #if TSF_DEBUG_OUTPUT
1110 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1113 throw new NotImplementedException();
1117 public void InsertEmbedded(
1118 InsertEmbeddedFlags i_flags,
1122 out TS_TEXTCHANGE o_textChange
1125 #if TSF_DEBUG_OUTPUT
1126 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1129 throw new NotImplementedException();
1133 public void InsertTextAtSelection(
1134 InsertAtSelectionFlags i_flags,
1137 out int o_startIndex,
1139 out TS_TEXTCHANGE o_textChange
1142 #if TSF_DEBUG_OUTPUT
1143 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1146 if (GetSelectionIndex == null || InsertAtSelection == null)
1147 throw new NotImplementedException();
1150 if(this.GetSelectionCount != null)
1151 sel_count = this.GetSelectionCount();
1154 throw new InvalidOperationException("sel_countは1以上の値でなければなりません");
1156 //エラーになるので適当な値で埋めておく
1159 o_textChange.start = 0;
1160 o_textChange.oldEnd = 0;
1161 o_textChange.newEnd = 0;
1163 TextSelection[] sels;
1164 GetSelectionIndex(0, sel_count, out sels);
1166 for(int i = 0; i < sel_count; i++)
1168 // 問い合わせのみで実際には操作を行わない
1169 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)
1171 o_startIndex = Math.Min(sels[i].start, sels[i].end);
1172 o_endIndex = Math.Max(sels[i].start, sels[i].end);//o_startIndex + i_length;
1174 o_textChange.start = o_startIndex;
1175 o_textChange.oldEnd = o_endIndex;
1176 o_textChange.newEnd = o_startIndex + i_length;
1180 var start = Math.Min(sels[i].start, sels[i].end);
1181 var end = Math.Max(sels[i].start, sels[i].end);
1183 #if TSF_DEBUG_OUTPUT
1184 DebugOut.Print("start: {0}, end: {1}, text: {2}", start, end, new string(i_text));
1187 o_startIndex = start;
1188 o_endIndex = start + i_length;
1190 InsertAtSelection(new string(i_text), ref o_startIndex, ref o_endIndex);
1192 o_textChange.start = start;
1193 o_textChange.oldEnd = end;
1194 o_textChange.newEnd = o_endIndex;
1195 // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。
1197 // SetSelectionIndex(start, start + i_length);
1203 public void GetEndACP(out int o_length)
1205 #if TSF_DEBUG_OUTPUT
1206 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1209 if (GetStringLength == null)
1210 throw new NotImplementedException();
1212 if (IsLocked(LockFlags.TS_LF_READ) == false)
1214 throw new COMException(
1216 TsResult.TS_E_NOLOCK
1220 o_length = GetStringLength();
1224 public void GetActiveView(out int o_viewCookie)
1226 #if TSF_DEBUG_OUTPUT
1227 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1234 public void GetACPFromPoint(
1237 GetPositionFromPointFlags i_flags,
1241 #if TSF_DEBUG_OUTPUT
1242 using (var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1245 throw new NotImplementedException();
1249 public void GetTextExt(
1254 out bool o_isClipped
1257 #if TSF_DEBUG_OUTPUT
1258 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1261 if (GetStringLength == null)
1262 throw new NotImplementedException();
1265 if (IsLocked(LockFlags.TS_LF_READ) == false)
1267 throw new COMException(
1269 TsResult.TS_E_NOLOCK
1273 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
1274 || i_startIndex < 0 || i_startIndex > GetStringLength()
1275 || i_endIndex > GetStringLength())
1277 throw new COMException(
1279 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
1283 if (i_endIndex == -1)
1284 i_endIndex = GetStringLength();
1286 var pointTopLeft = new POINT();
1287 var pointBotttomRight = new POINT();
1288 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);
1290 o_rect.left = (int)(pointTopLeft.x);
1291 o_rect.top = (int)(pointTopLeft.y);
1292 o_rect.bottom = (int)(pointBotttomRight.y);
1293 o_rect.right = (int)(pointBotttomRight.x);
1294 o_isClipped = false;
1295 #if TSF_DEBUG_OUTPUT
1296 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
1301 public void GetScreenExt(int i_viewCookie, out RECT o_rect)
1303 #if TSF_DEBUG_OUTPUT
1304 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1307 if (GetScreenExtent == null)
1308 throw new NotImplementedException();
1310 POINT pointTopLeft, pointBottomRight;
1312 GetScreenExtent(out pointTopLeft, out pointBottomRight);
1314 o_rect.left = (int)(pointTopLeft.x);
1315 o_rect.top = (int)(pointTopLeft.y);
1316 o_rect.bottom = (int)(pointBottomRight.y);
1317 o_rect.right = (int)(pointBottomRight.x);
1318 #if TSF_DEBUG_OUTPUT
1319 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
1324 public void RequestSupportedAttrs(
1325 AttributeFlags i_flags,
1327 Guid[] i_filterAttributes
1330 #if TSF_DEBUG_OUTPUT
1331 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1334 for (int i = 0; i < i_length; i++)
1336 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
1338 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
1339 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
1341 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
1345 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
1352 public void RequestAttrsAtPosition(
1355 Guid[] i_filterAttributes,
1356 AttributeFlags i_flags
1359 #if TSF_DEBUG_OUTPUT
1360 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1363 for (int i = 0; i < i_length; i++)
1365 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
1367 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
1368 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
1370 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
1374 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
1381 public void RequestAttrsTransitioningAtPosition(
1384 Guid[] i_filterAttributes,
1385 AttributeFlags i_flags
1388 #if TSF_DEBUG_OUTPUT
1389 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1396 public void FindNextAttrTransition(
1400 Guid[] i_filterAttributes,
1401 AttributeFlags i_flags,
1402 out int o_nextIndex,
1404 out int o_foundOffset
1407 #if TSF_DEBUG_OUTPUT
1408 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1411 throw new NotImplementedException();
1415 public void RetrieveRequestedAttrs(
1417 TS_ATTRVAL[] o_attributeVals,
1418 out int o_fetchedLength
1421 #if TSF_DEBUG_OUTPUT
1422 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1425 o_fetchedLength = 0;
1426 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)
1428 if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)
1430 o_attributeVals[o_fetchedLength].overlappedId = 0;
1431 o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;
1432 o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;
1434 if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)
1435 _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;
1438 _attributeInfo[i].flags = AttributeInfoFlags.None;
1445 #region "ITfContextOwnerCompositionSink インターフェイスの実装"
1446 /// <summary>コンポジション入力が開始された時の処理。</summary>
1447 public void OnStartComposition(ITfCompositionView view, out bool ok)
1449 #if TSF_DEBUG_OUTPUT
1450 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1453 if( CompositionStarted != null )
1454 ok = CompositionStarted();
1461 //========================================================================================
1464 /// <summary>コンポジションが変更された時の処理。</summary>
1465 public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)
1467 #if TSF_DEBUG_OUTPUT
1468 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1471 if (rangeNew == null)
1476 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;
1478 rangeAcp.GetExtent(out start, out count);
1480 if (this.CompositionUpdated != null)
1481 this.CompositionUpdated(start, start + count);
1486 //========================================================================================
1489 /// <summary>コンポジション入力が終了した時の処理。</summary>
1490 public void OnEndComposition(ITfCompositionView view)
1492 #if TSF_DEBUG_OUTPUT
1493 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
1496 if( CompositionEnded != null )
1500 #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"
1503 /// <summary>表示属性の取得</summary>
1504 public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)
1506 ITfRangeACP allRange;
1507 _services.CreateRange(start, end, out allRange);
1509 foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))
1512 ReleaseComObject("allRange", ref allRange);
1515 IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)
1517 #if TSF_DEBUG_OUTPUT
1518 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
1521 ITfProperty property = null; // プロパティインターフェイス
1522 IEnumTfRanges enumRanges; // 範囲の列挙子
1523 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;
1525 if (_context == null || _services == null)
1528 // GUID_PROP_ATTRIBUTE プロパティを取得。
1529 _context.GetProperty(ref guidPropAttribute, out property);
1530 if (property == null)
1533 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。
1534 property.EnumRanges((int)_editCookie, out enumRanges, range);
1536 ITfRange[] ranges = new ITfRange[1];
1537 int fetchedLength = 0;
1538 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))
1539 && fetchedLength > 0)
1541 // ItfRange から ItfRangeACP を取得。
1542 ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;
1543 if (rangeACP == null)
1544 continue; // 普通はあり得ない
1548 rangeACP.GetExtent(out start, out count);
1550 // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。
1551 VARIANT value = new VARIANT();
1552 property.GetValue((int)_editCookie, ranges[0], ref value);
1553 if (value.vt == (short)VarEnum.VT_I4)
1556 ITfDisplayAttributeInfo info;
1557 TF_DISPLAYATTRIBUTE attribute;
1559 // GUID ATOM から GUID を取得する。
1560 _categoryMgr.GetGUID((int)value.data1, out guid);
1561 // その GUID から IDisplayAttributeInfo インターフェイスを取得。
1562 _displayAttributeMgr.GetDisplayAttributeInfo(
1567 // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。
1568 info.GetAttributeInfo(out attribute);
1569 ReleaseComObject("info", ref info);
1571 yield return new TextDisplayAttribute
1574 endIndex = start + count,
1575 attribute = attribute
1578 #if TSF_DEBUG_OUTPUT_DISPLAY_ATTR
1580 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",
1581 start, start + count
1583 Debug.WriteLine(attribute.bAttr);
1585 "LineColorType: {0}, {1}",
1586 attribute.crLine.type, attribute.crLine.indexOrColorRef
1589 "TextColorType: {0}, {1}",
1590 attribute.crText.type, attribute.crText.indexOrColorRef
1593 "BackColorType: {0}, {1}",
1594 attribute.crBk.type, attribute.crBk.indexOrColorRef
1597 "Bold, Style : {0}, {1}",
1598 attribute.fBoldLine, attribute.lsStyle
1603 ReleaseComObject("rangeACP", ref rangeACP);
1606 ReleaseComObject("ranges[0]", ref ranges[0]);
1607 ReleaseComObject("enumRanges", ref enumRanges);
1608 ReleaseComObject("property", ref property);
1614 protected ITfThreadMgr2 _threadMgr;
1616 protected ITfThreadMgr _threadMgr;
1618 protected ITfDocumentMgr _documentMgr;
1619 protected ITfFunctionProvider _functionProvider;
1620 protected ITfFnReconversion _reconversion;
1621 protected ITfContext _context;
1622 protected ITfCategoryMgr _categoryMgr;
1623 protected ITfDisplayAttributeMgr _displayAttributeMgr;
1624 protected ITextStoreACPSink _sink;
1625 protected uint _editCookie = 0;
1626 protected ITextStoreACPServices _services;
1627 protected AdviseFlags _adviseFlags = 0;
1628 protected LockFlags _lockFlags = 0;
1629 protected bool _pendingLockUpgrade = false;
1632 /// AttributeInfo で使用されるフラグ。各属性の状態を示す。
1634 protected enum AttributeInfoFlags
1636 /// <summary>何もない。</summary>
1638 /// <summary>デフォルト値の要求。</summary>
1640 /// <summary>要求された。</summary>
1644 protected struct AttributeInfo
1647 public AttributeInfoFlags flags;
1648 public VARIANT currentValue;
1649 public VARIANT defaultValue;
1652 protected AttributeInfo[] _attributeInfo = new AttributeInfo[1];