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