[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Wheel Emulation and two wheel mices
From:       Antonio Larrosa =?iso-8859-1?q?Jim=E9nez?= <larrosa () kde ! org>
Date:       2001-05-11 17:57:46
[Download RAW message or body]

Hello,

I've send this mail to Keith Packard and qt-bugs@trolltech.com. After waiting 
some days with no response (not even the automatic response from trolltech)
I sent it again. Again, no response at all.
I don't know what to do about it, I suppose there's some problem with email
so I'll just post it here (kde-core-devel and xpert@xfree86.org), and please 
do whatever you want with the patches and tell me if it gets included in XFree 
and/or Qt (note that I'm not subscribed to xpert@xfree86.org, so please Cc: me
any answer). Sorry if this is not the appropiate list, I've never posted to an 
XFree list. Feel free to forward it to the appropiate list/person.

I've added support on XFree for the Trackman Marble FX's 4th button (in a
generic way, so that it can be used to emulate wheels in every mouse and is 
not specific to that model) and also added support for mice with two wheels 
(vertical and horizontal) on Qt.

I'll explain.

The purpose of that "4th button" is that when it's pressed and the user moves
the ball (it's a trackball), the mouse cursor doesn't move, but generates
wheel events to move _freely_ (vertically and horizontally) through the
document (like panning function that is usual on image viewers). This is done
by simulating vertical and horizontal wheels. Of course, this only worked
 with Windows (using Logitech's software) but now it also works for us :) and
 for any mouse.

The attached xfree86-emuwheel.diff file should be applied into
xc/programs/Xserver/hw/xfree86 . The patch adds a new option to the mouse
driver called "WheelButtonEmulation" used like this in XF86Config:
  Option        "Buttons"       "4"
  Option        "WheelButtonEmulation" "4"
  Option        "ZAxisMapping"  "4 5 6 7"

Each time the 4th button is pressed and the mouse is moved, the position
won't change, but the 4th, 5th, 6th and 7th buttons will be used as if they
were two wheels (4 and 5 -> vertical, 6 and 7 -> horizontal)

The patch should be clear, except maybe the emulateWheelType variable.
This is used because for my trackball, the 4th button state is not available
for mouse movements, but just when it's pressed or released, so it should be
handled different than all the other buttons, whose state is given for every
movement. I don't know how other mices with more than 3 buttons work, so I've
leaved this to be handled in each mouse type.

Note that I've preferred to make the button configurable just in case someone
prefers to use it with a traditional 3 button mouse by setting
"WheelButtonEmulation" to the middle button. What I don't have clear is if
there should be a
buttons &= ~pMse->emulateWheelButton;
above the
dz=dy; dw=dx;
line to "disable" the button. This may be neccesary for emulation with usual
buttons (left or right) but I've preferred to leave this decission to the
mantainer of that module.

This patch alone makes it possible to generate wheel events with any mouse in
a nice manner, but only vertical events are used by applications, so that's
why I've also patched Qt.

The patch for Qt allows it to understand horizontal wheel events so that you
can move completely freely for example in applications like konqueror, kmail,
etc.

I've extended the QWheelEvent class to support a Direction property that
specifies if it's a horizontal or vertical wheel event. Then, I've modified a
few widgets to support this property and use the appropiate scrollbar in each
case.

This has only one problem, there are Button4 and Button5 definitions in X.h
but there're no Button6 and Button7 definitions ! (note that they were used
even before my changes, with the dw variable in PostEvent). The X.h.diff
patch adds them, but I suppose that there should be other changes in that
file like adding a Button6Mask, Mod6Mask, Button6MotionMask, etc. so I've
decided to just use the values 6 and 7 in Qt instead of the definitions
Button6 and Button7.

Please, also note that before any of my changes, a horizontal wheel event
would generate a single click (as if it was the left button) as the
switch
{
  case Button1:
  ...
  case Button2:
  ...
  case Button3:
  ...

  case Button4:
  case Button5:
  ...

}

statement in qapplication_x11.cpp didn't have a default: case

There's just one problem with this approach in Qt: If a 3rd party application
reacts to a QWheelEvent event by itself (not using QScrollView::wheelEvent or
similar) and it isn't changed to support the direction property of the event
(for example, if a user only upgrades the library and not the app) then the
application will think it's receiving only vertical wheel events (and thus, 
scroll a bit randomly when moving the mouse while pressing the "emulation 
button") . I can modify all the applications on KDE's cvs, but everything else 
making use of QWheelEvent would need to be changed by the respective author.

Btw, the patch for XFree is against the current CVS, and the patch for Qt is
against the qt-copy module in KDE's cvs. I read a bit a recent snapshot of Qt
3.0 and it seems it can be applied there too mostly as it is.

I haven't modified the help files (in X, the documentation about the new
option, and in Qt, the developer documentation).

Well, I think that's all.

Opinions ?

Greetings,

--
Antonio Larrosa Jimenez
KDE Core developer  - larrosa@kde.org
SuSE Labs developer - larrosa@suse.de
http://perso.wanadoo.es/antlarr
KDE - The development framework of the future, today.




["xfree86-emuwheel.diff" (text/x-c)]

Index: input/mouse/mouse.c
===================================================================
RCS file: /cvs/xc/programs/Xserver/hw/xfree86/input/mouse/mouse.c,v
retrieving revision 1.41
diff -u -r1.41 mouse.c
--- input/mouse/mouse.c	2001/03/07 16:21:05	1.41
+++ input/mouse/mouse.c	2001/05/03 17:51:51
@@ -410,6 +410,20 @@
 		    pInfo->name, s);
 	}
     }
+
+    {
+	int b=0;
+	b = xf86SetIntOption(pInfo->options,
+			"WheelButtonEmulation", 0);
+
+	if (b) {
+	    pMse->emulateWheelButton = 1 << (b-1);
+	    pMse->emulateWheelType = (b > 3) ? 2 : 1;
+	} else {
+	    pMse->emulateWheelButton = 0;
+	    pMse->emulateWheelType = 0;
+	}
+    }
 }
 
 static InputInfoPtr
@@ -1020,6 +1034,7 @@
 
     pMse->protoBufTail = 0;
     pMse->inSync = 0;
+    pMse->isEmuWheel = 0;
 
     return TRUE;
 }
@@ -1353,6 +1368,11 @@
 		    dx = dy = 0;
 		    dz = (pBuf[2] & 0x08) ? (pBuf[2] & 0x0f) - 16 :
 					    (pBuf[2] & 0x0f);
+
+		    if (pMse->emulateWheelType==2) /* For the TrackMan MarbleFX
+							4th button */
+    		       pMse->isEmuWheel=(buttons & pMse->emulateWheelButton);
+
 		    break;
 		case 2:		/* Logitech reserves this packet type */
 		    /* 
@@ -1852,6 +1872,15 @@
 
 
     pMse = pInfo->private;
+
+    if (pMse->emulateWheelType==1)
+        pMse->isEmuWheel=(buttons & pMse->emulateWheelButton);
+
+    if (pMse->isEmuWheel)
+    {
+	   dz=dy; dw=dx;
+	   dx=0; dy=0;
+    }
 
     /* Map the Z axis movement. */
     /* XXX Could this go in the conversion_proc? */
Index: os-support/xf86OSmouse.h
===================================================================
RCS file: /cvs/xc/programs/Xserver/hw/xfree86/os-support/xf86OSmouse.h,v
retrieving revision 1.14
diff -u -r1.14 xf86OSmouse.h
--- os-support/xf86OSmouse.h	2001/03/07 16:21:04	1.14
+++ os-support/xf86OSmouse.h	2001/05/03 17:51:52
@@ -136,6 +136,13 @@
     unsigned char	protoBuf[8];
     unsigned char	protoPara[8];
     unsigned char	inSync;		/* driver in sync with datastream */
+    unsigned char	isEmuWheel;	/* emulating wheel */
+    int 		emulateWheelButton;/* button that emulates the wheel */
+    int 		emulateWheelType;/* 1 = button gives state for each 
+						move event.
+					    2 = button gives state when 
+						changing (should be handled in
+						each mouse type) */
     pointer		mousePriv;	/* private area */
     InputInfoPtr	pInfo;
     int			origProtocolID;

["X.h.diff" (text/x-c)]

Index: X.h
===================================================================
RCS file: /cvs/xc/include/X.h,v
retrieving revision 1.4
diff -u -r1.4 X.h
--- X.h	2001/01/17 17:53:09	1.4
+++ X.h	2001/05/03 16:23:51
@@ -261,6 +261,8 @@
 #define Button3			3
 #define Button4			4
 #define Button5			5
+#define Button6			6
+#define Button7			7
 
 /* Notify modes */
 

["qt-twowheels.diff" (text/x-c++)]

Index: kernel/qapplication_x11.cpp
===================================================================
RCS file: /home/kde/qt-copy/src/kernel/qapplication_x11.cpp,v
retrieving revision 1.40
diff -u -r1.40 qapplication_x11.cpp
--- kernel/qapplication_x11.cpp	2001/03/07 19:08:51	1.40
+++ kernel/qapplication_x11.cpp	2001/05/07 17:34:27
@@ -542,7 +542,7 @@
     bool translateConfigEvent( const XEvent * );
     bool translateCloseEvent( const XEvent * );
     bool translateScrollDoneEvent( const XEvent * );
-    bool translateWheelEvent( int global_x, int global_y, int delta, int state );
+    bool translateWheelEvent( int global_x, int global_y, int delta, int state, \
QWheelEvent::Direction dir );  };
 
 
@@ -3893,6 +3893,8 @@
 		break;
 	    case Button4:
 	    case Button5:
+	    case 6:
+	    case 7:
 		// the fancy mouse wheel.
 
 		// take care about grabbing.  We do this here since it
@@ -3923,11 +3925,19 @@
 		    // may offer a finer-resolution.  A positive delta
 		    // indicates forward rotation, a negative one
 		    // backward rotation respectively.
-		    delta *= 120*(event->xbutton.button == Button4?1:-1);
+		    delta *= 120*((event->xbutton.button == Button4 || 
+				  event->xbutton.button == 6 ) ?1:-1);
+		    
+		    QWheelEvent::Direction dir=
+			(event->xbutton.button == Button4 ||
+			event->xbutton.button == Button5 ) ?
+			QWheelEvent::Vertical : QWheelEvent::Horizontal;
 
-		    translateWheelEvent( globalPos.x(), globalPos.y(), delta, state );
+		    translateWheelEvent( globalPos.x(), globalPos.y(), delta, state, dir );
 		}
 		return TRUE;
+	    default:
+		return TRUE;
 	}
 	if ( event->type == ButtonPress ) {	// mouse button pressed
 	    qt_button_down = findChildWidget( this, pos );	//magic for masked widgets
@@ -4072,7 +4082,7 @@
 //
 // Wheel event translation
 //
-bool QETWidget::translateWheelEvent( int global_x, int global_y, int delta, int \
state ) +bool QETWidget::translateWheelEvent( int global_x, int global_y, int delta, \
int state, QWheelEvent::Direction dir )  {
     QWidget* w = this;
 
@@ -4091,7 +4101,7 @@
 	    popup->hide();
 	do {
 	    QWheelEvent e( w->mapFromGlobal(QPoint( global_x, global_y)),
-			   QPoint(global_x, global_y), delta, state );
+			   QPoint(global_x, global_y), delta, state, dir );
 	    e.ignore();
 	    QApplication::sendEvent( w, &e );
 	    if ( e.isAccepted() )
@@ -4105,7 +4115,7 @@
     if (w){
 	do {
 	    QWheelEvent e( w->mapFromGlobal(QPoint( global_x, global_y)),
-			   QPoint(global_x, global_y), delta, state );
+			   QPoint(global_x, global_y), delta, state, dir );
 	    e.ignore();
 	    QApplication::sendEvent( w, &e );
 	    if ( e.isAccepted() )
Index: kernel/qevent.cpp
===================================================================
RCS file: /home/kde/qt-copy/src/kernel/qevent.cpp,v
retrieving revision 1.25
diff -u -r1.25 qevent.cpp
--- kernel/qevent.cpp	2001/03/07 19:08:53	1.25
+++ kernel/qevent.cpp	2001/05/07 17:34:30
@@ -398,7 +398,7 @@
 */
 
 /*!
-  \fn QWheelEvent::QWheelEvent( const QPoint &pos, int delta, int state )
+  \fn QWheelEvent::QWheelEvent( const QPoint &pos, int delta, int state, Direction \
dir )  
   Constructs a wheel event object.
 
@@ -408,15 +408,16 @@
 
   \sa pos(), delta(), state()
 */
-QWheelEvent::QWheelEvent( const QPoint &pos, int delta, int state )
+QWheelEvent::QWheelEvent( const QPoint &pos, int delta, int state, 
+			Direction _dir )
     : QEvent(Wheel), p(pos), d(delta), s((ushort)state),
-      accpt(TRUE)
+      accpt(TRUE), dir(_dir)
 {
     g = QCursor::pos();
 }
 
 /*!
-  \fn QWheelEvent::QWheelEvent( const QPoint &pos, const QPoint&globalPos, int \
delta, int state ) +  \fn QWheelEvent::QWheelEvent( const QPoint &pos, const \
QPoint&globalPos, int delta, int state, Direction dir )  
   Constructs a wheel event object.
 
Index: kernel/qevent.h
===================================================================
RCS file: /home/kde/qt-copy/src/kernel/qevent.h,v
retrieving revision 1.25
diff -u -r1.25 qevent.h
--- kernel/qevent.h	2001/03/07 19:08:53	1.25
+++ kernel/qevent.h	2001/05/07 17:34:31
@@ -171,11 +171,15 @@
 class Q_EXPORT QWheelEvent : public QEvent
 {
 public:
-    QWheelEvent( const QPoint &pos, int delta, int state );
-    QWheelEvent( const QPoint &pos, const QPoint& globalPos, int delta, int state )
+    enum Direction { Horizontal, Vertical };
+
+    QWheelEvent( const QPoint &pos, int delta, int state,
+	 Direction _dir = Vertical );
+    QWheelEvent( const QPoint &pos, const QPoint& globalPos, int delta, int state, \
Direction _dir = Vertical )  : QEvent(Wheel), p(pos), g(globalPos), d(delta), \
                s((ushort)state),
-	  accpt(TRUE) {}
+	  accpt(TRUE), dir(_dir) {}
     int	   delta()	const	{ return d; }
+    Direction direction() const	{ return dir; }
     const QPoint &pos() const	{ return p; }
     const QPoint &globalPos() const	{ return g; }
     int	   x()		const	{ return p.x(); }
@@ -192,6 +196,7 @@
     int d;
     ushort s;
     bool   accpt;
+    Direction dir;
 };
 
 
Index: widgets/qmultilineedit.cpp
===================================================================
RCS file: /home/kde/qt-copy/src/widgets/qmultilineedit.cpp,v
retrieving revision 1.23
diff -u -r1.23 qmultilineedit.cpp
--- widgets/qmultilineedit.cpp	2001/03/07 19:08:59	1.23
+++ widgets/qmultilineedit.cpp	2001/05/07 17:35:05
@@ -1042,7 +1042,12 @@
 Passes wheel events to the vertical scrollbar.
 */
 void QMultiLineEdit::wheelEvent( QWheelEvent *e ){
-    QApplication::sendEvent( verticalScrollBar(), e);
+    if (e->direction()==QWheelEvent::Vertical) {
+           if (verticalScrollBar())
+              QApplication::sendEvent( verticalScrollBar(), e);
+        } else
+           if (horizontalScrollBar())
+              QApplication::sendEvent( horizontalScrollBar(), e);
 }
 
 
Index: widgets/qscrollview.cpp
===================================================================
RCS file: /home/kde/qt-copy/src/widgets/qscrollview.cpp,v
retrieving revision 1.31
diff -u -r1.31 qscrollview.cpp
--- widgets/qscrollview.cpp	2001/03/07 19:08:59	1.31
+++ widgets/qscrollview.cpp	2001/05/07 17:35:20
@@ -926,11 +926,15 @@
 */
 void QScrollView::wheelEvent( QWheelEvent *e ){
     QWheelEvent ce( viewport()->mapFromGlobal( e->globalPos() ),
-		    e->globalPos(), e->delta(), e->state());
+		    e->globalPos(), e->delta(), e->state(), e->direction());
     viewportWheelEvent(&ce);
     if ( !ce.isAccepted() ) {
-	if (verticalScrollBar())
-	    QApplication::sendEvent( verticalScrollBar(), e);
+	if (ce.direction()==QWheelEvent::Vertical) {
+	   if (verticalScrollBar())
+	      QApplication::sendEvent( verticalScrollBar(), e);
+	} else
+	   if (horizontalScrollBar())
+	      QApplication::sendEvent( horizontalScrollBar(), e);
     }
 }
 



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic