기능 추가 Ctrl +Shift + P

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019WT2pzDE45iP4QMAAo7cyz
main
Claude 2026-10-21 06:41:15 +00:00
parent 9962c4e7dd
commit e7f39a7bc1
No known key found for this signature in database
1 changed files with 167 additions and 70 deletions

View File

@ -247,6 +247,64 @@ namespace WindowsKeyInfo
}
}
/// <summary>제한 화면에서 Ctrl+Shift+P로 여는 마스터 암호 입력 창 (틀리면 알림 후 다시 입력)</summary>
internal sealed class MasterPasswordDialog : Form
{
private readonly TextBox _box;
public MasterPasswordDialog()
{
Text = "Windows Key";
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterParent;
AutoScaleMode = AutoScaleMode.Dpi;
Font = new Font("맑은 고딕", 9.5f);
ClientSize = new Size(360, 130);
var lbl = new Label
{
Text = "마스터 암호를 입력하세요.",
Location = new Point(14, 14),
Size = new Size(332, 22)
};
_box = new TextBox
{
Location = new Point(14, 42),
Size = new Size(332, 28),
UseSystemPasswordChar = true
};
var btnOk = new Button { Text = "확인", Location = new Point(126, 84), Size = new Size(108, 32) };
btnOk.Click += (s, e) => TryAccept();
var btnCancel = new Button { Text = "취소", Location = new Point(240, 84), Size = new Size(106, 32), DialogResult = DialogResult.Cancel };
Controls.Add(lbl);
Controls.Add(_box);
Controls.Add(btnOk);
Controls.Add(btnCancel);
AcceptButton = btnOk;
CancelButton = btnCancel;
ActiveControl = _box;
}
private void TryAccept()
{
if (PasswordStore.Verify(_box.Text))
{
DialogResult = DialogResult.OK;
Close();
return;
}
MessageBox.Show(this, "암호가 틀렸습니다.", Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
_box.Clear();
_box.Focus();
}
}
/// <summary>암호 변경 창 (새 암호 한 번 입력)</summary>
internal sealed class ChangePasswordDialog : Form
{
@ -409,15 +467,24 @@ namespace WindowsKeyInfo
}
}
/// <summary>메인 창 (WinForms). fullMode=false면 키 정보 4줄 + 복사/파일로 저장/닫기만 표시</summary>
/// <summary>메인 창 (WinForms). 제한 모드면 키 정보 4줄 + 복사/파일로 저장/닫기만 표시,
/// 제한 모드에서 Ctrl+Shift+P → 마스터 암호 입력 → 맞으면 그 자리에서 전체 화면으로 전환</summary>
internal sealed class MainForm : Form
{
private const Keys UnlockShortcut = Keys.Control | Keys.Shift | Keys.P;
private readonly KeyReader.KeyInfo _info;
private readonly TextBox _txtProductName;
private readonly TextBox _txtProductId;
private readonly TextBox _txtInstalledKey;
private readonly TextBox _txtBackupKey;
// 전체 모드에서만 보이는 컨트롤
private readonly Button _btnChangePw;
private readonly FlowLayoutPanel _phone;
private readonly FlowLayoutPanel _links;
private bool _fullMode;
public MainForm(bool fullMode)
{
Text = "Windows 제품 키 백업";
@ -426,7 +493,7 @@ namespace WindowsKeyInfo
StartPosition = FormStartPosition.CenterScreen;
AutoScaleMode = AutoScaleMode.Dpi;
Font = new Font("맑은 고딕", 9.5f);
ClientSize = fullMode ? new Size(560, 344) : new Size(560, 240);
ClientSize = new Size(560, 344);
var table = new TableLayoutPanel
{
@ -465,77 +532,69 @@ namespace WindowsKeyInfo
buttons.Controls.Add(btnSave);
buttons.Controls.Add(btnCopy);
if (fullMode)
{
var btnChangePw = MakeButton("암호 변경");
btnChangePw.Click += (s, e) => ChangePassword();
buttons.Controls.Add(btnChangePw);
}
_btnChangePw = MakeButton("암호 변경");
_btnChangePw.Click += (s, e) => ChangePassword();
buttons.Controls.Add(_btnChangePw);
// 화면 하단 바로가기 버튼 (기본 브라우저로 열기)
_links = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
FlowDirection = FlowDirection.LeftToRight,
Height = 50,
Padding = new Padding(14, 4, 10, 10)
};
var lblLinks = new Label
{
Text = "바로가기:",
AutoSize = true,
Margin = new Padding(0, 9, 6, 0)
};
var btnGetCidMe = MakeLinkButton("GETCID.ME", "https://getcid.me/");
var btnGetCidInfo = MakeLinkButton("GETCID.INFO", "https://getcid.info/");
var btnGetCidUs = MakeLinkButton("GETCID.US", "https://getcid.us/");
_links.Controls.Add(lblLinks);
_links.Controls.Add(btnGetCidMe);
_links.Controls.Add(btnGetCidInfo);
_links.Controls.Add(btnGetCidUs);
// 전화 인증 (slmgr 명령어 방식 — slui 4 창이 막혀 있어도 동작)
_phone = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
FlowDirection = FlowDirection.LeftToRight,
Height = 44,
Padding = new Padding(14, 4, 10, 0)
};
var lblPhone = new Label
{
Text = "전화 인증:",
AutoSize = true,
Margin = new Padding(0, 9, 6, 0)
};
var btnShowIid = MakeActionButton("① 설치 ID 보기");
btnShowIid.Click += (s, e) => ShowInstallationId();
var btnEnterCid = MakeActionButton("② 확인 ID 입력");
btnEnterCid.Click += (s, e) => EnterConfirmationId();
_phone.Controls.Add(lblPhone);
_phone.Controls.Add(btnShowIid);
_phone.Controls.Add(btnEnterCid);
var tip = new ToolTip();
tip.SetToolTip(btnShowIid, "설치 ID(Installation ID)를 확인합니다 (slmgr /dti)");
tip.SetToolTip(btnEnterCid, "받은 확인 ID(Confirmation ID)를 입력해 인증합니다 (slmgr /atp, 관리자 권한 필요)");
tip.SetToolTip(btnGetCidMe, "https://getcid.me/");
tip.SetToolTip(btnGetCidInfo, "https://getcid.info/");
tip.SetToolTip(btnGetCidUs, "https://getcid.us/");
// Dock=Bottom 은 나중에 추가한 것이 더 아래에 배치됨
Controls.Add(table);
Controls.Add(buttons);
if (fullMode)
{
// 화면 하단 바로가기 버튼 (기본 브라우저로 열기)
var links = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
FlowDirection = FlowDirection.LeftToRight,
Height = 50,
Padding = new Padding(14, 4, 10, 10)
};
var lblLinks = new Label
{
Text = "바로가기:",
AutoSize = true,
Margin = new Padding(0, 9, 6, 0)
};
var btnGetCidMe = MakeLinkButton("GETCID.ME", "https://getcid.me/");
var btnGetCidInfo = MakeLinkButton("GETCID.INFO", "https://getcid.info/");
var btnGetCidUs = MakeLinkButton("GETCID.US", "https://getcid.us/");
links.Controls.Add(lblLinks);
links.Controls.Add(btnGetCidMe);
links.Controls.Add(btnGetCidInfo);
links.Controls.Add(btnGetCidUs);
// 전화 인증 (slmgr 명령어 방식 — slui 4 창이 막혀 있어도 동작)
var phone = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
FlowDirection = FlowDirection.LeftToRight,
Height = 44,
Padding = new Padding(14, 4, 10, 0)
};
var lblPhone = new Label
{
Text = "전화 인증:",
AutoSize = true,
Margin = new Padding(0, 9, 6, 0)
};
var btnShowIid = MakeActionButton("① 설치 ID 보기");
btnShowIid.Click += (s, e) => ShowInstallationId();
var btnEnterCid = MakeActionButton("② 확인 ID 입력");
btnEnterCid.Click += (s, e) => EnterConfirmationId();
phone.Controls.Add(lblPhone);
phone.Controls.Add(btnShowIid);
phone.Controls.Add(btnEnterCid);
var tip = new ToolTip();
tip.SetToolTip(btnShowIid, "설치 ID(Installation ID)를 확인합니다 (slmgr /dti)");
tip.SetToolTip(btnEnterCid, "받은 확인 ID(Confirmation ID)를 입력해 인증합니다 (slmgr /atp, 관리자 권한 필요)");
tip.SetToolTip(btnGetCidMe, "https://getcid.me/");
tip.SetToolTip(btnGetCidInfo, "https://getcid.info/");
tip.SetToolTip(btnGetCidUs, "https://getcid.us/");
// Dock=Bottom 은 나중에 추가한 것이 더 아래에 배치됨
Controls.Add(phone);
Controls.Add(links);
}
Controls.Add(_phone);
Controls.Add(_links);
CancelButton = btnClose;
try
@ -560,6 +619,44 @@ namespace WindowsKeyInfo
_txtProductId.Text = _info.ProductId;
_txtInstalledKey.Text = _info.InstalledKey;
_txtBackupKey.Text = _info.BackupKey;
// 처음 표시 모드 (DPI 배율 적용 전이므로 기준 크기로 지정)
_fullMode = fullMode;
_btnChangePw.Visible = fullMode;
_phone.Visible = fullMode;
_links.Visible = fullMode;
ClientSize = new Size(560, fullMode ? 344 : 240);
}
/// <summary>제한 모드 → 전체 모드 전환 (실행 중, DPI 배율이 적용된 실제 크기 기준으로 창 높이 증가)</summary>
private void SwitchToFullMode()
{
if (_fullMode) return;
_fullMode = true;
float scale = _phone.Height / 44f; // 현재 DPI 배율
int extra = _phone.Height + _links.Height + (int)Math.Round(10 * scale); // 344 - 240 = 104 = 44 + 50 + 10
SuspendLayout();
_btnChangePw.Visible = true;
_phone.Visible = true;
_links.Visible = true;
ClientSize = new Size(ClientSize.Width, ClientSize.Height + extra);
ResumeLayout(true);
}
/// <summary>제한 모드에서 Ctrl+Shift+P → 마스터 암호 입력 창</summary>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == UnlockShortcut && !_fullMode)
{
using (var dlg = new MasterPasswordDialog())
{
if (dlg.ShowDialog(this) == DialogResult.OK) SwitchToFullMode();
}
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private static TextBox AddRow(TableLayoutPanel table, int row, string caption, bool monospace)