Home | History | Annotate | Download | only in win_text
      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