{"record":{"id":"22d4c53bdcae1c8c","repo":"dotnet/wpf","slug":"sr-onlyacceptskeymessages-hwndsource","errorCode":null,"errorMessage":"SR.OnlyAcceptsKeyMessages","messagePattern":"SR\\.OnlyAcceptsKeyMessages","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs","lineNumber":2092,"sourceCode":"\n                        if (AccessKeyManager.IsKeyRegistered(this, text))\n                        {\n                            AccessKeyManager.ProcessKey(this, text, false);\n\n                            // is it ok not to update _lastKeyboardMessage?\n                            return true;\n                        }\n                    }\n                    // these are OK\n                    break;\n\n                case WindowMessage.WM_CHAR:\n                case WindowMessage.WM_DEADCHAR:\n                    // these are OK\n                    break;\n\n                default:\n                    throw new ArgumentException(SR.OnlyAcceptsKeyMessages);\n            }\n\n            // We record the last message that was processed by us.\n            // This is also checked in WndProc processing to prevent double processing.\n            _lastKeyboardMessage = msg;\n\n            // The bubble will take care of access key processing for this HWND.  Call\n            // the IKIS children unless we are in menu mode.\n            if (_keyboardInputSinkChildren != null && !IsInExclusiveMenuMode)\n            {\n                foreach ( HwndSourceKeyboardInputSite childSite in _keyboardInputSinkChildren )\n                {\n                    if (((IKeyboardInputSite)childSite).Sink.OnMnemonic(ref msg, modifiers))\n                        return true;\n                }\n            }\n            return false;\n        }","sourceCodeStart":2074,"sourceCodeEnd":2110,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs#L2074-L2110","documentation":"This HwndSource member (the keyboard-sink message processing path) accepts only keyboard-related window messages; its switch statement whitelists messages such as WM_KEYDOWN/WM_KEYUP/WM_CHAR/WM_DEADCHAR and throws ArgumentException(SR.OnlyAcceptsKeyMessages) for anything else. It is a contract check that the caller only forwards messages this sink is meant to process.","triggerScenarios":"Forwarding a non-key WindowMessage (e.g. WM_MOUSEMOVE, WM_PAINT, or an application-defined message) into the sink's keyboard processing method instead of letting the normal WndProc dispatch handle it.","commonSituations":"Custom AddHook callbacks that forward every message to the sink unfiltered; testing/automation code synthesizing messages and calling the processor directly; forwarding messages from a parent window that include non-key messages.","solutions":["Filter messages before calling: only route WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_CHAR, WM_DEADCHAR (and siblings the switch allows).","In an AddHook handler, return early (don't call the processor) for messages you don't handle.","Use the public HwndSource pipeline (WndProc) rather than calling internal processing methods with arbitrary messages."],"exampleFix":"// before\nvoid Hook(IntPtr hwnd, int msg, IntPtr w, IntPtr l, ref bool handled)\n{\n    ProcessKeyboardMessage((WindowMessage)msg); // throws for WM_PAINT\n}\n// after\nvoid Hook(IntPtr hwnd, int msg, IntPtr w, IntPtr l, ref bool handled)\n{\n    switch ((WindowMessage)msg)\n    {\n        case WindowMessage.WM_KEYDOWN:\n        case WindowMessage.WM_KEYUP:\n        case WindowMessage.WM_CHAR:\n            ProcessKeyboardMessage((WindowMessage)msg);\n            break;\n    }\n}\n","handlingStrategy":"validation","validationCode":"static readonly HashSet<WindowMessage> Accepted = new() {\n    WindowMessage.WM_KEYDOWN, WindowMessage.WM_KEYUP,\n    WindowMessage.WM_SYSKEYDOWN, WindowMessage.WM_SYSKEYUP,\n    WindowMessage.WM_CHAR, WindowMessage.WM_DEADCHAR };\nif (Accepted.Contains(msg)) ProcessKeyboardMessage(msg);","typeGuard":null,"tryCatchPattern":"try\n{\n    ProcessKeyboardMessage(msg);\n}\ncatch (ArgumentException)\n{\n    // non-key message reached the keyboard path; ignore\n}","preventionTips":["Whitelist key messages at the AddHook boundary.","Return early from hooks for messages you don't own.","Don't call internal processing methods with arbitrary WndProc traffic."],"tags":["argument","keyboard","window-messages","wpf"],"backgroundTag":"invalid-argument-value","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}