1 #pragma once 2 3 namespace rxcpp { namespace windows_user { 4 5 struct rx_messages 6 { 7 struct Result 8 { 9 LRESULT lres = 0; 10 bool handled = false; 11 }; 12 13 struct Message 14 { 15 template<UINT WM> 16 static auto is() { return [](Message m){ return m.message == WM; }; } 17 18 HWND hWnd; 19 UINT message; 20 WPARAM wParam; 21 LPARAM lParam; 22 Result* result; 23 24 void handled() { result->handled = true; } 25 void lresult(LRESULT lres) {result->lres = lres; } 26 27 template<class T> 28 T wparam_cast(){ 29 return *reinterpret_cast<T*>(std::addressof(wParam)); 30 } 31 32 template<class T> 33 T lparam_cast(){ 34 return *reinterpret_cast<T*>(std::addressof(lParam)); 35 } 36 }; 37 38 template<class WPARAM_t = WPARAM, class LPARAM_t = LPARAM> 39 struct TypedMessage 40 { 41 static auto as() { return [](Message m){return TypedMessage{m}; }; } 42 43 TypedMessage(Message m) 44 : hWnd(m.hWnd) 45 , message(m.message) 46 , wParam(m.wparam_cast<WPARAM_t>()) 47 , lParam(m.lparam_cast<LPARAM_t>()) 48 , result(m.result) 49 {} 50 51 HWND hWnd; 52 UINT message; 53 WPARAM_t wParam; 54 LPARAM_t lParam; 55 Result* result; 56 57 void handled() { result->handled = true; } 58 void lresult(LRESULT lres) {result->lres = lres; } 59 }; 60 61 subjects::subject<Message> subject; 62 subscriber<Message> sub; 63 64 ~rx_messages() { 65 sub.on_completed(); 66 } 67 rx_messages() : sub(subject.get_subscriber()) {} 68 69 std::tuple<bool, LRESULT> message(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 70 Result result; 71 auto m = Message{hWnd, message, wParam, lParam, &result}; 72 try { 73 sub.on_next(m); 74 } catch(...) { 75 sub.on_error(std::current_exception()); 76 } 77 return std::make_tuple(result.handled, result.lres); 78 } 79 80 observable<Message> messages() { 81 return subject.get_observable(); 82 } 83 84 template<UINT WM> 85 observable<Message> messages() { 86 return messages().filter(Message::is<WM>()); 87 } 88 89 template<UINT WM, class WPARAM_t, class LPARAM_t = LPARAM> 90 observable<TypedMessage<WPARAM_t, LPARAM_t>> messages() { 91 return messages<WM>().map(TypedMessage<WPARAM_t, LPARAM_t>::as()); 92 } 93 94 }; 95 96 template<class Derived, UINT WM> 97 struct enable_send_call 98 { 99 static LRESULT send_call(HWND w, std::function<LRESULT(Derived&)> f) { 100 auto fp = reinterpret_cast<LPARAM>(std::addressof(f)); 101 return SendMessage(w, WM, 0, fp); 102 } 103 104 void OnSendCall() { 105 auto derived = static_cast<Derived*>(this); 106 derived->messages<WM, WPARAM, std::function<LRESULT(Derived&)>*>(). 107 subscribe([=](auto m) { 108 m.handled(); // skip DefWindowProc 109 m.lresult((*m.lParam)(*derived)); 110 }); 111 } 112 113 enable_send_call() { 114 OnSendCall(); 115 } 116 }; 117 } } 118