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 double GetDpiHandeler();
\r
98 public event GetDpiHandeler GetDpi;
\r
100 public delegate bool IsReadOnlyHandler();
\r
101 public event IsReadOnlyHandler IsReadOnly;
\r
103 public delegate bool IsLoadingHandler();
\r
104 public event IsLoadingHandler IsLoading;
\r
106 public delegate int GetStringLengthHandler();
\r
107 public event GetStringLengthHandler GetStringLength;
\r
109 public delegate void GetSelectionIndexHandler(out int o_start, out int o_end);
\r
110 public event GetSelectionIndexHandler GetSelectionIndex;
\r
112 public delegate void SetSelectionIndexHandler(int i_start, int i_end);
\r
113 public event SetSelectionIndexHandler SetSelectionIndex;
\r
115 public delegate string GetStringHandler(int start, int length);
\r
116 public event GetStringHandler GetString;
\r
118 public delegate void InsertAtSelectionHandler(string i_value);
\r
119 public event InsertAtSelectionHandler InsertAtSelection;
\r
121 public delegate void GetScreenExtentHandler(
\r
122 out POINT o_pointTopLeft,
\r
123 out POINT o_pointBottomRight
\r
125 public event GetScreenExtentHandler GetScreenExtent;
\r
127 public delegate void GetStringExtentHandler(
\r
130 out POINT o_pointTopLeft,
\r
131 out POINT o_pointBottomRight
\r
133 public event GetStringExtentHandler GetStringExtent;
\r
135 public delegate bool CompositionStartedHandler();
\r
136 public event CompositionStartedHandler CompositionStarted;
\r
138 public delegate void CompostionUpdateHandler(int start, int end);
\r
139 public event CompostionUpdateHandler CompositionUpdated;
\r
141 public delegate void CompositionEndedHandler();
\r
142 public event CompositionEndedHandler CompositionEnded;
\r
145 public TextStoreBase()
\r
147 #if TSF_DEBUG_OUTPUT
\r
148 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
156 CreateCategoryMgr();
\r
158 CreateDisplayAttributeMgr();
\r
161 _threadMgr.CreateDocumentMgr(out _documentMgr);
\r
163 // スレッドマネージャのアクティブ化
\r
165 _threadMgr.Activate(out clientId);
\r
168 _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);
\r
171 _documentMgr.Push(_context);
\r
173 // ファンクションプロバイダーを取得する。
\r
174 Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;
\r
175 _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);
\r
177 // ITfReconversion オブジェクトを取得する。
\r
178 var guidNull = new Guid();
\r
179 var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5"); //ITfFnReconversionの定義から
\r
180 object reconversion = null;
\r
181 _functionProvider.GetFunction(
\r
183 ref guidReconversion,
\r
186 _reconversion = reconversion as ITfFnReconversion;
\r
190 Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;
\r
191 _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);
\r
192 _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;
\r
193 _attributeInfo[0].flags = AttributeInfoFlags.None;
\r
194 _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;
\r
195 _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;
\r
196 _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;
\r
198 catch (Exception exception)
\r
200 Debug.WriteLine(exception.Message);
\r
207 /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります
\r
209 /// <param name="flag"></param>
\r
210 protected void Dispose(bool flag)
\r
214 #if TSF_DEBUG_OUTPUT
\r
215 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
218 ReleaseComObject("_reconversion", ref _reconversion);
\r
219 ReleaseComObject("_functionProvider", ref _functionProvider);
\r
220 ReleaseComObject("_context", ref _context);
\r
221 DestroyDocumentMgr();
\r
222 DestroyDisplayAttributeMgr();
\r
223 DestroyCategoryMgr();
\r
224 DestroyThreadMgr();
\r
226 GC.SuppressFinalize(this);
\r
231 /// スレッドマネージャの生成。このメソッドの実装は必須です
\r
234 /// <exception cref="COMException">
\r
235 /// スレッドマネージャーの生成に失敗した場合。
\r
237 protected virtual void CreateThreadMgr()
\r
239 throw new NotImplementedException();
\r
245 void DestroyThreadMgr()
\r
247 if (_threadMgr != null)
\r
249 try { _threadMgr.Deactivate(); }
\r
250 catch (Exception) { }
\r
252 ReleaseComObject("_threadMgr", ref _threadMgr);
\r
260 /// <exception cref="COMException">
\r
261 /// カテゴリマネージャーの生成に失敗した場合。
\r
263 void CreateCategoryMgr()
\r
265 if (_categoryMgr == null)
\r
267 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);
\r
268 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;
\r
270 if (_categoryMgr == null)
\r
272 const string message = "カテゴリマネージャーの生成に失敗しました。";
\r
273 Debug.WriteLine(message);
\r
274 throw new COMException(message, HRESULT.E_NOTIMPL);
\r
282 void DestroyCategoryMgr()
\r
284 ReleaseComObject("_categoryMgr", ref _categoryMgr);
\r
291 /// <exception cref="COMException">
\r
292 /// 表示属性マネージャーの生成に失敗した場合。
\r
294 void CreateDisplayAttributeMgr()
\r
296 if (_displayAttributeMgr == null)
\r
298 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);
\r
299 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;
\r
301 if (_displayAttributeMgr == null)
\r
303 const string message = "表示属性マネージャーの生成に失敗しました。";
\r
304 Debug.WriteLine(message);
\r
305 throw new COMException(message, HRESULT.E_NOTIMPL);
\r
313 void DestroyDisplayAttributeMgr()
\r
315 ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);
\r
319 /// ドキュメントマネージャーの解放
\r
321 void DestroyDocumentMgr()
\r
323 if (_documentMgr != null)
\r
325 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }
\r
326 catch (Exception) { }
\r
328 ReleaseComObject("_documentMgr", ref _documentMgr);
\r
333 /// COM オブジェクトのリリースとデバッグメッセージ出力。
\r
335 protected static void ReleaseComObject<ComObject>(
\r
336 string i_objectName,
\r
337 ref ComObject io_comObject
\r
340 if (io_comObject != null)
\r
342 var refCount = Marshal.ReleaseComObject(io_comObject);
\r
343 #if TSF_DEBUG_OUTPUT
\r
345 "Marshal.ReleaseComObject({0}) returns {1}.",
\r
351 io_comObject = default(ComObject);
\r
356 #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
\r
358 /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
360 public void NotifySelectionChanged()
\r
362 if( _sink != null )
\r
364 #if TSF_DEBUG_OUTPUT
\r
365 DebugOut.Print(DebugOut.GetCaller());
\r
367 if ((_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0)
\r
368 _sink.OnSelectionChange();
\r
373 //=========================================================================================
\r
377 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
379 void NotifyTextChanged(TS_TEXTCHANGE textChange)
\r
381 if( _sink != null )
\r
383 #if TSF_DEBUG_OUTPUT
\r
384 DebugOut.Print(DebugOut.GetCaller());
\r
386 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
\r
387 _sink.OnTextChange(0, ref textChange);
\r
388 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
393 //=========================================================================================
\r
396 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
398 /// <param name="start">開始位置</param>
\r
399 /// <param name="oldend">更新前の終了位置</param>
\r
400 /// <param name="newend">更新後の終了位置</param>
\r
402 /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください
\r
404 public void NotifyTextChanged(int start,int oldend,int newend)
\r
408 #if TSF_DEBUG_OUTPUT
\r
409 DebugOut.Print(DebugOut.GetCaller());
\r
411 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
\r
413 var textChange = new TS_TEXTCHANGE();
\r
414 textChange.start = start;
\r
415 textChange.oldEnd = oldend;
\r
416 textChange.newEnd = newend;
\r
418 _sink.OnTextChange(0, ref textChange);
\r
420 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
425 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
427 /// <param name="i_oldLength"></param>
\r
428 /// <param name="i_newLength"></param>
\r
429 public void NotifyTextChanged(int i_oldLength, int i_newLength)
\r
431 if( _sink != null )
\r
433 #if TSF_DEBUG_OUTPUT
\r
434 DebugOut.Print(DebugOut.GetCaller());
\r
436 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
\r
438 var textChange = new TS_TEXTCHANGE();
\r
439 textChange.start = 0;
\r
440 textChange.oldEnd = i_oldLength;
\r
441 textChange.newEnd = i_newLength;
\r
443 _sink.OnTextChange(0, ref textChange);
\r
445 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
451 //=========================================================================================
\r
454 /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>
\r
455 public void SetFocus()
\r
457 #if TSF_DEBUG_OUTPUT
\r
458 DebugOut.Print(DebugOut.GetCaller());
\r
460 if (_threadMgr != null)
\r
461 _threadMgr.SetFocus(_documentMgr);
\r
463 #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
\r
469 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
\r
470 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
\r
471 public Unlocker LockDocument(bool i_writable)
\r
473 #if TSF_DEBUG_OUTPUT
\r
474 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
\r
480 if( this._lockFlags == 0 )
\r
483 this._lockFlags = LockFlags.TS_LF_READWRITE;
\r
485 this._lockFlags = LockFlags.TS_LF_READ;
\r
487 #if TSF_DEBUG_OUTPUT
\r
488 Debug.WriteLine("LockDocument is succeeded.");
\r
491 return new Unlocker(this);
\r
495 #if TSF_DEBUG_OUTPUT
\r
496 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
\r
506 //========================================================================================
\r
512 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
\r
513 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
\r
514 public Unlocker LockDocument(LockFlags i_flags)
\r
516 #if TSF_DEBUG_OUTPUT
\r
517 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
\r
523 if( this._lockFlags == 0 )
\r
525 this._lockFlags = i_flags;
\r
527 #if TSF_DEBUG_OUTPUT
\r
528 Debug.WriteLine("LockDocument is succeeded.");
\r
531 return new Unlocker(this);
\r
535 #if TSF_DEBUG_OUTPUT
\r
536 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
\r
546 //========================================================================================
\r
550 /// ドキュメントのアンロックを行う。
\r
552 public void UnlockDocument()
\r
554 #if TSF_DEBUG_OUTPUT
\r
555 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
563 if( _pendingLockUpgrade )
\r
565 _pendingLockUpgrade = false;
\r
567 RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);
\r
573 //========================================================================================
\r
577 /// 指定されたフラグでロックしている状態かどうか調べる。
\r
579 /// <param name="i_lockFlags"></param>
\r
580 /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>
\r
581 public bool IsLocked(LockFlags i_lockFlags)
\r
583 #if TSF_DEBUG_OUTPUT
\r
584 using(var dbgout = new DebugOut("{0}({1})",
\r
585 DebugOut.GetCaller(), i_lockFlags) )
\r
588 #if TSF_DEBUG_OUTPUT
\r
590 "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)
\r
593 return (this._lockFlags & i_lockFlags) == i_lockFlags;
\r
600 /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>
\r
601 public bool IsLocked()
\r
603 #if TSF_DEBUG_OUTPUT
\r
604 using(var dbgout = new DebugOut("{0}",
\r
605 DebugOut.GetCaller()) )
\r
608 bool retval = this._lockFlags != 0;
\r
609 #if TSF_DEBUG_OUTPUT
\r
611 "IsLocked() returns " + retval
\r
619 #region ITextStroeACP,ITextStoreACP2の共通部分
\r
624 public void InsertTextAtSelection(string s)
\r
626 TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();
\r
628 using (var unlocker = LockDocument(true))
\r
630 if (unlocker != null)
\r
632 int startIndex, endIndex;
\r
634 InsertTextAtSelection(
\r
635 UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,
\r
645 // シンクの OnSelectionChange() をコール。
\r
646 NotifySelectionChanged();
\r
647 NotifyTextChanged(textChange);
\r
650 public void InsertEmbeddedAtSelection(
\r
651 InsertAtSelectionFlags flags,
\r
655 out TS_TEXTCHANGE change
\r
658 #if TSF_DEBUG_OUTPUT
\r
659 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
662 throw new NotImplementedException();
\r
666 public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)
\r
668 #if TSF_DEBUG_OUTPUT
\r
669 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
672 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より
\r
674 throw new COMException(
\r
675 "ITextStoreACPSink 以外のIIDが渡されました。",
\r
676 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
681 if (_sink == i_unknown)
\r
683 _adviseFlags = i_mask;
\r
686 else if (_sink != null)
\r
688 throw new COMException(
\r
690 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT
\r
696 _services = (ITextStoreACPServices)i_unknown;
\r
697 _sink = (ITextStoreACPSink)i_unknown;
\r
698 _adviseFlags = i_mask;
\r
703 public void UnadviseSink(object i_unknown)
\r
705 #if TSF_DEBUG_OUTPUT
\r
706 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
709 if (_sink == null || _sink != i_unknown)
\r
711 throw new COMException(
\r
713 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
\r
723 public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)
\r
725 #if TSF_DEBUG_OUTPUT
\r
726 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
729 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;
\r
733 throw new COMException(
\r
735 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
\r
739 if (_lockFlags != 0) // すでにロックされた状態の場合。
\r
741 if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)
\r
743 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
\r
747 if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ
\r
748 && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)
\r
750 _pendingLockUpgrade = true;
\r
751 o_sessionResult = TsResult.TS_S_ASYNC;
\r
755 throw new COMException();
\r
758 using (var unlocker = LockDocument(i_lockFlags))
\r
760 // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。
\r
761 if (unlocker == null)
\r
763 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
\r
765 // ロックに成功した場合は OnLockGranted() を呼び出す。
\r
770 o_sessionResult = _sink.OnLockGranted(i_lockFlags);
\r
772 catch (COMException comException)
\r
774 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
\r
775 Debug.WriteLine(" " + comException.Message);
\r
776 o_sessionResult = comException.HResult;
\r
778 catch (Exception exception)
\r
780 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
\r
781 Debug.WriteLine(" " + exception.Message);
\r
788 public void GetStatus(out TS_STATUS o_documentStatus)
\r
790 #if TSF_DEBUG_OUTPUT
\r
791 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
794 if (IsReadOnly != null && IsReadOnly())
\r
795 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;
\r
796 if (IsLoading != null && IsLoading())
\r
797 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;
\r
799 o_documentStatus.dynamicFlags = 0;
\r
800 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;
\r
804 public void QueryInsert(
\r
808 out int o_startIndex,
\r
812 #if TSF_DEBUG_OUTPUT
\r
813 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
816 if (GetStringLength == null)
\r
817 throw new NotImplementedException();
\r
819 int documentLength = GetStringLength();
\r
821 if (i_startIndex < 0
\r
822 || i_startIndex > i_endIndex
\r
823 || i_endIndex > documentLength)
\r
825 throw new COMException(
\r
827 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
830 o_startIndex = i_startIndex;
\r
831 o_endIndex = i_endIndex;
\r
833 #if TSF_DEBUG_OUTPUT
\r
834 DebugOut.Print("o_startIndex:{0} o_endIndex:{1}", i_startIndex, i_endIndex);
\r
839 public void GetSelection(
\r
841 int i_selectionBufferLength,
\r
842 TS_SELECTION_ACP[] o_selections,
\r
843 out int o_fetchedLength
\r
846 #if TSF_DEBUG_OUTPUT
\r
847 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
850 if (GetSelectionIndex == null)
\r
851 throw new NotImplementedException();
\r
853 o_fetchedLength = 0;
\r
855 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
857 throw new COMException(
\r
859 TsResult.TS_E_NOLOCK
\r
863 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、
\r
864 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。
\r
865 if (i_index != -1 && i_index > 0)
\r
867 throw new COMException(
\r
868 "選択は1つだけしかサポートしていません。",
\r
869 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
873 if (i_selectionBufferLength > 0)
\r
875 int start = 0, end = 0;
\r
876 GetSelectionIndex(out start, out end);
\r
879 o_selections[0].start = start;
\r
880 o_selections[0].end = end;
\r
881 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;
\r
882 o_selections[0].style.interimChar = false;
\r
886 o_selections[0].start = end;
\r
887 o_selections[0].end = start;
\r
888 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;
\r
889 o_selections[0].style.interimChar = false;
\r
892 o_fetchedLength = 1;
\r
894 #if TSF_DEBUG_OUTPUT
\r
895 DebugOut.Print("sel start:{0} end:{1}", start, end);
\r
901 public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)
\r
903 #if TSF_DEBUG_OUTPUT
\r
904 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
905 DebugOut.GetCaller(),
\r
906 i_selections[0].start,
\r
907 i_selections[0].end))
\r
910 if (SetSelectionIndex == null)
\r
911 throw new NotImplementedException();
\r
915 throw new COMException(
\r
916 "選択は1つだけしかサポートしていません。",
\r
917 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
921 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)
\r
923 throw new COMException(
\r
925 TsResult.TS_E_NOLOCK
\r
929 SetSelectionIndex(i_selections[0].start, i_selections[0].end);
\r
931 #if TSF_DEBUG_OUTPUT
\r
932 DebugOut.Print("set selection startIndex:{0} endIndex:{1}", i_selections[0].start, i_selections[0].end);
\r
937 public void GetText(
\r
940 char[] o_plainText,
\r
941 int i_plainTextLength,
\r
942 out int o_plainTextLength,
\r
943 TS_RUNINFO[] o_runInfos,
\r
944 int i_runInfoLength,
\r
945 out int o_runInfoLength,
\r
946 out int o_nextUnreadCharPos
\r
949 #if TSF_DEBUG_OUTPUT
\r
950 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
953 if (GetStringLength == null || GetString == null)
\r
954 throw new NotImplementedException();
\r
956 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
958 throw new COMException(
\r
960 TsResult.TS_E_NOLOCK
\r
964 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
965 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
966 || i_endIndex > GetStringLength())
\r
968 throw new COMException(
\r
970 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
974 var textLength = 0;
\r
975 var copyLength = 0;
\r
977 if (i_endIndex == -1)
\r
978 textLength = GetStringLength() - i_startIndex;
\r
980 textLength = i_endIndex - i_startIndex;
\r
981 copyLength = Math.Min(i_plainTextLength, textLength);
\r
984 var text = GetString(i_startIndex, copyLength);
\r
985 #if TSF_DEBUG_OUTPUT
\r
986 DebugOut.Print("got text:{0} from {1} length {2}", text,i_startIndex,copyLength);
\r
988 for (int i = 0; i < copyLength; i++)
\r
990 o_plainText[i] = text[i];
\r
994 o_plainTextLength = copyLength;
\r
996 if (i_runInfoLength > 0)
\r
998 o_runInfos[0].type = TsRunType.TS_RT_PLAIN;
\r
999 o_runInfos[0].length = copyLength;
\r
1001 o_runInfoLength = 1;
\r
1004 o_nextUnreadCharPos = i_startIndex + copyLength;
\r
1008 public void SetText(
\r
1009 SetTextFlags i_flags,
\r
1014 out TS_TEXTCHANGE o_textChange
\r
1017 #if TSF_DEBUG_OUTPUT
\r
1018 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
1019 DebugOut.GetCaller(),
\r
1020 i_startIndex, i_endIndex) )
\r
1023 var selections = new TS_SELECTION_ACP[]
\r
1025 new TS_SELECTION_ACP
\r
1027 start = i_startIndex,
\r
1029 style = new TS_SELECTIONSTYLE
\r
1031 ase = TsActiveSelEnd.TS_AE_END,
\r
1032 interimChar = false
\r
1037 int startIndex = 0, endIndex = 0;
\r
1038 SetSelection(1, selections);
\r
1039 InsertTextAtSelection(
\r
1040 InsertAtSelectionFlags.TF_IAS_NOQUERY,
\r
1050 public void GetFormattedText(int i_start, int i_end, out object o_obj)
\r
1052 #if TSF_DEBUG_OUTPUT
\r
1053 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1056 throw new NotImplementedException();
\r
1060 public void GetEmbedded(
\r
1062 ref Guid i_guidService,
\r
1067 #if TSF_DEBUG_OUTPUT
\r
1068 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1071 throw new NotImplementedException();
\r
1075 public void QueryInsertEmbedded(
\r
1076 ref Guid i_guidService,
\r
1078 out bool o_insertable
\r
1081 #if TSF_DEBUG_OUTPUT
\r
1082 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1085 throw new NotImplementedException();
\r
1089 public void InsertEmbedded(
\r
1090 InsertEmbeddedFlags i_flags,
\r
1094 out TS_TEXTCHANGE o_textChange
\r
1097 #if TSF_DEBUG_OUTPUT
\r
1098 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1101 throw new NotImplementedException();
\r
1105 public void InsertTextAtSelection(
\r
1106 InsertAtSelectionFlags i_flags,
\r
1109 out int o_startIndex,
\r
1110 out int o_endIndex,
\r
1111 out TS_TEXTCHANGE o_textChange
\r
1114 #if TSF_DEBUG_OUTPUT
\r
1115 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1118 if (GetSelectionIndex == null || InsertAtSelection == null)
\r
1119 throw new NotImplementedException();
\r
1121 int selectionStart = 0, selectionEnd = 0;
\r
1122 GetSelectionIndex(out selectionStart, out selectionEnd);
\r
1124 // 問い合わせのみで実際には操作を行わない
\r
1125 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)
\r
1127 o_startIndex = Math.Min(selectionStart, selectionEnd);
\r
1128 o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;
\r
1130 o_textChange.start = o_startIndex;
\r
1131 o_textChange.oldEnd = o_endIndex;
\r
1132 o_textChange.newEnd = o_startIndex + i_length;
\r
1136 var start = Math.Min(selectionStart, selectionEnd);
\r
1137 var end = Math.Max(selectionStart, selectionEnd);
\r
1139 #if TSF_DEBUG_OUTPUT
\r
1140 DebugOut.Print("start: {0}, end: {1}, text: {2}", start, end, new string(i_text));
\r
1143 InsertAtSelection(new string(i_text));
\r
1145 o_startIndex = start;
\r
1146 o_endIndex = start + i_length;
\r
1148 o_textChange.start = start;
\r
1149 o_textChange.oldEnd = end;
\r
1150 o_textChange.newEnd = start + i_length;
\r
1152 // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。
\r
1154 // SetSelectionIndex(start, start + i_length);
\r
1159 public void GetEndACP(out int o_length)
\r
1161 #if TSF_DEBUG_OUTPUT
\r
1162 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1165 if (GetStringLength == null)
\r
1166 throw new NotImplementedException();
\r
1168 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1170 throw new COMException(
\r
1171 "読取用ロックがされていません。",
\r
1172 TsResult.TS_E_NOLOCK
\r
1176 o_length = GetStringLength();
\r
1180 public void GetActiveView(out int o_viewCookie)
\r
1182 #if TSF_DEBUG_OUTPUT
\r
1183 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1190 public void GetACPFromPoint(
\r
1192 ref POINT i_point,
\r
1193 GetPositionFromPointFlags i_flags,
\r
1197 #if TSF_DEBUG_OUTPUT
\r
1198 using (var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1201 throw new NotImplementedException();
\r
1205 public void GetTextExt(
\r
1210 out bool o_isClipped
\r
1213 #if TSF_DEBUG_OUTPUT
\r
1214 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1217 if (GetStringLength == null)
\r
1218 throw new NotImplementedException();
\r
1221 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1223 throw new COMException(
\r
1224 "読取用ロックがされていません。",
\r
1225 TsResult.TS_E_NOLOCK
\r
1229 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
1230 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
1231 || i_endIndex > GetStringLength())
\r
1233 throw new COMException(
\r
1235 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
1239 if (i_endIndex == -1)
\r
1240 i_endIndex = GetStringLength();
\r
1242 var pointTopLeft = new POINT();
\r
1243 var pointBotttomRight = new POINT();
\r
1244 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);
\r
1246 if(this.GetDpi == null)
\r
1247 throw new NotImplementedException();
\r
1249 double dpi = this.GetDpi();
\r
1251 o_rect.left = (int)(pointTopLeft.x * dpi / 96.0);
\r
1252 o_rect.top = (int)(pointTopLeft.y * dpi / 96.0);
\r
1253 o_rect.bottom = (int)(pointBotttomRight.y * dpi / 96.0);
\r
1254 o_rect.right = (int)(pointBotttomRight.x * dpi / 96.0);
\r
1255 o_isClipped = false;
\r
1256 #if TSF_DEBUG_OUTPUT
\r
1257 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
\r
1262 public void GetScreenExt(int i_viewCookie, out RECT o_rect)
\r
1264 #if TSF_DEBUG_OUTPUT
\r
1265 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1268 if (GetScreenExtent == null)
\r
1269 throw new NotImplementedException();
\r
1271 POINT pointTopLeft, pointBottomRight;
\r
1273 GetScreenExtent(out pointTopLeft, out pointBottomRight);
\r
1275 if (this.GetDpi == null)
\r
1276 throw new NotImplementedException();
\r
1278 double dpi = this.GetDpi();
\r
1280 o_rect.left = (int)(pointTopLeft.x * dpi / 96.0);
\r
1281 o_rect.top = (int)(pointTopLeft.y * dpi / 96.0);
\r
1282 o_rect.bottom = (int)(pointBottomRight.y * dpi / 96.0);
\r
1283 o_rect.right = (int)(pointBottomRight.x * dpi / 96.0);
\r
1284 #if TSF_DEBUG_OUTPUT
\r
1285 DebugOut.Print("rect left:{0} top:{1} bottom:{2} right:{3}", o_rect.left, o_rect.top, o_rect.bottom, o_rect.right);
\r
1290 public void RequestSupportedAttrs(
\r
1291 AttributeFlags i_flags,
\r
1293 Guid[] i_filterAttributes
\r
1296 #if TSF_DEBUG_OUTPUT
\r
1297 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1300 for (int i = 0; i < i_length; i++)
\r
1302 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1304 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1305 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1307 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1311 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1318 public void RequestAttrsAtPosition(
\r
1321 Guid[] i_filterAttributes,
\r
1322 AttributeFlags i_flags
\r
1325 #if TSF_DEBUG_OUTPUT
\r
1326 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1329 for (int i = 0; i < i_length; i++)
\r
1331 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1333 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1334 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1336 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1340 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1347 public void RequestAttrsTransitioningAtPosition(
\r
1350 Guid[] i_filterAttributes,
\r
1351 AttributeFlags i_flags
\r
1354 #if TSF_DEBUG_OUTPUT
\r
1355 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1362 public void FindNextAttrTransition(
\r
1366 Guid[] i_filterAttributes,
\r
1367 AttributeFlags i_flags,
\r
1368 out int o_nextIndex,
\r
1370 out int o_foundOffset
\r
1373 #if TSF_DEBUG_OUTPUT
\r
1374 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1377 throw new NotImplementedException();
\r
1381 public void RetrieveRequestedAttrs(
\r
1383 TS_ATTRVAL[] o_attributeVals,
\r
1384 out int o_fetchedLength
\r
1387 #if TSF_DEBUG_OUTPUT
\r
1388 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1391 o_fetchedLength = 0;
\r
1392 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)
\r
1394 if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)
\r
1396 o_attributeVals[o_fetchedLength].overlappedId = 0;
\r
1397 o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;
\r
1398 o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;
\r
1400 if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)
\r
1401 _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;
\r
1403 o_fetchedLength++;
\r
1404 _attributeInfo[i].flags = AttributeInfoFlags.None;
\r
1411 #region "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1412 /// <summary>コンポジション入力が開始された時の処理。</summary>
\r
1413 public void OnStartComposition(ITfCompositionView view, out bool ok)
\r
1415 #if TSF_DEBUG_OUTPUT
\r
1416 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1419 if( CompositionStarted != null )
\r
1420 ok = CompositionStarted();
\r
1427 //========================================================================================
\r
1430 /// <summary>コンポジションが変更された時の処理。</summary>
\r
1431 public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)
\r
1433 #if TSF_DEBUG_OUTPUT
\r
1434 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1437 if (rangeNew == null)
\r
1442 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;
\r
1444 rangeAcp.GetExtent(out start, out count);
\r
1446 if (this.CompositionUpdated != null)
\r
1447 this.CompositionUpdated(start, start + count);
\r
1452 //========================================================================================
\r
1455 /// <summary>コンポジション入力が終了した時の処理。</summary>
\r
1456 public void OnEndComposition(ITfCompositionView view)
\r
1458 #if TSF_DEBUG_OUTPUT
\r
1459 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1462 if( CompositionEnded != null )
\r
1463 CompositionEnded();
\r
1466 #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1469 /// <summary>表示属性の取得</summary>
\r
1470 public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)
\r
1472 ITfRangeACP allRange;
\r
1473 _services.CreateRange(start, end, out allRange);
\r
1475 foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))
\r
1476 yield return attr;
\r
1478 ReleaseComObject("allRange", ref allRange);
\r
1481 IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)
\r
1483 #if TSF_DEBUG_OUTPUT
\r
1484 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1487 ITfProperty property = null; // プロパティインターフェイス
\r
1488 IEnumTfRanges enumRanges; // 範囲の列挙子
\r
1489 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;
\r
1491 if (_context == null || _services == null)
\r
1494 // GUID_PROP_ATTRIBUTE プロパティを取得。
\r
1495 _context.GetProperty(ref guidPropAttribute, out property);
\r
1496 if (property == null)
\r
1499 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。
\r
1500 property.EnumRanges((int)_editCookie, out enumRanges, range);
\r
1502 ITfRange[] ranges = new ITfRange[1];
\r
1503 int fetchedLength = 0;
\r
1504 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))
\r
1505 && fetchedLength > 0)
\r
1507 // ItfRange から ItfRangeACP を取得。
\r
1508 ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;
\r
1509 if (rangeACP == null)
\r
1510 continue; // 普通はあり得ない
\r
1512 // 範囲の開始位置と文字数を取得。
\r
1514 rangeACP.GetExtent(out start, out count);
\r
1516 // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。
\r
1517 VARIANT value = new VARIANT();
\r
1518 property.GetValue((int)_editCookie, ranges[0], ref value);
\r
1519 if (value.vt == (short)VarEnum.VT_I4)
\r
1522 ITfDisplayAttributeInfo info;
\r
1523 TF_DISPLAYATTRIBUTE attribute;
\r
1525 // GUID ATOM から GUID を取得する。
\r
1526 _categoryMgr.GetGUID((int)value.data1, out guid);
\r
1527 // その GUID から IDisplayAttributeInfo インターフェイスを取得。
\r
1528 _displayAttributeMgr.GetDisplayAttributeInfo(
\r
1533 // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。
\r
1534 info.GetAttributeInfo(out attribute);
\r
1535 ReleaseComObject("info", ref info);
\r
1537 yield return new TextDisplayAttribute
\r
1539 startIndex = start,
\r
1540 endIndex = start + count,
\r
1541 attribute = attribute
\r
1544 #if TSF_DEBUG_OUTPUT_DISPLAY_ATTR
\r
1546 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",
\r
1547 start, start + count
\r
1549 Debug.WriteLine(attribute.bAttr);
\r
1551 "LineColorType: {0}, {1}",
\r
1552 attribute.crLine.type, attribute.crLine.indexOrColorRef
\r
1555 "TextColorType: {0}, {1}",
\r
1556 attribute.crText.type, attribute.crText.indexOrColorRef
\r
1559 "BackColorType: {0}, {1}",
\r
1560 attribute.crBk.type, attribute.crBk.indexOrColorRef
\r
1563 "Bold, Style : {0}, {1}",
\r
1564 attribute.fBoldLine, attribute.lsStyle
\r
1569 ReleaseComObject("rangeACP", ref rangeACP);
\r
1572 ReleaseComObject("ranges[0]", ref ranges[0]);
\r
1573 ReleaseComObject("enumRanges", ref enumRanges);
\r
1574 ReleaseComObject("property", ref property);
\r
1580 protected ITfThreadMgr2 _threadMgr;
\r
1582 protected ITfThreadMgr _threadMgr;
\r
1584 protected ITfDocumentMgr _documentMgr;
\r
1585 protected ITfFunctionProvider _functionProvider;
\r
1586 protected ITfFnReconversion _reconversion;
\r
1587 protected ITfContext _context;
\r
1588 protected ITfCategoryMgr _categoryMgr;
\r
1589 protected ITfDisplayAttributeMgr _displayAttributeMgr;
\r
1590 protected ITextStoreACPSink _sink;
\r
1591 protected uint _editCookie = 0;
\r
1592 protected ITextStoreACPServices _services;
\r
1593 protected AdviseFlags _adviseFlags = 0;
\r
1594 protected LockFlags _lockFlags = 0;
\r
1595 protected bool _pendingLockUpgrade = false;
\r
1598 /// AttributeInfo で使用されるフラグ。各属性の状態を示す。
\r
1600 protected enum AttributeInfoFlags
\r
1602 /// <summary>何もない。</summary>
\r
1604 /// <summary>デフォルト値の要求。</summary>
\r
1606 /// <summary>要求された。</summary>
\r
1607 Requested = 1 << 1
\r
1610 protected struct AttributeInfo
\r
1612 public Guid attrID;
\r
1613 public AttributeInfoFlags flags;
\r
1614 public VARIANT currentValue;
\r
1615 public VARIANT defaultValue;
\r
1618 protected AttributeInfo[] _attributeInfo = new AttributeInfo[1];
\r