From 01101e2da6f4493ce8cfcf4d9509163b9c264d58 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 29 Jul 2007 01:04:33 +0000 Subject: [PATCH] added support for 2 extra mouse buttons (patch 1757630) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47802 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/mouseevt.tex | 81 ++++++++++++++++++++++++++++++++++++-- include/wx/event.h | 39 ++++++++++++++++-- include/wx/utils.h | 7 ++++ src/common/event.cpp | 53 ++++++++++++++++++++++--- src/msw/window.cpp | 30 +++++++++++++- 6 files changed, 198 insertions(+), 13 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 5749e28c8e..6a61677bd0 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -150,6 +150,7 @@ All (GUI): - Support wxAPPLY and wxCLOSE in CreateStdDialogButtonSizer() (Marcin Wojdyr) - Show standard options in wxCmdLineParser usage message (Francesco Montorsi) - Added wxRect::operator+ (union) and * (intersection) (bdonner) +- Added support for two auxiliary mouse buttons to wxMouseEvent (Chris Weiland) wxGTK: diff --git a/docs/latex/wx/mouseevt.tex b/docs/latex/wx/mouseevt.tex index 7991cbb652..63b91473f3 100644 --- a/docs/latex/wx/mouseevt.tex +++ b/docs/latex/wx/mouseevt.tex @@ -5,9 +5,12 @@ they include mouse buttons press and release events and mouse move events. All mouse events involving the buttons use {\tt wxMOUSE\_BTN\_LEFT} for the left mouse button, {\tt wxMOUSE\_BTN\_MIDDLE} for the middle one and -{\tt wxMOUSE\_BTN\_RIGHT} for the right one. Note that not all mice have a -middle button so a portable application should avoid relying on the events from -it. +{\tt wxMOUSE\_BTN\_RIGHT} for the right one. And if the system supports more +buttons, the \texttt{wxMOUSE\_BTN\_AUX1} and \texttt{wxMOUSE\_BTN\_AUX2} events +can also be generated. Note that not all mice have even a middle button so a +portable application should avoid relying on the events from it (but the right +button click can be emulated using the left mouse button with the control key +under Mac platforms with a single button mouse). For the \texttt{wxEVT\_ENTER\_WINDOW} and \texttt{wxEVT\_LEAVE\_WINDOW} events purposes, the mouse is considered to be inside the window if it is in the @@ -66,6 +69,12 @@ wouldn't get the focus.} \twocolitem{{\bf EVT\_RIGHT\_DOWN(func)}}{Process a wxEVT\_RIGHT\_DOWN event.} \twocolitem{{\bf EVT\_RIGHT\_UP(func)}}{Process a wxEVT\_RIGHT\_UP event.} \twocolitem{{\bf EVT\_RIGHT\_DCLICK(func)}}{Process a wxEVT\_RIGHT\_DCLICK event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX1\_DOWN(func)}}{Process a wxEVT\_MOUSE\_AUX1\_DOWN event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX1\_UP(func)}}{Process a wxEVT\_MOUSE\_AUX1\_UP event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX1\_DCLICK(func)}}{Process a wxEVT\_MOUSE\_AUX1\_DCLICK event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX2\_DOWN(func)}}{Process a wxEVT\_MOUSE\_AUX2\_DOWN event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX2\_UP(func)}}{Process a wxEVT\_MOUSE\_AUX2\_UP event.} +\twocolitem{{\bf EVT\_MOUSE\_AUX2\_DCLICK(func)}}{Process a wxEVT\_MOUSE\_AUX2\_DCLICK event.} \twocolitem{{\bf EVT\_MOTION(func)}}{Process a wxEVT\_MOTION event.} \twocolitem{{\bf EVT\_ENTER\_WINDOW(func)}}{Process a wxEVT\_ENTER\_WINDOW event.} \twocolitem{{\bf EVT\_LEAVE\_WINDOW(func)}}{Process a wxEVT\_LEAVE\_WINDOW event.} @@ -181,6 +190,12 @@ Constructor. Valid event types are: \item {\bf wxEVT\_RIGHT\_DOWN} \item {\bf wxEVT\_RIGHT\_UP} \item {\bf wxEVT\_RIGHT\_DCLICK} +\item {\bf wxEVT\_MOUSE\_AUX1\_DOWN} +\item {\bf wxEVT\_MOUSE\_AUX1\_UP} +\item {\bf wxEVT\_MOUSE\_AUX1\_DCLICK} +\item {\bf wxEVT\_MOUSE\_AUX2\_DOWN} +\item {\bf wxEVT\_MOUSE\_AUX2\_UP} +\item {\bf wxEVT\_MOUSE\_AUX2\_DCLICK} \item {\bf wxEVT\_MOTION} \item {\bf wxEVT\_MOUSEWHEEL} \end{itemize} @@ -193,6 +208,64 @@ Constructor. Valid event types are: Returns true if the Alt key was down at the time of the event. +\membersection{wxMouseEvent::Aux1DClick}\label{wxmouseeventaux1dclick} + +\constfunc{bool}{Aux1DClick}{\void} + +Returns true if the event was a first extra button double click. + + +\membersection{wxMouseEvent::Aux1Down}\label{wxmouseeventaux1down} + +\constfunc{bool}{Aux1Down}{\void} + +Returns true if the first extra button mouse button changed to down. + + +\membersection{wxMouseEvent::Aux1IsDown}\label{wxmouseeventaux1isdown} + +\constfunc{bool}{Aux1IsDown}{\void} + +Returns true if the first extra button mouse button is currently down, independent +of the current event type. + + +\membersection{wxMouseEvent::Aux1Up}\label{wxmouseeventaux1up} + +\constfunc{bool}{Aux1Up}{\void} + +Returns true if the first extra button mouse button changed to up. + + +\membersection{wxMouseEvent::Aux2DClick}\label{wxmouseeventaux2dclick} + +\constfunc{bool}{Aux2DClick}{\void} + +Returns true if the event was a second extra button double click. + + +\membersection{wxMouseEvent::Aux2Down}\label{wxmouseeventaux2down} + +\constfunc{bool}{Aux2Down}{\void} + +Returns true if the second extra button mouse button changed to down. + + +\membersection{wxMouseEvent::Aux2IsDown}\label{wxmouseeventaux2isdown} + +\constfunc{bool}{Aux2IsDown}{\void} + +Returns true if the second extra button mouse button is currently down, independent +of the current event type. + + +\membersection{wxMouseEvent::Aux2Up}\label{wxmouseeventaux2up} + +\constfunc{bool}{Aux2Up}{\void} + +Returns true if the second extra button mouse button changed to up. + + \membersection{wxMouseEvent::Button}\label{wxmouseeventbutton} \func{bool}{Button}{\param{int}{ button}} @@ -204,6 +277,8 @@ values of {\it button} are: \twocolitem{{\tt wxMOUSE\_BTN\_LEFT}}{check if left button was pressed} \twocolitem{{\tt wxMOUSE\_BTN\_MIDDLE}}{check if middle button was pressed} \twocolitem{{\tt wxMOUSE\_BTN\_RIGHT}}{check if right button was pressed} +\twocolitem{{\tt wxMOUSE\_BTN\_AUX1}}{check if the first extra button was pressed} +\twocolitem{{\tt wxMOUSE\_BTN\_AUX2}}{check if the second extra button was pressed} \twocolitem{{\tt wxMOUSE\_BTN\_ANY}}{check if any button was pressed} \end{twocollist} diff --git a/include/wx/event.h b/include/wx/event.h index 1278284950..3635b757ec 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -179,6 +179,12 @@ BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE(wxEVT_KILL_FOCUS, 113) DECLARE_EVENT_TYPE(wxEVT_CHILD_FOCUS, 114) DECLARE_EVENT_TYPE(wxEVT_MOUSEWHEEL, 115) + DECLARE_EVENT_TYPE(wxEVT_AUX1_DOWN, 116) + DECLARE_EVENT_TYPE(wxEVT_AUX1_UP, 117) + DECLARE_EVENT_TYPE(wxEVT_AUX1_DCLICK, 118) + DECLARE_EVENT_TYPE(wxEVT_AUX2_DOWN, 119) + DECLARE_EVENT_TYPE(wxEVT_AUX2_UP, 120) + DECLARE_EVENT_TYPE(wxEVT_AUX2_DCLICK, 121) // Non-client mouse events DECLARE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN, 200) @@ -676,7 +682,10 @@ enum wxMOUSE_BTN_NONE = 0, wxMOUSE_BTN_LEFT = 1, wxMOUSE_BTN_MIDDLE = 2, - wxMOUSE_BTN_RIGHT = 3 + wxMOUSE_BTN_RIGHT = 3, + wxMOUSE_BTN_AUX1 = 4, + wxMOUSE_BTN_AUX2 = 5, + wxMOUSE_BTN_MAX }; class WXDLLIMPEXP_CORE wxMouseEvent : public wxEvent @@ -725,20 +734,28 @@ public: bool LeftDown() const { return (m_eventType == wxEVT_LEFT_DOWN); } bool MiddleDown() const { return (m_eventType == wxEVT_MIDDLE_DOWN); } bool RightDown() const { return (m_eventType == wxEVT_RIGHT_DOWN); } + bool Aux1Down() const { return (m_eventType == wxEVT_AUX1_DOWN); } + bool Aux2Down() const { return (m_eventType == wxEVT_AUX2_DOWN); } bool LeftUp() const { return (m_eventType == wxEVT_LEFT_UP); } bool MiddleUp() const { return (m_eventType == wxEVT_MIDDLE_UP); } bool RightUp() const { return (m_eventType == wxEVT_RIGHT_UP); } + bool Aux1Up() const { return (m_eventType == wxEVT_AUX1_UP); } + bool Aux2Up() const { return (m_eventType == wxEVT_AUX2_UP); } bool LeftDClick() const { return (m_eventType == wxEVT_LEFT_DCLICK); } bool MiddleDClick() const { return (m_eventType == wxEVT_MIDDLE_DCLICK); } bool RightDClick() const { return (m_eventType == wxEVT_RIGHT_DCLICK); } + bool Aux1DClick() const { return (m_eventType == wxEVT_AUX1_UP); } + bool Aux2DClick() const { return (m_eventType == wxEVT_AUX2_UP); } // Find the current state of the mouse buttons (regardless // of current event type) bool LeftIsDown() const { return m_leftDown; } bool MiddleIsDown() const { return m_middleDown; } bool RightIsDown() const { return m_rightDown; } + bool Aux1IsDown() const { return m_aux1Down; } + bool Aux2IsDown() const { return m_aux2Down; } // True if a button is down and the mouse is moving bool Dragging() const @@ -823,6 +840,8 @@ public: bool m_leftDown; bool m_middleDown; bool m_rightDown; + bool m_aux1Down; + bool m_aux2Down; bool m_controlDown; bool m_shiftDown; @@ -2882,19 +2901,31 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent& #define EVT_LEAVE_WINDOW(func) wx__DECLARE_EVT0(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(func)) #define EVT_ENTER_WINDOW(func) wx__DECLARE_EVT0(wxEVT_ENTER_WINDOW, wxMouseEventHandler(func)) #define EVT_MOUSEWHEEL(func) wx__DECLARE_EVT0(wxEVT_MOUSEWHEEL, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX1_DOWN(func) wx__DECLARE_EVT0(wxEVT_AUX1_DOWN, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX1_UP(func) wx__DECLARE_EVT0(wxEVT_AUX1_UP, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX1_DCLICK(func) wx__DECLARE_EVT0(wxEVT_AUX1_DCLICK, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX2_DOWN(func) wx__DECLARE_EVT0(wxEVT_AUX2_DOWN, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX2_UP(func) wx__DECLARE_EVT0(wxEVT_AUX2_UP, wxMouseEventHandler(func)) +#define EVT_MOUSE_AUX2_DCLICK(func) wx__DECLARE_EVT0(wxEVT_AUX2_DCLICK, wxMouseEventHandler(func)) // All mouse events #define EVT_MOUSE_EVENTS(func) \ EVT_LEFT_DOWN(func) \ EVT_LEFT_UP(func) \ + EVT_LEFT_DCLICK(func) \ EVT_MIDDLE_DOWN(func) \ EVT_MIDDLE_UP(func) \ + EVT_MIDDLE_DCLICK(func) \ EVT_RIGHT_DOWN(func) \ EVT_RIGHT_UP(func) \ - EVT_MOTION(func) \ - EVT_LEFT_DCLICK(func) \ - EVT_MIDDLE_DCLICK(func) \ EVT_RIGHT_DCLICK(func) \ + EVT_MOUSE_AUX1_DOWN(func) \ + EVT_MOUSE_AUX1_UP(func) \ + EVT_MOUSE_AUX1_DCLICK(func) \ + EVT_MOUSE_AUX2_DOWN(func) \ + EVT_MOUSE_AUX2_UP(func) \ + EVT_MOUSE_AUX2_DCLICK(func) \ + EVT_MOTION(func) \ EVT_LEAVE_WINDOW(func) \ EVT_ENTER_WINDOW(func) \ EVT_MOUSEWHEEL(func) diff --git a/include/wx/utils.h b/include/wx/utils.h index e68243b82d..2a811afba8 100644 --- a/include/wx/utils.h +++ b/include/wx/utils.h @@ -212,6 +212,7 @@ public: wxMouseState() : m_x(0), m_y(0), m_leftDown(false), m_middleDown(false), m_rightDown(false), + m_aux1Down(false), m_aux2Down(false), m_controlDown(false), m_shiftDown(false), m_altDown(false), m_metaDown(false) {} @@ -222,6 +223,8 @@ public: bool LeftDown() { return m_leftDown; } bool MiddleDown() { return m_middleDown; } bool RightDown() { return m_rightDown; } + bool Aux1Down() { return m_aux1Down; } + bool Aux2Down() { return m_aux2Down; } bool ControlDown() { return m_controlDown; } bool ShiftDown() { return m_shiftDown; } @@ -242,6 +245,8 @@ public: void SetLeftDown(bool down) { m_leftDown = down; } void SetMiddleDown(bool down) { m_middleDown = down; } void SetRightDown(bool down) { m_rightDown = down; } + void SetAux1Down(bool down) { m_aux1Down = down; } + void SetAux2Down(bool down) { m_aux2Down = down; } void SetControlDown(bool down) { m_controlDown = down; } void SetShiftDown(bool down) { m_shiftDown = down; } @@ -255,6 +260,8 @@ private: bool m_leftDown : 1; bool m_middleDown : 1; bool m_rightDown : 1; + bool m_aux1Down : 1; + bool m_aux2Down : 1; bool m_controlDown : 1; bool m_shiftDown : 1; diff --git a/src/common/event.cpp b/src/common/event.cpp index 3ac1284d86..980f6ba965 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -197,6 +197,12 @@ DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS) DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS) DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS) DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL) +DEFINE_EVENT_TYPE(wxEVT_AUX1_DOWN) +DEFINE_EVENT_TYPE(wxEVT_AUX1_UP) +DEFINE_EVENT_TYPE(wxEVT_AUX1_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_AUX2_DOWN) +DEFINE_EVENT_TYPE(wxEVT_AUX2_UP) +DEFINE_EVENT_TYPE(wxEVT_AUX2_DCLICK) // Non-client mouse events DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN) @@ -518,6 +524,8 @@ wxMouseEvent::wxMouseEvent(wxEventType commandType) m_leftDown = false; m_rightDown = false; m_middleDown = false; + m_aux1Down = false; + m_aux2Down = false; m_x = 0; m_y = 0; m_wheelRotation = 0; @@ -536,6 +544,8 @@ void wxMouseEvent::Assign(const wxMouseEvent& event) m_leftDown = event.m_leftDown; m_middleDown = event.m_middleDown; m_rightDown = event.m_rightDown; + m_aux1Down = event.m_aux1Down; + m_aux2Down = event.m_aux2Down; m_controlDown = event.m_controlDown; m_shiftDown = event.m_shiftDown; @@ -558,7 +568,8 @@ bool wxMouseEvent::ButtonDClick(int but) const // fall through case wxMOUSE_BTN_ANY: - return (LeftDClick() || MiddleDClick() || RightDClick()); + return (LeftDClick() || MiddleDClick() || RightDClick() || + Aux1DClick() || Aux2DClick()); case wxMOUSE_BTN_LEFT: return LeftDClick(); @@ -568,6 +579,12 @@ bool wxMouseEvent::ButtonDClick(int but) const case wxMOUSE_BTN_RIGHT: return RightDClick(); + + case wxMOUSE_BTN_AUX1: + return Aux1DClick(); + + case wxMOUSE_BTN_AUX2: + return Aux2DClick(); } } @@ -581,7 +598,8 @@ bool wxMouseEvent::ButtonDown(int but) const // fall through case wxMOUSE_BTN_ANY: - return (LeftDown() || MiddleDown() || RightDown()); + return (LeftDown() || MiddleDown() || RightDown() || + Aux1Down() || Aux2Down()); case wxMOUSE_BTN_LEFT: return LeftDown(); @@ -591,6 +609,12 @@ bool wxMouseEvent::ButtonDown(int but) const case wxMOUSE_BTN_RIGHT: return RightDown(); + + case wxMOUSE_BTN_AUX1: + return Aux1Down(); + + case wxMOUSE_BTN_AUX2: + return Aux2Down(); } } @@ -604,7 +628,8 @@ bool wxMouseEvent::ButtonUp(int but) const // fall through case wxMOUSE_BTN_ANY: - return (LeftUp() || MiddleUp() || RightUp()); + return (LeftUp() || MiddleUp() || RightUp() || + Aux1Up() || Aux2Up()); case wxMOUSE_BTN_LEFT: return LeftUp(); @@ -614,6 +639,12 @@ bool wxMouseEvent::ButtonUp(int but) const case wxMOUSE_BTN_RIGHT: return RightUp(); + + case wxMOUSE_BTN_AUX1: + return Aux1Up(); + + case wxMOUSE_BTN_AUX2: + return Aux2Up(); } } @@ -639,6 +670,12 @@ bool wxMouseEvent::Button(int but) const case wxMOUSE_BTN_RIGHT: return RightDown() || RightUp() || RightDClick(); + + case wxMOUSE_BTN_AUX1: + return Aux1Down() || Aux1Up() || Aux1DClick(); + + case wxMOUSE_BTN_AUX2: + return Aux2Down() || Aux2Up() || Aux2DClick(); } } @@ -651,7 +688,7 @@ bool wxMouseEvent::ButtonIsDown(int but) const // fall through case wxMOUSE_BTN_ANY: - return LeftIsDown() || MiddleIsDown() || RightIsDown(); + return LeftIsDown() || MiddleIsDown() || RightIsDown() || Aux1Down() || Aux2Down(); case wxMOUSE_BTN_LEFT: return LeftIsDown(); @@ -661,12 +698,18 @@ bool wxMouseEvent::ButtonIsDown(int but) const case wxMOUSE_BTN_RIGHT: return RightIsDown(); + + case wxMOUSE_BTN_AUX1: + return Aux1IsDown(); + + case wxMOUSE_BTN_AUX2: + return Aux2IsDown(); } } int wxMouseEvent::GetButton() const { - for ( int i = 1; i <= 3; i++ ) + for ( int i = 1; i < wxMOUSE_BTN_MAX; i++ ) { if ( Button(i) ) { diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 81ee66815f..ef18195d59 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -2652,6 +2652,9 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_XBUTTONDBLCLK: { #ifdef __WXMICROWIN__ // MicroWindows seems to ignore the fact that a window is @@ -4794,6 +4797,8 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, event.m_leftDown = (flags & MK_LBUTTON) != 0; event.m_middleDown = (flags & MK_MBUTTON) != 0; event.m_rightDown = (flags & MK_RBUTTON) != 0; + event.m_aux1Down = (flags & MK_XBUTTON1) != 0; + event.m_aux2Down = (flags & MK_XBUTTON2) != 0; event.m_altDown = ::GetKeyState(VK_MENU) < 0; #ifndef __WXWINCE__ @@ -4892,9 +4897,27 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) wxEVT_RIGHT_DCLICK, wxEVT_MIDDLE_DOWN, wxEVT_MIDDLE_UP, - wxEVT_MIDDLE_DCLICK + wxEVT_MIDDLE_DCLICK, + 0, // this one is for wxEVT_MOTION which is not used here + wxEVT_AUX1_DOWN, + wxEVT_AUX1_UP, + wxEVT_AUX1_DCLICK, + wxEVT_AUX2_DOWN, + wxEVT_AUX2_UP, + wxEVT_AUX2_DCLICK }; + // the same messages are used for both auxillary mouse buttons so we need + // to adjust the index manually + switch ( msg ) + { + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_XBUTTONDBLCLK: + if ( flags & MK_XBUTTON2 ) + msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN; + } + wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]); InitMouseEvent(event, x, y, flags); @@ -5810,6 +5833,8 @@ wxMouseState wxGetMouseState() ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON)); ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON)); ms.SetRightDown(wxIsKeyDown(VK_RBUTTON)); + ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1)); + ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2)); ms.SetControlDown(wxIsKeyDown(VK_CONTROL)); ms.SetShiftDown(wxIsKeyDown(VK_SHIFT)); @@ -6140,6 +6165,9 @@ const wxChar *wxGetMessageName(int message) case 0x0208: return wxT("WM_MBUTTONUP"); case 0x0209: return wxT("WM_MBUTTONDBLCLK"); case 0x020A: return wxT("WM_MOUSEWHEEL"); + case 0x020B: return wxT("WM_XBUTTONDOWN"); + case 0x020C: return wxT("WM_XBUTTONUP"); + case 0x020D: return wxT("WM_XBUTTONDBLCLK"); case 0x0210: return wxT("WM_PARENTNOTIFY"); case 0x0211: return wxT("WM_ENTERMENULOOP"); case 0x0212: return wxT("WM_EXITMENULOOP"); -- 2.45.2