Пример #1
0
        /// <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, @"パラメータの取得に失敗しました。");
        }
Пример #2
0
        /// <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, @"本体の文章入力欄から文章を取得できませんでした。");
        }
Пример #3
0
        /// <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, @"本体のトラック群が見つかりませんでした。");
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
            /// <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>
            /// <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);
            }
Пример #10
0
        /// <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>成功したならば 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);
            }
Пример #12
0
        /// <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);
        }
Пример #13
0
            /// <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);
            }
Пример #14
0
            /// <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>
        /// 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));
        }
Пример #16
0
        /// <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, @"本体の操作画面が見つかりません。");
        }
Пример #17
0
        /// <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, @"本体の試聴/停止ボタンが見つかりません。");
        }
Пример #18
0
        /// <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);
        }
Пример #19
0
        /// <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);
        }
Пример #20
0
        /// <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);
        }
Пример #21
0
            /// <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);
            }
Пример #22
0
        /// <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);
        }
Пример #23
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="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>
            /// 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);
            }
Пример #26
0
        /// <summary>
        /// コントロールパネルを取得する。
        /// </summary>
        /// <param name="kind">コントロールパネル種別の設定先。</param>
        /// <param name="root">
        /// ルートコントロール。 null ならばメソッド内で取得される。
        /// </param>
        /// <param name="appVisualTree">
        /// ビジュアルツリー走査用オブジェクト。 null ならばメソッド内で取得される。
        /// </param>
        /// <returns>コントロール。見つからないならば null 。</returns>
        public Result <dynamic> GetAny(
            out ControlPanelKind kind,
            dynamic root = null,
            WpfVisualTree appVisualTree = null)
        {
            kind = ControlPanelKind.None;

            // ルートコントロールを取得
            var rootCtrl = root;

            if (rootCtrl == null)
            {
                var rv = this.Root.Get();
                if (rv.Value == null)
                {
                    return(null, rv.Message);
                }
                rootCtrl = rv.Value;
            }

            // ビジュアルツリー走査用オブジェクトを取得
            var vtree = appVisualTree ?? this.AppVisualTreeGetter();

            if (vtree == null)
            {
                return(null, @"本体の情報を取得できません。");
            }

            try
            {
                var editor = vtree.GetDescendant(rootCtrl.Children[3], 0, 0);
                try
                {
                    var panel = editor.Content;

                    kind =
                        ((int)panel.Children.Count < 4) ?
                        ControlPanelKind.None : ControlPanelKind.Talk;
                    return(panel, null);
                }
                catch
                {
                    // ソング用は階層構造が異なる
                    kind = ControlPanelKind.Song;
                    return(editor.Child.Content, null);
                }
            }
            catch (Exception ex)
            {
                ThreadTrace.WriteException(ex);
            }

            kind = ControlPanelKind.None;
            return(null, @"本体の操作画面が見つかりませんでした。");
        }
Пример #27
0
        /// <summary>
        /// WAV書き出しメニューをクリックし、音声ファイル保存ダイアログを取得する。
        /// </summary>
        /// <param name="mainWindow">メインウィンドウ。</param>
        /// <param name="speechDataGrid">セリフデータグリッド。</param>
        /// <param name="saveMenuAsync">
        /// WAV書き出しメニュークリック処理用の非同期オブジェクト。
        /// </param>
        /// <returns>音声ファイル保存ダイアログ。表示されなかった場合は null 。</returns>
        private Result <WindowControl> SaveFileImpl_ClickSaveMenu(
            dynamic mainWindow,
            WpfDataGrid speechDataGrid,
            Async saveMenuAsync)
        {
            Debug.Assert((DynamicAppVar)mainWindow != null);
            Debug.Assert(speechDataGrid != null);
            Debug.Assert(saveMenuAsync != null);

            WindowControl fileDialog = null;

            try
            {
                // WAVE書き出しメニューアイテムを取得
                var menuItem = speechDataGrid.Base.ContextMenu.Items[12];

                if (!(bool)menuItem.IsEnabled)
                {
                    return(null, @"本体のWAV書き出しメニューがクリックできない状態です。");
                }

                // WAVE書き出しメニュークリック
                PerformClick(menuItem, saveMenuAsync);

                // ファイルダイアログを待つ
                fileDialog = new WindowControl(mainWindow).WaitForNextModal(saveMenuAsync);
                if (fileDialog == null)
                {
                    return(null, @"本体の音声保存ダイアログが見つかりません。");
                }

                // ダイアログタイトルを確認
                switch (fileDialog.GetWindowText())
                {
                case SaveFileDialogTitle:
                    // OK
                    break;

                case SaveSomeFilesDialogTitle:
                    // 連続書き出しダイアログになってしまっている
                    return(null, @"本体側で連続WAV書き出しダイアログが表示されました。");

                default:
                    return(null, @"本体側でダイアログが表示されました。");
                }
            }
            catch (Exception ex)
            {
                ThreadTrace.WriteException(ex);
                return(null, @"本体のWAV書き出しメニューをクリックできませんでした。");
            }

            return(fileDialog);
        }
Пример #28
0
 /// <summary>
 /// リソースを破棄する。
 /// </summary>
 public virtual void Dispose()
 {
     try
     {
         this.CompositeDisposable.Dispose();
     }
     catch (Exception ex)
     {
         ThreadTrace.WriteException(ex);
     }
 }
Пример #29
0
        /// <summary>
        /// セリフデータグリッドを取得する。
        /// </summary>
        /// <param name="controlPanel">
        /// コントロールパネル。 null ならばメソッド内で取得される。
        /// </param>
        /// <param name="appVisualTree">
        /// ビジュアルツリー走査用オブジェクト。 null ならばメソッド内で取得される。
        /// </param>
        /// <returns>コントロール。見つからないか取得できない状態ならば null 。</returns>
        public Result <WpfDataGrid> Get(
            dynamic controlPanel        = null,
            WpfVisualTree appVisualTree = null)
        {
            // コントロールパネルを取得
            var ctrlPanel = controlPanel;

            if (ctrlPanel == null)
            {
                var cv = this.ControlPanel.GetTalk();
                if (cv.Value == null)
                {
                    return(null, cv.Message);
                }
                ctrlPanel = cv.Value;
            }

            // ビジュアルツリー走査用オブジェクトを取得
            var vtree = appVisualTree ?? this.AppVisualTreeGetter();

            if (vtree == null)
            {
                return(null, @"本体の情報を取得できません。");
            }

            try
            {
                var dataGrid =
                    new WpfDataGrid(ctrlPanel.Children[0].Content.Children[0], vtree);

                // コンテキストメニューを初期化して取得
                var menu = InitializeContextMenu(dataGrid);
                if (menu == null)
                {
                    return(null, @"本体のセリフ一覧表を初期化できません。");
                }

                // キャスト列を表示させる
                var castItem = FindCastMenuItem(menu);
                if (castItem == null)
                {
                    return(null, @"本体のセリフ一覧表を初期化できません。");
                }
                castItem.IsChecked = true;

                return(dataGrid);
            }
            catch (Exception ex)
            {
                ThreadTrace.WriteException(ex);
            }
            return(null, @"本体のセリフ一覧表が見つかりません。");
        }
Пример #30
0
        /// <summary>
        /// 現在の文章の読み上げを開始させる。
        /// </summary>
        /// <returns>成功したならば true 。そうでなければ false 。</returns>
        /// <remarks>
        /// 読み上げ開始の成否を確認するまでブロッキングする。読み上げ完了は待たない。
        /// 既に読み上げ中の場合は一旦停止して再度開始させる。
        /// </remarks>
        public Result <bool> Speak()
        {
            // SaveFile 処理中のデッドロック回避
            if (this.IsPropertyChangedOnSaveFile)
            {
                return(MakeStateErrorResult(false));
            }

            Result <bool> result;
            Action        raisePropChanged = null;

            try
            {
                lock (this.LockObject)
                {
                    if (!this.CanOperate)
                    {
                        return(MakeStateErrorResult(false));
                    }

                    // 読み上げ中ならまず停止させる
                    if (this.State == TalkerState.Speaking)
                    {
                        var r = this.StopImpl();
                        if (!r.Value)
                        {
                            return(r);
                        }
                    }

                    result = this.SpeakImpl();

                    // 状態更新
                    raisePropChanged = this.UpdateByCurrentTargetProcess();
                }
            }
            finally
            {
                try
                {
                    raisePropChanged?.Invoke();
                }
                catch (Exception ex)
                {
                    ThreadTrace.WriteException(ex);
                    result = (
                        false,
                        ex.Message ?? (ex.GetType().Name + @" 例外が発生しました。"));
                }
            }

            return(result);
        }