using System.IO; using System.Text.RegularExpressions; using System.Diagnostics; using DBObj; using OverlayFormObj; using NAudio.Wave; namespace DualScreenDemo { public class CommandHandler { public static bool readyForSongListInput = false; /* 關機 queue */ private readonly int _maxHistoryLength = 6; // 最多保留 6 筆 public static readonly Queue _indataHistory = new Queue(); /* 顯示按鈕設定 */ private readonly SQLManager songListManager; public CommandHandler(SQLManager songListManager) { this.songListManager = songListManager; } /// /// 遙控器接收資料 /// public Task ProcessData(string indata) { AddToHistory(indata); // 遙控器測試 // Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 遙控器: {indata}"); switch (indata) { case "A261A4": // 輸入 // HandleInput("a"); HandleRoomState("A261A4"); break; case "A262A4": // 插播 // HandleInput("b"); HandleRoomState("A262A4"); break; case "A263A4": ClearDisplay(); _indataHistory.Clear(); // 清空歷史紀錄 break; case "A268A4": OverlayForm.MainForm.currentPage = 1; DisplaySongHistory(); break; case "A26AA4": PreviousPage(); break; case "A26BA4": NextPage(); break; case "A271A4": // HandleNewSongAnnouncements(); HandleRoomState("A271A4"); break; case "A273A4": // HandleHotSongAnnouncements(); HandleRoomState("A273A4"); break; case "A267A4": // SkipToNextSong(); // ClearDisplay(); HandleRoomState("A267A4"); break; case "A269A4": // ReplayCurrentSong(); HandleRoomState("A269A4"); break; // 原唱 case "A26CA4": Console.WriteLine("ToggleVocalRemoval Invoked"); SafeInvokeAction("A26CA4",() => VideoPlayerForm.Instance.ToggleVocalRemoval()); break; // 導唱 case "A26EA4": SafeInvokeAction("A26EA4",() => VideoPlayerForm.Instance.ToggleVocalRemoval()); break; case "A26DA4": PauseOrResumeSong(); break; case "A276A4": ToggleMute(); break; case "A274A4": // OverlayForm.MainForm.currentPage = 1; // HandleArtistAnnouncements(); HandleRoomState("A274A4"); break; case "A2B3A4": SafeInvokeAction("A2B3A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↑ ")); break; case "A2B4A4": SafeInvokeAction("A2B4A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("音量 ↓ ")); break; case "A2B5A4": SafeInvokeAction("A2B5A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↑ ")); break; case "A2B6A4": SafeInvokeAction("A2B6A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("麥克風 ↓ ")); break; case "A2C2A4": SafeInvokeAction("A2C2A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("標準迴音")); break; case "A2C3A4": SafeInvokeAction("A2C3A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("專業迴音")); break; case "A2C4A4": SafeInvokeAction("A2C4A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("廣場迴音")); break; case "A2C1A4": SafeInvokeAction("A2C1A4",() => OverlayForm.MainForm.ShowTopRightEchoLabel("唱將迴音")); break; case "A2D5A4": SafeInvokeAction("A2D5A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 明亮 ")); break; case "A2D7A4": SafeInvokeAction("A2D7A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 浪漫 ")); break; case "A2D6A4": SafeInvokeAction("A2D6A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 柔和 ")); break; case "A2D8A4": SafeInvokeAction("A2D8A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 動感 ")); break; case "A275A4": SafeInvokeAction("A275A4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 調色 ")); break; case "A283A4": SafeInvokeAction("A283A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升4調 ")); break; case "A282A4": SafeInvokeAction("A282A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升3調 ")); break; case "A281A4": SafeInvokeAction("A281A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升2調 ")); break; case "A280A4": SafeInvokeAction("A280A4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↑升1調 ")); break; case "A27FA4": SafeInvokeAction("A27FA4",() => OverlayForm.MainForm.ShowTopRightLabelTime(" 標準調 ")); break; case "A27EA4": SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降1調 ")); break; case "A27DA4": SafeInvokeAction("A27EA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降2調 ")); break; case "A27CA4": SafeInvokeAction("A27CA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降3調 ")); break; case "A27BA4": SafeInvokeAction("A27BA4",() => OverlayForm.MainForm.ShowTopRightLabelTime("↓降4調 ")); break; case "A266A4": SafeInvokeAction("A266A4",() => OverlayForm.MainForm.ShowTopRightLabel("服務鈴")); break; default: if (Regex.IsMatch(indata, @"^A23\d+A4$")) { HandleNumberInput(indata); } break; } return Task.CompletedTask; } private void HandleRoomState(string action) { if (Program.room.IsOpen()==false) { switch (action) { case "A261A4": // 輸入 HandleInput("a"); break; case "A262A4": // 插播 HandleInput("b"); break; case "A271A4": HandleNewSongAnnouncements(); break; case "A273A4": HandleHotSongAnnouncements(); break; case "A267A4": SkipToNextSong(); ClearDisplay(); break; case "A269A4": ReplayCurrentSong(); break; case "A274A4": OverlayForm.MainForm.currentPage = 1; HandleArtistAnnouncements(); break; default: break; } } } private void SafeInvokeAction(string commandKey, Action action) { // 真正執行 UI 操作 if (OverlayForm.MainForm.InvokeRequired) { OverlayForm.MainForm.BeginInvoke(action); } else { action(); } } private void AddToHistory(string indata) { if (_indataHistory.Count >= _maxHistoryLength) { _indataHistory.Dequeue(); // 移除最舊的項目 } _indataHistory.Enqueue(indata); // 添加新的項目 CheckSequenceforClose(); // 每次更新完 queue 後檢查 } private void CheckSequenceforClose() { string[] targetSequence = { "A262A4", "A262A4", "A262A4", "A261A4", "A261A4", "A261A4" }; if (_indataHistory.Count == targetSequence.Length && _indataHistory.SequenceEqual(targetSequence)) { Console.WriteLine("Shutdown condition met. Application will now close."); ShutdownComputer(); } } static void InvokeAction(Action action) { if (OverlayForm.MainForm.InvokeRequired) { OverlayForm.MainForm.Invoke(action); } else { action(); } } private void SkipToNextSong() { InvokeAction(() => PrimaryForm.Instance.videoPlayerForm.PlayNextSong()); InvokeAction(() => OverlayForm.MainForm.ShowTopRightEchoLabel("標準迴音")); } private void ReplayCurrentSong() { InvokeAction(() => PrimaryForm.Instance.videoPlayerForm.ReplayCurrentSong()); } private static void PauseOrResumeSong() { InvokeAction(() => PrimaryForm.Instance.videoPlayerForm.PauseOrResumeSong()); } public static void ToggleMute() { if (VideoPlayerForm.Instance.InvokeRequired) { VideoPlayerForm.Instance.Invoke(new System.Action(ToggleMute)); } else { if (VideoPlayerForm.Instance.isMuted) { VideoPlayerForm.Instance.Mute(false); VideoPlayerForm.Instance.isMuted = false; OverlayForm.MainForm.Invoke(new System.Action(() => OverlayForm.MainForm.HideMuteLabel())); } else { VideoPlayerForm.Instance.Mute(true); VideoPlayerForm.Instance.isMuted = true; OverlayForm.MainForm.Invoke(new System.Action(() => OverlayForm.MainForm.ShowMuteLabel())); } } } private void HandleInput(string input) { if (readyForSongListInput) { InvokeAction(() => { Console.WriteLine("F sign for input :" + input); OverlayForm.MainForm.OnUserInput(input); }); } else { InvokeAction(() => { OverlayForm.displayTimer.Stop(); string songNumber = OverlayForm.ReadSongNumber(); var song = songListManager.SearchSongByNumber(songNumber); ClearDisplay(); if (song != null) { song.getBasic().setNameTest("."); if (Program.room.IsOpen()) { if (input.Equals("a")) { OverlayForm.MainForm.displayLabel.Text = String.Format("已點歌曲:{0}", song); SongList.Add(song); } else { OverlayForm.MainForm.displayLabel.Text = String.Format("插播歌曲:{0}", song); SongList.Insert(song); } } else { OverlayForm.MainForm.displayLabel.Text = "包廂己關閉"; } _indataHistory.Clear(); // 清空歷史紀錄 } else OverlayForm.MainForm.displayLabel.Text = check_control(); OverlayForm.MainForm.topLeftLabel.Visible = false; OverlayForm.displayTimer.Start(); }); } } private string check_control(){ string str = ""; foreach (string item in _indataHistory) { if (item == "A261A4") str += "#"; else if (item == "A262A4") str += "*"; } return str; } /// /// 清除 OverlayForm 上除特定保留控制項外的所有控制項,並重設顯示狀態 /// private static void ClearDisplay() { // 停止顯示用的計時器 OverlayForm.displayTimer.Stop(); // 判斷是否需要透過 Invoke 回 UI 執行緒執行 InvokeAction(() => ClearControlsAndReset()); } /// /// 實際執行移除不需要的控制項並重設 UI 狀態 /// private static void ClearControlsAndReset() { // 保留不刪除的控制項列表 var preservedControls = new HashSet { OverlayForm.MainForm.displayLabel, OverlayForm.MainForm.pauseLabel, OverlayForm.MainForm.muteLabel, OverlayForm.MainForm.topRightLabel, OverlayForm.MainForm.blackBackgroundPanel, OverlayForm.MainForm.topLeftLabel }; // 將所有不在保留清單內的控制項移除並釋放資源 foreach (var control in OverlayForm.MainForm.Controls.OfType().ToArray()) { if (!preservedControls.Contains(control)) { OverlayForm.MainForm.Controls.Remove(control); control.Dispose(); } } // 清空主顯示區的文字 OverlayForm.MainForm.displayLabel.Text = ""; Console.WriteLine("ClearDisplay called."); // 重設狀態標記與 UI 狀態 // 嘗試 true readyForSongListInput = true; OverlayForm.SetUIState(OverlayForm.UIState.Initial); Console.WriteLine("Display cleared."); } private static void DisplaySongHistory() { // 清除畫面上現有的顯示內容 ClearDisplay(); // 設定歌曲總數為已播放歌曲的數量 List history= SongList.GetHistory(); List historySongs = new List(); OverlayForm.MainForm.totalSongs = SongList.GetHistory().Count; // 若無任何播放紀錄,直接顯示訊息並返回,不執行後續動作 if (OverlayForm.MainForm.totalSongs == 0) { Console.WriteLine("No song history available."); return; } // 計算總頁數,每頁顯示 songsPerPage 首歌,使用天花板函數確保不足一頁也算一頁 int totalPages = (int)Math.Ceiling(OverlayForm.MainForm.totalSongs / (double)OverlayForm.MainForm.songsPerPage); // 計算當前頁面要顯示的歌的起始與結束索引 int startIndex = (OverlayForm.MainForm.currentPage - 1) * OverlayForm.MainForm.songsPerPage; int endIndex = Math.Min(startIndex + OverlayForm.MainForm.songsPerPage, OverlayForm.MainForm.totalSongs); // 準備要傳給 UpdateHistoryLabel 的兩個清單:歌曲資料與播放狀態 for (int i = startIndex; i < endIndex; i++) { historySongs.Add(history[i]); } // 錨點 遙控器 // 安全更新 UI:若非 UI 執行緒則使用 Invoke 切換 InvokeAction(() => { // 更新主畫面的歷史播放顯示區 OverlayForm.MainForm.UpdateHistoryLabel(historySongs, OverlayForm.MainForm.currentPage, totalPages); // 隱藏下一首提示 OverlayForm.MainForm.topLeftLabel.Visible = false; }); // 切換 UI 狀態為播放歷史模式(可做為內部狀態管理用途) OverlayForm.SetUIState(OverlayForm.UIState.PlayHistory); } private static void PreviousPage() { if (OverlayForm.CurrentUIState == OverlayForm.UIState.SelectingSong) { InvokeAction(() =>OverlayForm.MainForm.PreviousPage()); } else if (OverlayForm.CurrentUIState == OverlayForm.UIState.SelectingArtist) { InvokeAction(() =>OverlayForm.MainForm.PreviousPage()); } else if (OverlayForm.CurrentUIState == OverlayForm.UIState.PlayHistory) { if (OverlayForm.MainForm.currentPage > 1) { OverlayForm.MainForm.currentPage--; InvokeAction(() => DisplaySongHistory()); } } else { Console.WriteLine("Page turning is not allowed in the current state."); } } private static void NextPage() { if (OverlayForm.CurrentUIState == OverlayForm.UIState.SelectingSong) { InvokeAction(() => OverlayForm.MainForm.NextPage()); } else if (OverlayForm.CurrentUIState == OverlayForm.UIState.SelectingArtist) { InvokeAction(() => OverlayForm.MainForm.NextPage() ); } else if (OverlayForm.CurrentUIState == OverlayForm.UIState.PlayHistory) { if (OverlayForm.MainForm.currentPage * OverlayForm.MainForm.songsPerPage < OverlayForm.MainForm.totalSongs) { OverlayForm.MainForm.currentPage++; if (OverlayForm.CurrentUIState == OverlayForm.UIState.PlayHistory) { InvokeAction(() => DisplaySongHistory() ); } } } else { Console.WriteLine("Page turning is not allowed in the current state."); } } private static void HandleNewSongAnnouncements() { ClearDisplay(); OverlayForm.CurrentCategory = OverlayForm.Category.NewSongs; string[] messages = new string[] { "新歌快訊", "1. 國語", "2. 台語", "3. 粵語", "4. 英語", "5. 日語", "6. 韓語", }; readyForSongListInput = true; OverlayForm.SetUIState(OverlayForm.UIState.SelectingLanguage); UpdateDisplayLabels(messages); } private static void HandleHotSongAnnouncements() { ClearDisplay(); OverlayForm.CurrentCategory = OverlayForm.Category.HotSongs; string[] messages = new string[] { "熱門排行", "1. 國語", "2. 台語", "3. 粵語", "4. 英語", "5. 日語", "6. 韓語", }; readyForSongListInput = true; OverlayForm.SetUIState(OverlayForm.UIState.SelectingLanguage); UpdateDisplayLabels(messages); } private static void HandleArtistAnnouncements() { ClearDisplay(); OverlayForm.CurrentCategory = OverlayForm.Category.Artists; string[] messages = new string[] { "歌星選歌", "1.男歌星", "2.女歌星", "3.團體", "4.外語", "5.全部", }; readyForSongListInput = true; OverlayForm.SetUIState(OverlayForm.UIState.SelectingArtistCategory); UpdateDisplayLabels(messages); } private static void UpdateDisplayLabels(string[] messages) { InvokeAction(() => { foreach (var control in OverlayForm.MainForm.Controls.OfType().ToArray()) { if (control != OverlayForm.MainForm.displayLabel && control != OverlayForm.MainForm.pauseLabel && control != OverlayForm.MainForm.muteLabel && control != OverlayForm.MainForm.topRightLabel && control != OverlayForm.MainForm.blackBackgroundPanel && control != OverlayForm.MainForm.topLeftLabel) { OverlayForm.MainForm.Controls.Remove(control); control.Dispose(); } } OverlayForm.MainForm.UpdateDisplayLabels(messages); }); } private static void HandleNumberInput(string trimmedData) { string number = trimmedData; var match = Regex.Match(trimmedData, @"^A23(\d)A4$"); if (match.Success) { number = match.Groups[1].Value; Console.WriteLine($"Handling number: {number}"); } if (readyForSongListInput) { InvokeAction(() => { Console.WriteLine("D sign for number :" + number); OverlayForm.MainForm.OnUserInput(number); }); } else { InvokeAction(() => { OverlayForm.MainForm.HideTopRightLabels(); OverlayForm.DisplayNumberAtTopLeft(number); }); } } public static void ShutdownComputer() { try { ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe", "/c shutdown /s /f /t 0") { CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true }; Process process = Process.Start(processStartInfo); process.WaitForExit(); Console.WriteLine("Computer is shutting down..."); } catch (Exception ex) { Console.WriteLine("Error shutting down computer: " + ex.Message); } } } }