Community
    • Login

    Handling Ctrl+C in a c++ plugin dialog

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    3 Posts 2 Posters 64 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • PeterJonesP
      PeterJones
      last edited by

      I know this borders on a generic Win32 coding question, so it’s borderline off-topic. But I’m trying to figure out how to handle Ctrl+C to copy elements from the (as I said I would here)

      I am using the main C++ plugintemplate coding style (so more c-like than c++, so not with a separate class for each dialog, just the old-fashioned callback dialog-proc).

      My searches have suggested either using TranslateAccelerator (with accelerators defined in the RC file), or just handling WM_KEYDOWN in my dialog procedure.

      TranslateAccelerator seems to need to be called from the main message loop (in the GetMessage/TranslateMessage/DispatchMessage) – but I think that’s controlled outside the plugin (at least, the plugintemplate doesn’t have that explicit message loop), so I don’t think that’s a viable option for a plugin (unless I’ve misunderstood, which is quite possible).

      So I thought WM_KEYDOWN was a better bet. But when I add that case WM_KEYDOWN: to my dialog-proc function, that message never gets received by my procedure, whether I type Ctrl+C or just a normal keyboard character. I am guessing I am missing something (like some flag in the RC file definition for the dialog and/or the listbox control), but if so, I cannot find it; or maybe it’s a fundamental concept or something else I need to do.

      If I cannot get past this, I will just add a “copy selected error” button. But Ctrl+C would be so much more elegant, so I was hoping a more-experienced plugin programmer could chime in with how to make it work, or at least give me some hints that my internet searches haven’t turned up yet.

      Thomas KnoefelT 1 Reply Last reply Reply Quote 0
      • Thomas KnoefelT
        Thomas Knoefel @PeterJones
        last edited by Thomas Knoefel

        @PeterJones
        The reason your DialogProc doesn’t see WM_KEYDOWN is keyboard focus. Windows sends keyboard messages directly to the control that is currently active—in this case, your list control. The parent dialog is never notified.

        Since your plugin can’t access the main Notepad++ message loop to use accelerators, the correct approach is to tap directly into the message stream of the list control itself. This is what subclassing is for. It lets you create a small, specialized message handler that inspects messages for your control before the default behavior kicks in. It’s a clean, safe, and officially sanctioned way to extend control functionality.

        The most robust implementation is a subclass procedure that is completely self-contained. It handles the specific key combination you’re interested in and even cleans itself up automatically when the control is destroyed. This makes your code more modular and easier to maintain.

        Here is what such a procedure looks like. It’s the only piece of complex code you need.

        static LRESULT CALLBACK ListBoxSubclassProc(
            HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
            UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
        {
            // Check for the universal Ctrl+C signal (works on all keyboard layouts)
            if (uMsg == WM_CHAR && wParam == 0x03) {
                CopySelectionFromControl(hWnd); // Your function to copy text
                return 0; // Event handled
            }
        
            // When the control is destroyed, it automatically removes this subclass
            if (uMsg == WM_NCDESTROY) {
                RemoveWindowSubclass(hWnd, ListBoxSubclassProc, uIdSubclass);
            }
        
            // For all other messages, just pass them to the default handler
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
        }
        

        This procedure is activated with a single line in your DialogProc’s WM_INITDIALOG case: SetWindowSubclass(hListBox, ListBoxSubclassProc, 0, 0);. That’s it. Because the subclass cleans itself up, you don’t even need to add code to WM_DESTROY.

        PeterJonesP 1 Reply Last reply Reply Quote 1
        • PeterJonesP
          PeterJones @Thomas Knoefel
          last edited by

          @Thomas-Knoefel ,

          Well, that got me farther. With some keystrokes, like a normal letter, or a key-combo that’s not assigned to anything in Notepad++ (like Shift+Ctrl+C), it will call that subclass function and see the uMsg==WM_CHAR. But Ctrl+C doesn’t trigger it; and if I try a shortcut that does something obviousl in N++, like Alt+C (for the Column Editor).

          But that reminded me of the recent conversation about shortcut mappings, and so I tried sending the appropriate NPPM_MODELESSDIALOG arguments during my plugin’s init & destroy, and now it can capture Ctrl+C (or any other shortcut).

          Thank you

          1 Reply Last reply Reply Quote 2
          • First post
            Last post
          The Community of users of the Notepad++ text editor.
          Powered by NodeBB | Contributors