/// <summary> /// 現在のパラメータ一覧を取得する。 /// </summary> /// <param name="targetParameterIds"> /// 取得対象のパラメータID列挙。 null ならば存在する全パラメータを対象とする。 /// </param> /// <returns> /// パラメータIDとその値のディクショナリ。取得できなかった場合は null 。 /// </returns> protected override Result <Dictionary <ParameterId, decimal> > GetParametersImpl( IEnumerable <ParameterId> targetParameterIds) { // パラメータ値を取得するローカルメソッド Result <decimal> getParameter(ParameterId id, dynamic slider) { try { return((decimal)(double)slider.Value); } catch (Exception ex) { ThreadDebug.WriteException(ex); } return( 0, GetParameterTabItemName(id) + @"タブの" + id.GetInfo().DisplayName + @"値を取得できませんでした。"); } try { return(this.ProcessParameterSliders(getParameter, targetParameterIds)); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null, @"パラメータの取得に失敗しました。"); }
/// <summary> /// 音声保存処理の完了を待機する。 /// </summary> /// <param name="mainWindow">メインウィンドウ。</param> /// <param name="saveMenuAsync"> /// WAV書き出しメニュークリック処理に用いた非同期オブジェクト。 /// </param> /// <returns>成功したならば true 。そうでなければ false 。</returns> private Result <bool> SaveFileImpl_WaitSaving(dynamic mainWindow, Async saveMenuAsync) { Debug.Assert((DynamicAppVar)mainWindow != null); Debug.Assert(saveMenuAsync != null); try { // WAV書き出しメニュークリック処理とビジー表示が両方完了するまで待機 while (!saveMenuAsync.IsCompleted || IsBusyIndicatorVisible(mainWindow)) { Thread.Yield(); } // 保存完了ダイアログを探す var completeDialog = WaitUntil( () => { var win = WindowControl.FromZTop(this.TargetApp); return ((win.GetWindowText() == SaveCompleteDialogTitle) ? win : null); }, win => win != null); if (completeDialog == null) { return(false, @"本体の保存完了ダイアログが見つかりません。"); } // 保存完了ダイアログのOKボタンを押下する // 失敗してもよい try { var vtree = this.TargetAppVisualTree; var border = vtree.GetDescendant(completeDialog, 0); var buttonParent = border .Child // StackPanel .Children[1] // Border .Child // StackPanel .Children[1]; // Control var button = vtree.GetDescendant(buttonParent, 0); PerformClick(button); } catch (Exception ex) { ThreadDebug.WriteException(ex); } } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"音声保存処理の完了待機に失敗しました。"); } return(true); }
/// <summary> /// 現在設定されている文章を取得する。 /// </summary> /// <returns>文章。取得できなかった場合は null 。</returns> protected override Result <string> GetTextImpl() { // メインウィンドウを取得 var mainWin = this.GetMainWindow(); if (mainWin == null) { return(null, @"本体のウィンドウが見つかりません。"); } // 文章入力欄を取得 var textBox = GetMainTextBox(mainWin); if (textBox == null) { return(null, @"本体の文章入力欄が見つかりません。"); } try { return((string)textBox.Text); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null, @"本体の文章入力欄から文章を取得できませんでした。"); }
/// <summary> /// プロセスを終了させる。 /// </summary> /// <returns> /// 成功したならば true 。 /// 終了通知には成功したがプロセス側で終了が抑止されたならば null 。 /// 失敗したならば false 。 /// </returns> /// <remarks> /// <para> /// 既定では <see cref="LockObject"/> による排他ロックを行った後に /// <see cref="ExitProcessCore"/> を呼び出す。 /// その後、受け取ったプロパティ値変更通知デリゲートを排他ロック外で呼び出す。 /// プロパティ値変更通知デリゲートが例外を送出した場合は失敗扱いとなる。 /// </para> /// <para> /// 排他ロック内で <see cref="INotifyPropertyChanged.PropertyChanged"/> /// イベントを呼び出してしまうと、アタッチされたデリゲートから他のメソッドが /// 呼び出されることによるデッドロックの恐れがあるため、このような処理となっている。 /// </para> /// </remarks> public virtual Result <bool?> ExitProcess() { Result <bool?> result; Action raisePropChanged = null; try { lock (this.LockObject) { result = this.ExitProcessCore(out raisePropChanged); } } finally { try { raisePropChanged?.Invoke(); } catch (Exception ex) { ThreadTrace.WriteException(ex); result = ( false, ex.Message ?? (ex.GetType().Name + @" 例外が発生しました。")); } } return(result); }
/// <summary> /// Controls プロパティツリーを辿ることによって子孫コントロールを取得する。 /// </summary> /// <param name="root">ツリーのルートとなるコントロール。</param> /// <param name="treeIndices">Controls プロパティツリーインデックス配列。</param> /// <returns>コントロール。取得できなかった場合は null 。</returns> protected static dynamic GetControlFromControlsTree( dynamic root, params int[] treeIndices) { if (root != null && treeIndices != null) { try { var control = root; foreach (var index in treeIndices) { control = control.Controls[index]; } return(control); } catch (Exception ex) { ThreadTrace.WriteException(ex); } } return(null); }
public override void Load(UIntPtr location, uint size, int codeLabel, bool is_volatile) { UIntPtr objH, objO; ObjectTracking.GetObjectHandle(location, out objH, out objO); if (this.RecordRW && !this.CallStack.Peek().FullName.Contains("Microsoft.PSharp") && objH != null) { // TODO: Hack if (this.CallStack.Peek().ToString().Contains("Monitor")) { return; } // End hack ThreadTrace obj = this.ThreadTrace[this.ThreadTrace.Count - 1]; obj.Accesses.Add(new ActionInstr(false, location, objH, objO, GetSourceLocation(location))); this.DebugTrace.Add($"<ThreadMonitorLog> Load '{objH}' '{objO}' " + $"'{this.CallStack.Peek()}' '{GetSourceLocation(location)}'."); } else if (!this.CallStack.Peek().FullName.Contains("Microsoft.PSharp") && objH != null) { foreach (Tuple <Method, int> m in TaskMethods) { // TODO: This is fragile (for tasks) if (this.CallStack.Peek().ShortName.Contains(m.Item1.ShortName)) { ThreadTrace obj = Monitoring.ThreadTrace.CreateTraceForTask(m.Item2); obj.Accesses.Add(new ActionInstr(false, location, objH, objO, GetSourceLocation(location))); this.ThreadTrace.Add(obj); } } } }
/// <summary> /// 試聴/停止トグルボタンを取得する。 /// </summary> /// <param name="operationPanel"> /// 操作パネル。 null ならばメソッド内で取得される。 /// </param> /// <returns>コントロール。見つからないか取得できない状態ならば null 。</returns> public Result <dynamic> Get(dynamic operationPanel = null) { // 操作パネルを取得 var opePanel = operationPanel; if (opePanel == null) { var ov = this.OperationPanel.Get(); if (ov.Value == null) { return(null, ov.Message); } opePanel = ov.Value; } try { return(opePanel.Children[0].Children[0]); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null, @"本体の試聴/停止ボタンが見つかりません。"); }
/// <summary> /// 音声保存ダイアログを検索する処理を行う。 /// </summary> /// <returns>音声保存ダイアログ。見つからなければ null 。</returns> /// <remarks> /// オプションウィンドウ、ファイルダイアログ、 /// 確認ダイアログ(A.I.VOICEのみ)のいずれかを返す。 /// </remarks> private async Task <AutomationElement> DoFindSaveDialogTask() { try { var dialogs = await RepeatUntil( async() => await this.FindDialogs(), dlgs => dlgs.Any(), 150); return (dialogs .FirstOrDefault( d => { var name = d.Current.Name; return (name == SaveOptionDialogName) || (name == SaveFileDialogName) || (name == AiVoiceSaveConfirmDialogName); })); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null); }
/// <summary> /// 読み上げを停止させる。 /// </summary> /// <returns>成功したか既に停止中ならば true 。そうでなければ false 。</returns> protected override Result <bool> StopImpl() { // 試聴/停止トグルボタンを取得 var(button, failButton) = this.PlayStopToggle.Get(); if (button == null) { return(false, failButton); } try { if (!(bool)button.IsEnabled) { return(false, @"本体の試聴/停止ボタンがクリックできない状態です。"); } if ((bool?)button.IsChecked == false) { // 既に停止しているので何もしない return(true, @"停止済みです。"); } // IsChecked = false だと見た目は変化するが停止されない。 // PerformClick を使う。 // 試聴/停止トグルボタンをクリック PerformClick(button); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"本体の試聴/停止ボタンをクリックできませんでした。"); } return(true); }
/// <summary> /// ボイスプリセット一覧リストビューアイテムからボイスプリセット名を取得する。 /// </summary> /// <param name="presetListViewItem"> /// ボイスプリセット一覧リストビューアイテム。 /// </param> /// <returns>ボイスプリセット名。取得できなかった場合は null 。</returns> /// <remarks> /// ビジュアルツリーを走査するため、リストビューが表示状態であること。 /// </remarks> private string GetPresetName(dynamic presetListViewItem) { // Content.PresetName から取得するのが手っ取り早いのだが、 // VOICEROID2定義の型を参照することになるのでやめておく。 // ビジュアルツリー走査用オブジェクトを取得 var vtree = this.TargetAppVisualTree; if (vtree == null) { return(null); } try { var border = vtree.GetDescendant(presetListViewItem, 0); var presenter = border.Child.Child.Children[1]; var block = vtree.GetDescendant(presenter, 1, 0); return((string)block.Text); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null); }
/// <summary> /// AviUtl拡張編集ファイルのドロップ処理を行う。 /// </summary> /// <param name="exoFilePath">AviUtl拡張編集ファイルパス。</param> /// <param name="exoLength">AviUtl拡張編集オブジェクトのフレーム数。</param> /// <param name="layer">ドロップ先レイヤー番号。</param> /// <param name="aviUtlFileDropService"> /// AviUtl拡張編集ファイルドロップサービス。 /// </param> /// <returns>警告文字列。成功したならば null 。</returns> private static async Task <string> DoOperateExoDrop( string exoFilePath, int exoLength, int layer, IAviUtlFileDropService aviUtlFileDropService) { var result = GcmzDrops.FileDrop.Result.Fail; try { result = await aviUtlFileDropService.Run( exoFilePath, exoLength, layer, ExoDropTimeoutMilliseconds); } catch (Exception ex) { ThreadTrace.WriteException(ex); result = GcmzDrops.FileDrop.Result.Fail; } return(MakeFailMessageFromExoDropResult(result, true)); }
/// <summary> /// トークテキスト設定の実処理を行う。 /// </summary> /// <param name="text">設定するトークテキスト。</param> /// <returns>成功したならば true 。そうでなければ false 。</returns> protected override async Task <bool> DoSetTalkText(string text) { var edit = this.TalkEdit; if (edit == null) { return(false); } // 500文字あたり1ミリ秒をタイムアウト値に追加 var timeout = UIControlTimeout + (text.Length / 500); try { if (!(await Task.Run(() => edit.SetText(text, timeout)))) { ThreadTrace.WriteLine( @"トークテキスト設定処理がタイムアウトしました。 " + nameof(text) + @".Length=" + text.Length); return(false); } } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false); } return(true); }
/// <summary> /// トークテキスト再生の実処理を行う。 /// </summary> /// <returns>成功したならば true 。そうでなければ false 。</returns> protected override async Task <bool> DoPlay() { if (this.PlayButton == null || !(await this.SetTalkTextCursorToHead())) { return(false); } try { this.PlayButton.PostMessage(BM_CLICK); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false); } // 保存ボタンが無効になるかダイアログが出るまで少し待つ // ダイアログが出ない限りは失敗にしない await RepeatUntil( async() => this.SaveButton?.IsEnabled != true || (await this.UpdateDialogShowing()), f => f, 15); return(!this.IsDialogShowing); }
/// <summary> /// AutomationElement の Invoke 操作を行う。 /// </summary> /// <param name="element">操作対象の AutomationElement 。</param> /// <returns>成功したならば true 。そうでなければ false 。</returns> protected static bool InvokeElement(AutomationElement element) { if (element == null) { throw new ArgumentNullException(nameof(element)); } try { if (!element.Current.IsEnabled) { return(false); } if (!element.TryGetCurrentPattern(InvokePattern.Pattern, out var pattern)) { return(false); } ((InvokePattern)pattern).Invoke(); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false); } return(true); }
/// <summary> /// トークテキストのカーソル位置を先頭に移動させる。 /// </summary> /// <returns>成功したならば true 。そうでなければ false 。</returns> /// <remarks> /// 再生中の場合は停止させる。既にWAVEファイル保存中である場合は失敗する。 /// </remarks> private async Task <bool> SetTalkTextCursorToHead() { var edit = this.TalkEdit; if (edit == null || this.IsSaving || !(await this.Stop())) { return(false); } try { return (await Task.Run( () => edit .SendMessage( EM_SETSEL, timeoutMilliseconds : UIControlTimeout) .HasValue)); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(false); }
protected override void OnReply(Message message, TimeSpan timeout) { TimeoutHelper helper = new TimeoutHelper(timeout); Message message2 = null; message2 = message; try { bool flag = this.PrepareReply(ref message2); ThreadTrace.Trace("Begin sending http reply"); this.httpOutput.Send(helper.RemainingTime()); if (TD.MessageSentByTransportIsEnabled()) { TD.MessageSentByTransport(this.Listener.Uri.AbsoluteUri); } ThreadTrace.Trace("End sending http reply"); if (flag) { this.httpOutput.Close(); } } finally { if ((message != null) && !object.ReferenceEquals(message, message2)) { message2.Close(); } } }
/// <summary> /// AutomationElement の ValuePattern に文字列値を設定する。 /// </summary> /// <param name="element">設定対象の AutomationElement 。</param> /// <param name="value">設定する文字列値。</param> /// <returns>成功したならば true 。そうでなければ false 。</returns> protected static bool SetElementValue(AutomationElement element, string value) { if (element == null) { throw new ArgumentNullException(nameof(element)); } try { if (!element.TryGetCurrentPattern(ValuePattern.Pattern, out var pattern)) { return(false); } var vp = (ValuePattern)pattern; if (vp.Current.IsReadOnly) { ThreadDebug.WriteLine(@"The element is readonly."); return(false); } vp.SetValue(value); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false); } return(true); }
/// <summary> /// 現在のパラメータ一覧を取得する。 /// </summary> /// <param name="targetParameterIds"> /// 取得対象のパラメータID列挙。 null ならば存在する全パラメータを対象とする。 /// </param> /// <returns> /// パラメータIDとその値のディクショナリ。取得できなかった場合は null 。 /// </returns> protected override Result <Dictionary <ParameterId, decimal> > GetParametersImpl( IEnumerable <ParameterId> targetParameterIds) { // パラメータスライダー群を取得 var(sliders, failMessage) = this.ParameterSliders.Get(targetParameterIds); if (sliders == null) { return(null, failMessage); } var dict = new Dictionary <ParameterId, decimal>(); foreach (var idSlider in sliders) { var id = idSlider.Key; try { dict.Add(id, (decimal)(double)idSlider.Value.Value); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(null, MakeParameterValueName(id) + @"を取得できませんでした。"); } } return(dict); }
/// <summary> /// トラックセレクタを取得する。 /// </summary> /// <param name="root"> /// ルートコントロール。 null ならばメソッド内で取得される。 /// </param> /// <returns>コントロール。見つからないならば null 。</returns> public Result <dynamic> Get(dynamic root = null) { // ルートコントロールを取得 var rootCtrl = root; if (rootCtrl == null) { var rv = this.Root.Get(); if (rv.Value == null) { return(null, rv.Message); } rootCtrl = rv.Value; } try { var trackSelector = rootCtrl .Children[1] // Grid .Children[0] // Timetable .Content // Grid .Children[1] // DockPanel .Children[0] // DockPanel .Children[1] // ScrollViewer .Content; return(trackSelector, null); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null, @"本体のトラック群が見つかりませんでした。"); }
/// <summary> /// メインウィンドウを検索する。 /// </summary> /// <returns>メインウィンドウ。見つからなかった場合は null 。</returns> /// <remarks> /// 戻り値が有効である場合、本体側の /// <see cref="Form"/> オブジェクトを参照している。 /// </remarks> protected dynamic FindMainWindow() { var app = this.TargetApp; if (app == null) { return(null); } try { foreach (var form in app.Type <Application>().OpenForms) { if (this.CheckWindowTitleKind((string)form.Text) == WindowTitleKind.Main) { return(form); } } } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null); }
/// <summary> /// 操作パネルを取得する。 /// </summary> /// <param name="controlPanel"> /// コントロールパネル。 null ならばメソッド内で取得される。 /// </param> /// <returns>コントロール。見つからないか取得できない状態ならば null 。</returns> public Result <dynamic> Get(dynamic controlPanel = null) { // コントロールパネルを取得 var ctrlPanel = controlPanel; if (ctrlPanel == null) { var cv = this.ControlPanel.GetTalk(); if (cv.Value == null) { return(null, cv.Message); } ctrlPanel = cv.Value; } try { return (ctrlPanel .Children[2] // VoiceEditor .Content // ScrollViewer .Content); // Grid } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(null, @"本体の操作画面が見つかりません。"); }
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, AsyncCallback callback, object state) { ThreadTrace.Trace("BC:BeginWrite"); TimeoutHelper helper = new TimeoutHelper(timeout); this.Flush(helper.RemainingTime()); return(base.BeginWrite(buffer, offset, size, immediate, helper.RemainingTime(), callback, state)); }
/// <summary> /// 音声保存先ディレクトリを作成し、書き込み権限を確認する。 /// </summary> /// <param name="dirPath">ディレクトリパス。</param> /// <returns>成功したならば true 。そうでなければ false 。</returns> private static Result <bool> CreateSaveDirectory(string dirPath) { if (string.IsNullOrWhiteSpace(dirPath)) { return(false, @"保存先フォルダーパスが不正です。"); } // ディレクトリ作成 if (!Directory.Exists(dirPath)) { try { Directory.CreateDirectory(dirPath); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"保存先フォルダーを作成できませんでした。"); } } // テンポラリファイルパス作成 string tempFilePath = null; try { for (uint i = 0; tempFilePath == null || File.Exists(tempFilePath); ++i) { tempFilePath = Path.Combine(dirPath, i.ToString()); } } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"保存先フォルダーの書き込み権限を確認できませんでした。"); } // 書き込み確認 try { File.WriteAllBytes(tempFilePath, new byte[] { 0 }); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"保存先フォルダーの書き込み権限がありません。"); } finally { try { File.Delete(tempFilePath); } catch { } } return(true); }
/// <summary> /// ファイル名エディットコントロールの入力内容確定処理を行う。 /// </summary> /// <param name="okButton">ファイルダイアログのOKボタン。</param> /// <param name="fileDialogParent">ファイルダイアログの親。</param> /// <returns> /// 成功したならば null 。そうでなければ処理失敗時の追加メッセージ。 /// </returns> private async Task <string> DoDecideFilePathTask( AutomationElement okButton, AutomationElement fileDialogParent) { if (okButton == null || fileDialogParent == null) { return(@"内部パラメータが不正です。"); } // 入力可能状態まで待機 if (!(await this.WhenForInputIdle())) { return(@"入力可能状態になりませんでした。"); } // フォーカス try { okButton.SetFocus(); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(@"OKボタンをフォーカスできませんでした。"); } // OKボタン押下 if (!InvokeElement(okButton)) { return(@"OKボタンをクリックできませんでした。"); } // ファイルダイアログが閉じるまで待つ try { var closed = await RepeatUntil( () => !FindChildWindows( fileDialogParent, SaveFileDialogName) .Any(), f => f, 150); if (!closed) { return(@"ダイアログの終了を確認できませんでした。"); } } catch (Exception ex) { ThreadTrace.WriteException(ex); return(@"内部エラーが発生しました。"); } return(null); }
void FlushCore(TimeSpan timeout) { if (pendingWriteSize > 0) { ThreadTrace.Trace("BC:Flush"); Connection.Write(writeBuffer, 0, pendingWriteSize, false, timeout); pendingWriteSize = 0; } }
/// <summary> /// 既に存在するWAVEファイルの削除処理を行う。 /// </summary> /// <param name="filePath">WAVEファイルパス。</param> /// <param name="withSplitFiles"> /// 分割連番ファイルの削除も行うならば true 。 /// </param> /// <returns>削除したファイル数。失敗したならば -1 。</returns> private async Task <int> DoEraseOldFileTask( string filePath, bool withSplitFiles = true) { if (string.IsNullOrWhiteSpace(filePath)) { return(-1); } int count = 0; // そのままの名前の wav, txt を削除 var txtPath = Path.ChangeExtension(filePath, @".txt"); try { await Task.Run( () => { foreach (var path in new[] { filePath, txtPath }) { if (File.Exists(path)) { File.Delete(path); ++count; } } }); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(-1); } // VOICEROID2ライクソフトウェアのファイル分割機能による連番ファイルを削除 if (withSplitFiles) { for (int i = 0; ; ++i) { var splitPath = Path.Combine( Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + @"-" + i + Path.GetExtension(filePath)); var c = await this.DoEraseOldFileTask(splitPath, false); if (c <= 0) { break; } count += c; } } return(count); }
/// <summary> /// キャラクターを選択させる。 /// </summary> /// <param name="character"> /// キャラクター。 /// <see cref="ProcessTalkerBase{TParameterId}"/> 実装から null が渡されることはない。 /// 有効でないキャラクターは渡されうる。 /// </param> /// <returns>成功したならば true 。そうでなければ false 。</returns> protected override Result <bool> SetCharacterImpl(string character) { // セリフデータグリッドを取得 var(grid, gridMessage) = this.SpeechDataGrid.Get(); if (grid == null) { return(false, gridMessage); } try { // 選択行のキャストセルコンボボックス取得 var combo = grid.GetCellContent(grid.SelectedRow, 0); // 既に対象キャスト選択中なら何もせず終える // CastSpeechInputRow 設定が Blank の場合は SetTextImpl で帳尻合わせされる if ((string)combo.Text == character) { return(true); } // キャスト名キャッシュを取得or作成 var(cache, cacheMessage) = this.GetOrCreateCastNamesCache((DynamicAppVar)combo); if (cache == null) { return(false, cacheMessage); } // キャスト検索 var castIndex = cache.IndexOf(character); if (castIndex < 0) { return(false, $@"本体に {character} が登録されていません。"); } // 適切な行を選択 var(ok, failMessage) = this.SelectSpeechDataGridRowForInput(grid); if (!ok) { return(false, failMessage); } // 改めて選択行のキャストセルコンボボックス取得 combo = grid.GetCellContent(grid.SelectedRow, 0); // キャスト選択 combo.SelectedIndex = castIndex; } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false, @"キャストの選択に失敗しました。"); } return(true); }
private void FlushCore(TimeSpan timeout) { if (this.pendingWriteSize > 0) { ThreadTrace.Trace("BC:Flush"); base.Connection.Write(this.writeBuffer, 0, this.pendingWriteSize, false, timeout); this.pendingWriteSize = 0; } }
/// <summary> /// ボイスプリセット一覧リストビューとそのアイテム群の親コントロールを取得する。 /// </summary> /// <param name="presetTabControl">ボイスプリセット一覧タブコントロール。</param> /// <param name="tabItemIndex">タブアイテムインデックス。</param> /// <returns> /// リストビューとそのアイテム群の親コントロール。 /// 取得できなかった場合は (null, null) 。 /// </returns> /// <remarks> /// ビジュアルツリーを走査するため、必要に応じて選択タブアイテムを変更する。 /// </remarks> private Result <(dynamic listView, dynamic itemsParent)> GetPresetListView( dynamic presetTabControl, int tabItemIndex) { // 失敗時の戻り値を作成するローカルメソッド Result <(dynamic listView, dynamic itemsParent)> makeFailResult(string message) => new Result <(dynamic listView, dynamic itemsParent)>((null, null), message); // ビジュアルツリー走査用オブジェクトを取得 var vtree = this.TargetAppVisualTree; if (vtree == null) { return(makeFailResult(@"本体の情報を取得できません。")); } // 対象タブアイテムを選択 try { if ( presetTabControl == null || tabItemIndex < 0 || tabItemIndex >= (int)presetTabControl.Items.Count) { return (makeFailResult( @"本体のボイスプリセットタブページが見つかりません。")); } presetTabControl.SelectedIndex = tabItemIndex; } catch (Exception ex) { ThreadTrace.WriteException(ex); return (makeFailResult( @"本体のボイスプリセットタブページを操作できませんでした。")); } try { var listView = presetTabControl.Items[tabItemIndex].Content.Content.Children[0]; var chrome = vtree.GetDescendant(listView, 0); var presenter = chrome.Child.Content; var itemsParent = vtree.GetDescendant(presenter, 0); return (new Result <(dynamic listView, dynamic itemsParent)>( (listView, itemsParent))); } catch (Exception ex) { ThreadTrace.WriteException(ex); } return(makeFailResult(@"本体のボイスプリセット一覧が見つかりません。")); }
/// <summary> /// WAVEファイルパスをファイル名エディットへ設定する処理を行う。 /// </summary> /// <param name="fileNameEdit">ファイル名エディット。</param> /// <param name="filePath">WAVEファイルパス。</param> /// <returns>成功したならば true 。そうでなければ false 。</returns> private async Task <bool> DoSetFilePathToEditTask( AutomationElement fileNameEdit, string filePath) { if (fileNameEdit == null || string.IsNullOrWhiteSpace(filePath)) { return(false); } // 入力可能状態まで待機 if (!(await this.WhenForInputIdle())) { ThreadTrace.WriteLine(@"入力可能状態になりません。"); return(false); } // フォーカス try { fileNameEdit.SetFocus(); } catch (Exception ex) { ThreadTrace.WriteException(ex); return(false); } // VOICEROID2ライクソフトウェアでは、 // Windowsのフォルダーオプションで拡張子を表示しない設定にしていると、 // ValuePattern.SetValue によるファイルパス設定が無視され、 // 元々入力されている前回保存時の名前が参照されてしまう。 // 一旦キー入力を行うことで回避できるようなので、適当な文字を送ってみる。 // 適当な文字をファイル名エディットへ送信 // 失敗しても先へ進む try { var editWin = new Win32Window(new IntPtr(fileNameEdit.Current.NativeWindowHandle)); editWin.SendMessage( WM_CHAR, new IntPtr('x'), IntPtr.Zero, UIControlTimeout); } catch { } // ファイルパス設定 if (!SetElementValue(fileNameEdit, filePath)) { ThreadTrace.WriteLine(@"ファイルパスを設定できません。"); return(false); } return(true); }