diff --git a/Program.cs b/Program.cs
index 3184769..ba6af1d 100644
--- a/Program.cs
+++ b/Program.cs
@@ -247,6 +247,64 @@ namespace WindowsKeyInfo
}
}
+ /// 제한 화면에서 Ctrl+Shift+P로 여는 마스터 암호 입력 창 (틀리면 알림 후 다시 입력)
+ 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();
+ }
+ }
+
/// 암호 변경 창 (새 암호 한 번 입력)
internal sealed class ChangePasswordDialog : Form
{
@@ -409,15 +467,24 @@ namespace WindowsKeyInfo
}
}
- /// 메인 창 (WinForms). fullMode=false면 키 정보 4줄 + 복사/파일로 저장/닫기만 표시
+ /// 메인 창 (WinForms). 제한 모드면 키 정보 4줄 + 복사/파일로 저장/닫기만 표시,
+ /// 제한 모드에서 Ctrl+Shift+P → 마스터 암호 입력 → 맞으면 그 자리에서 전체 화면으로 전환
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);
+ }
+
+ /// 제한 모드 → 전체 모드 전환 (실행 중, DPI 배율이 적용된 실제 크기 기준으로 창 높이 증가)
+ 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);
+ }
+
+ /// 제한 모드에서 Ctrl+Shift+P → 마스터 암호 입력 창
+ 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)