Home > Back-end >  Remove focus from SAVE button in OPENFILENAME win32?
Remove focus from SAVE button in OPENFILENAME win32?

Time:11-18

Problem:

If the user holds the "enter" keyboard button and opens OPENFILENAME Save As Dialog, it will automatically save the file - dialog only blinks.

Desired result:

The user holds the "enter" keyboard button, opens OPENFILENAME Save As Dialog, nothing happens. He needs to click on the Save button or click again the "enter" keyboard button to save a file.

My current code:

OPENFILENAME ofn;
TCHAR szFile[260] = { 't','e','s','t'}; // example filename

// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;    
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
//Files like: (ALL - *.*), (Text - .TXT)
ofn.lpstrFilter = _T("All\0*.*\0Text\0*.TXT\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if (GetSaveFileName(&ofn) == TRUE)
{
    // file saved
}

Actual dialog

Possible solution:

  • When ofn.lpstrFile is empty do nothing; Can't save file when there is no filename
  • When ofn.lpstrFile has suggested filename then turn off focus on "Save" button or somehow ignore button enter holding.

I was trying to do that but failed, I am a beginner in CPP :(

Thanks for help

CodePudding user response:

The easy solution to prevent data loss is to add the OFN_OVERWRITEPROMPT flag. This does not prevent the issue from happening if the suggested name does not already exist as a file.

To actually interact with the dialog you need OFN_ENABLEHOOK and a hook function. When you receive WM_NOTIFY, you can handle CDN_FILEOK to block the suggested name if not enough time has passed or maybe it is possible to change the focus in CDN_INITDONE.

Either way, you have to be mindful of the fact that you are changing how a common dialog works and this might anger some users.

Here is one way to do it. The actual delay to return the dialog to normal is something you have to decide for yourself.

const int btnid = 1337;

void CALLBACK resetsavedlgdefpush(HWND hWnd, UINT Msg, UINT_PTR idEvent, DWORD Time)
{
    KillTimer(hWnd, idEvent);
    HWND hDlg = GetParent(hWnd);
    UINT id = LOWORD(SendMessage(hDlg, DM_GETDEFID, 0, 0));
    if (id == btnid)
    {
        SendMessage(hDlg, DM_SETDEFID, IDOK, 0);
    }
}

UINT_PTR CALLBACK mysavehook(HWND hWndInner, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (Msg == WM_NOTIFY)
    {
        OFNOTIFY*pOFN = (OFNOTIFY*) lParam;
        if (pOFN->hdr.code == CDN_INITDONE)
        {
            HWND hDlg = GetParent(hWndInner);
            CreateWindowEx(0, TEXT("BUTTON"), 0, BS_DEFPUSHBUTTON|BS_TEXT|WS_CHILD|WS_VISIBLE, 0, 0, 0, 0, hWndInner, (HMENU) btnid, 0, 0);
            SendMessage(hDlg, DM_SETDEFID, btnid, 0);
            PostMessage(hDlg, DM_SETDEFID, btnid, 0);
            int keydelay = 0;
            SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &keydelay, 0);
            SetTimer(hWndInner, 0, (250 *   keydelay) * 5, resetsavedlgdefpush);
        }
    }
    return 0;
}

...
ofn.Flags = OFN_PATHMUSTEXIST|OFN_EXPLORER|OFN_OVERWRITEPROMPT|OFN_ENABLESIZING|OFN_ENABLEHOOK;
ofn.lpfnHook = mysavehook;
MessageBox(ofn.hwndOwner, TEXT("Hold enter to test..."), 0, 0);
if (GetSaveFileName(&ofn) == TRUE) ...
  • Related