");
sb.AppendLine($"
{label} 쨌 {msg.Timestamp:HH:mm}
");
sb.AppendLine($"
{System.Net.WebUtility.HtmlEncode(msg.Content)}
");
sb.AppendLine("
");
}
sb.AppendLine("");
return sb.ToString();
}
// ??? 踰꾪듉 ?대깽????????????????????????????????????????????????????????
private void ChatWindow_KeyDown(object sender, KeyEventArgs e)
{
var mod = Keyboard.Modifiers;
// Ctrl ?⑥텞?? if (mod == ModifierKeys.Control)
{
switch (e.Key)
{
case Key.N: BtnNewChat_Click(this, new RoutedEventArgs()); e.Handled = true; break;
case Key.W: Close(); e.Handled = true; break;
case Key.E: ExportConversation(); e.Handled = true; break;
case Key.L: InputBox.Text = ""; InputBox.Focus(); e.Handled = true; break;
case Key.B: BtnToggleSidebar_Click(this, new RoutedEventArgs()); e.Handled = true; break;
case Key.M: BtnModelSelector_Click(this, new RoutedEventArgs()); e.Handled = true; break;
case Key.OemComma: BtnSettings_Click(this, new RoutedEventArgs()); e.Handled = true; break;
case Key.F: ToggleMessageSearch(); e.Handled = true; break;
case Key.D1: TabChat.IsChecked = true; e.Handled = true; break;
case Key.D2: TabCowork.IsChecked = true; e.Handled = true; break;
case Key.D3: if (TabCode.IsEnabled) TabCode.IsChecked = true; e.Handled = true; break;
}
}
// Ctrl+Shift ?⑥텞?? if (mod == (ModifierKeys.Control | ModifierKeys.Shift))
{
switch (e.Key)
{
case Key.C:
// 留덉?留?AI ?묐떟 蹂듭궗
ChatConversation? conv;
lock (_convLock) conv = _currentConversation;
if (conv != null)
{
var lastAi = conv.Messages.LastOrDefault(m => m.Role == "assistant");
if (lastAi != null)
try { Clipboard.SetText(lastAi.Content); } catch { }
}
e.Handled = true;
break;
case Key.R:
// 留덉?留??묐떟 ?ъ깮?? _ = RegenerateLastAsync();
e.Handled = true;
break;
case Key.D:
// 紐⑤뱺 ?????젣
BtnDeleteAll_Click(this, new RoutedEventArgs());
e.Handled = true;
break;
case Key.P:
// 而ㅻ㎤???붾젅?? OpenCommandPalette();
e.Handled = true;
break;
}
}
// Escape: 寃??諛??リ린 ?먮뒗 ?ㅽ듃由щ컢 以묒?
if (e.Key == Key.Escape)
{
if (MessageSearchBar.Visibility == Visibility.Visible) { CloseMessageSearch(); e.Handled = true; }
else if (_isStreaming) { StopGeneration(); e.Handled = true; }
}
// ?щ옒??紐낅졊 ?앹뾽 ??泥섎━
if (SlashPopup.IsOpen)
{
if (e.Key == Key.Escape)
{
SlashPopup.IsOpen = false;
_slashSelectedIndex = -1;
e.Handled = true;
}
else if (e.Key == Key.Up)
{
SlashPopup_ScrollByDelta(120); // ?꾨줈 1移? e.Handled = true;
}
else if (e.Key == Key.Down)
{
SlashPopup_ScrollByDelta(-120); // ?꾨옒濡?1移? e.Handled = true;
}
else if (e.Key == Key.Enter && _slashSelectedIndex >= 0)
{
e.Handled = true;
ExecuteSlashSelectedItem();
}
}
}
private void BtnStop_Click(object sender, RoutedEventArgs e) => StopGeneration();
private void BtnPause_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (_agentLoop.IsPaused)
{
_agentLoop.Resume();
PauseIcon.Text = "\uE769"; // ?쇱떆?뺤? ?꾩씠肄? BtnPause.ToolTip = "?쇱떆?뺤?";
}
else
{
_ = _agentLoop.PauseAsync();
PauseIcon.Text = "\uE768"; // ?ъ깮 ?꾩씠肄? BtnPause.ToolTip = "?ш컻";
}
}
private void BtnExport_Click(object sender, RoutedEventArgs e) => ExportConversation();
// ??? 硫붿떆吏 ??寃??(Ctrl+F) ?????????????????????????????????????????
private List