/////////////////////////////////////////////////////////////////////////////// // ketchup/message_processor.hp // // Version 0.903 // Copyright 2005 MB@unknown.jp. // // This file is a part of the *ketchup*. // The use and distribution terms for this software are covered by the // Common Public License 1.0 (http://opensource.org/licenses/cpl.php) // which can be found in the file CPL.TXT at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. You must not remove this notice, or // any other, from this software. // // Revision History // 05 May 2005 Initial version #ifndef KETCHUP_MESSAGE_PROCESSOR_H #define KETCHUP_MESSAGE_PROCESSOR_H #ifdef _MSC_VER #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include "ignore_unused_variables_warning.hpp" /////////////////////////////////////////////////////////////////////////////// // function parameters and arguments // #define KETCHUP_PROCESS_WINDOW_MESSAGE_PARAMS \ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID #define KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS \ hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID /////////////////////////////////////////////////////////////////////////////// // function body variables (bHandled added) // #define KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS \ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID, BOOL& bHandled #define KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS \ hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID, bHandled /////////////////////////////////////////////////////////////////////////////// // KETCHUP_CHAIN_MSG_MAP for ATL's BEGIN_MSG_MAP macro // #define KETCHUP_CHAIN_MSG_MAP(MessageMap) {\ if (process_window_message(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID))\ return TRUE;\ } namespace ketchup { namespace detail { /////////////////////////////////////////////////////////////////////////////// // Note: // If MessageMap has the same MessageMapEntry, VC7.1 duplicates // the static member function, MessageMapEntry::compile (LNK1179 error). // I can't understand the problem, // but VC7.1 seems to hate static member functions. // So I define workaround_for_mpl_assert_not_arg and... // // compile_message_map_entry // template< class Derived, class MessageMapEntry > inline bool compile_message_map_entry(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { return MessageMapEntry::compile(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); } /////////////////////////////////////////////////////////////////////////////// // big_if_statement // template< class Derived, class MessageMap > struct big_if_statement { template< class State, class MessageMapEntry > struct op { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { if (compile_message_map_entry(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS)) return true; else return State::compile(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); } }; struct init_state { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); return false; } }; // The placeholders say mpl_assert_not_arg, so I define struct workaround_for_mpl_assert_not_arg { template< class State, class MessageMapEntry > struct apply { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { if (compile_message_map_entry(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS)) return true; else return State::compile(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); } typedef apply type; }; }; typedef typename boost::mpl::reverse_fold< MessageMap, init_state, // op // makes mpl_assert_not_arg workaround_for_mpl_assert_not_arg >::type type; }; /////////////////////////////////////////////////////////////////////////////// // process_window_message_function_body // template< class Derived, class MessageMap > struct process_window_message_function_body { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_PARAMS) { BOOL bHandled = TRUE; typedef typename big_if_statement< Derived, MessageMap >::type statement; return statement::compile(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); } typedef process_window_message_function_body type; }; /////////////////////////////////////////////////////////////////////////////// // process_window_message_function_body_for_cracked_handlers // template< class Derived, class MessageMap > struct process_window_message_function_body_for_cracked_handlers { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_PARAMS) { bool old = derived.is_msg_handled(); // for recursive calls BOOL bHandled = TRUE; typedef typename big_if_statement< Derived, MessageMap >::type statement; bool ret = statement::compile(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); derived.set_msg_handled(old); return ret; } typedef process_window_message_function_body_for_cracked_handlers type; }; /////////////////////////////////////////////////////////////////////////////// // message_processor_base // template< class Derived, class HasCrackedHandlers > struct message_processor_base { struct base { template< class MessageMap > bool process_window_message(KETCHUP_PROCESS_WINDOW_MESSAGE_PARAMS) { typedef typename process_window_message_function_body::type body; return body::compile(*static_cast(this), KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS); }; typedef base type; }; struct base_for_cracked_handlers { bool msg_handled_; bool is_msg_handled() { return msg_handled_; } void set_msg_handled(bool handled) { msg_handled_ = handled; } template< class MessageMap > bool process_window_message(KETCHUP_PROCESS_WINDOW_MESSAGE_PARAMS) { typedef typename process_window_message_function_body_for_cracked_handlers::type body; return body::compile(*static_cast(this), KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS); }; typedef base_for_cracked_handlers type; }; typedef typename boost::mpl::eval_if< HasCrackedHandlers, base_for_cracked_handlers, base >::type type; }; } } // namespace ketchup::detail namespace ketchup { /////////////////////////////////////////////////////////////////////////////// // message_processor // template< class Derived, bool has_cracked_handlers = false > struct message_processor : detail::message_processor_base< Derived, boost::mpl::bool_ >::type { protected: /////////////////////////////////////////////////////////////////////////////// // MessageMapEntries // // Note: Default parameters in nested templates will be ignored by VC7.1. // /////////////////////////////////////////////////////////////////////////////// // empty_handler // struct empty_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); return false; } }; /////////////////////////////////////////////////////////////////////////////// // message_handler // typedef LRESULT (Derived::*message_handler_type)(UINT, WPARAM, LPARAM, BOOL&); template< UINT msg, message_handler_type func > struct message_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == msg) { bHandled = TRUE; lResult = (derived.*func)(uMsg, wParam, lParam, bHandled); if (bHandled) return true; } return false; } }; template< UINT msg, message_handler_type func > struct message_handler_hot { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == msg) { lResult = (derived.*func)(uMsg, wParam, lParam, bHandled); return true; } return false; } }; template< UINT msg, message_handler_type func > struct message_handler_not { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == msg) { lResult = (derived.*func)(uMsg, wParam, lParam, bHandled); } return false; } }; /////////////////////////////////////////////////////////////////////////////// // message_range_handler // template< UINT msgFirst, UINT msgLast, message_handler_type func > struct message_range_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg >= msgFirst && uMsg <= msgLast) { bHandled = TRUE; lResult = (derived.*func)(uMsg, wParam, lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // command_handler // typedef LRESULT (Derived::*command_handler_type)(WORD, WORD, HWND, BOOL&); template< WORD id, WORD code, command_handler_type func > struct command_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) { bHandled = TRUE; lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // command_id_handler // template< WORD id, command_handler_type func > struct command_id_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && id == LOWORD(wParam)) { bHandled = TRUE; lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); if (bHandled) return true; } return false; } }; template< WORD id, command_handler_type func > struct command_id_handler_hot { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && id == LOWORD(wParam)) { lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); return true; } return false; } }; template< WORD id, command_handler_type func > struct command_id_handler_not { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && id == LOWORD(wParam)) { lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); } return false; } }; /////////////////////////////////////////////////////////////////////////////// // command_code_handler // template< WORD code, command_handler_type func > struct command_code_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && id == HIWORD(wParam)) { bHandled = TRUE; lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // command_range_handler // template< WORD idFirst, WORD idLast, command_handler_type func > struct command_range_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { bHandled = TRUE; lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // command_range_code_handler // template< WORD idFirst, WORD idLast, WORD code, command_handler_type func > struct command_range_code_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { bHandled = TRUE; lResult = (derived.*func)(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // notify_handler // typedef LRESULT (Derived::*notify_handler_type)(int, LPNMHDR, BOOL&); template< UINT id, UINT cd, notify_handler_type func > struct notify_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) { bHandled = TRUE; lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // notify_id_handler // template< UINT id, notify_handler_type func > struct notify_id_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) { bHandled = TRUE; lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // notify_code_handler // template< UINT cd, notify_handler_type func > struct notify_code_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { bHandled = TRUE; lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); if (bHandled) return true; } return false; } }; template< UINT cd, notify_handler_type func > struct notify_code_handler_hot { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); return true; } return false; } }; template< UINT cd, notify_handler_type func > struct notify_code_handler_not { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); } return false; } }; /////////////////////////////////////////////////////////////////////////////// // notify_range_handler // template< UINT idFirst, UINT idLast, notify_handler_type func > struct notify_range_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) { bHandled = TRUE; lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // notify_range_code_handler // template< UINT idFirst, UINT idLast, UINT cd, notify_handler_type func > struct notify_range_code_handler { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) { bHandled = TRUE; lResult = (derived.*func)((int)wParam, (LPNMHDR)lParam, bHandled); if (bHandled) return true; } return false; } }; /////////////////////////////////////////////////////////////////////////////// // chain_msg_map // // Note: to avoid ::type syntax // template< class theChainClassOrMessageMap > struct chain_msg_map_base { template< class MessageMap > struct chain_msg_map_statement { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); return derived.process_window_message(KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS); } typedef chain_msg_map_statement type; }; template< class theChainClass > struct chain_atl_msg_map_statement { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); // no warning cast from BOOL to bool if (derived.theChainClass::ProcessWindowMessage(KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS)) return true; return false; } typedef chain_atl_msg_map_statement type; }; typedef typename boost::mpl::eval_if< boost::mpl::is_sequence, chain_msg_map_statement, chain_atl_msg_map_statement >::type statement; typedef typename boost::mpl::apply::type type; }; template< class theChainClassOrMessageMap > struct chain_msg_map : chain_msg_map_base::type { /* static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (derived.theChainClass::ProcessWindowMessage(KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS)) return true; return false; } */ }; /////////////////////////////////////////////////////////////////////////////// // alt_msg_map // template< DWORD msgMapID, class MessageMap > struct alt_msg_map { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (dwMsgMapID == msgMapID) { return derived.process_window_message(KETCHUP_PROCESS_WINDOW_MESSAGE_ARGS); } else return false; // pass to other alternates } }; /////////////////////////////////////////////////////////////////////////////// // cracked_handlers // template< void (Derived::*func)() > struct msg_wm_close { static bool compile(Derived& derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_PARAMS) { BOOST_STATIC_ASSERT(has_cracked_handlers); ignore_unused_variables_warning(derived, KETCHUP_PROCESS_WINDOW_MESSAGE_VARS_AS_ARGS); if (uMsg == WM_CLOSE) { derived.set_msg_handled(true); (derived.*func)(); lResult = 0; if (derived.is_msg_handled()) return true; } return false; } }; //#include "detail/cracked_handlers.ipp" }; // struct message_listener } // namespace ketchup #endif