1
/****************************************************************************
5
Copyright (C) 1999-2002 Lubos Lunak <l.lunak@kde.org>
7
Distributed under the terms of the GNU General Public License version 2.
10
( libstroke - an X11 stroke interface library
11
Copyright (c) 1996,1997,1998,1999 Mark F. Willey, ETLA Technical
12
There is a reference application available on the LibStroke Home Page:
13
http://www.etla.net/~willey/projects/libstroke/ )
15
$Id: gestures.cpp,v 1.6.2.2 2004/03/15 13:38:21 lunakl Exp $
17
****************************************************************************/
19
#define _GESTURES_CPP_
33
#include <kapplication.h>
35
#include <kxerrorhandler.h>
36
#include <kkeynative.h>
43
Gesture* gesture_handler;
45
Gesture::Gesture( bool /*enabled_P*/, QObject* parent_P )
46
: _enabled( false ), recording( false ), button( 0 )
48
(void) new DeleteObject( this, parent_P );
49
assert( gesture_handler == NULL );
50
gesture_handler = this;
51
connect( &nostroke_timer, SIGNAL( timeout()), SLOT( stroke_timeout()));
57
gesture_handler = NULL;
60
void Gesture::enable( bool enabled_P )
62
if( _enabled == enabled_P )
65
assert( button != 0 );
69
void Gesture::update_grab()
71
if( _enabled && handlers.count() > 0 )
73
kapp->installX11EventFilter( this );
74
// CHECKME at se grabuje jen kdyz je alespon jedno gesto?
75
// + seznam oken, pro ktere nedelat grab?
81
kapp->removeX11EventFilter( this );
85
void Gesture::register_handler( QObject* receiver_P, const char* slot_P )
87
if( handlers.contains( receiver_P ))
89
handlers[ receiver_P ] = true;
90
connect( this, SIGNAL( handle_gesture( const QString& )),
92
if( handlers.count() == 1 )
96
void Gesture::unregister_handler( QObject* receiver_P, const char* slot_P )
98
if( !handlers.contains( receiver_P ))
100
handlers.remove( receiver_P );
101
disconnect( this, SIGNAL( handle_gesture( const QString& )),
102
receiver_P, slot_P );
103
if( handlers.count() == 0 )
107
bool Gesture::x11Event( XEvent* ev_P )
109
if( ev_P->type == ButtonPress && ev_P->xbutton.button == button )
111
kdDebug( 1217 ) << "GESTURE: mouse press" << endl;
113
stroke.record( ev_P->xbutton.x, ev_P->xbutton.y );
114
nostroke_timer.start( timeout, true );
116
start_x = ev_P->xbutton.x_root;
117
start_y = ev_P->xbutton.y_root;
120
else if( ev_P->type == ButtonRelease && ev_P->xbutton.button == button
124
nostroke_timer.stop();
125
stroke.record( ev_P->xbutton.x, ev_P->xbutton.y );
126
QString gesture( stroke.translate());
127
if( gesture.isEmpty())
129
kdDebug( 1217 ) << "GESTURE: replay" << endl;
130
XAllowEvents( qt_xdisplay(), AsyncPointer, CurrentTime );
131
XUngrabPointer( qt_xdisplay(), CurrentTime );
132
mouse_replay( true );
135
kdDebug( 1217 ) << "GESTURE: got: " << gesture << endl;
136
emit handle_gesture( gesture );
139
else if( ev_P->type == MotionNotify && recording )
140
{ // ignore small initial movement
141
if( nostroke_timer.isActive()
142
&& abs( start_x - ev_P->xmotion.x_root ) < 10
143
&& abs( start_y - ev_P->xmotion.y_root ) < 10 )
145
nostroke_timer.stop();
146
stroke.record( ev_P->xmotion.x, ev_P->xmotion.y );
151
void Gesture::stroke_timeout()
153
kdDebug( 1217 ) << "GESTURE: timeout" << endl;
154
XAllowEvents( qt_xdisplay(), AsyncPointer, CurrentTime );
155
XUngrabPointer( qt_xdisplay(), CurrentTime );
156
mouse_replay( false );
160
void Gesture::mouse_replay( bool release_P )
162
bool was_enabled = _enabled;
164
Mouse::send_mouse_button( button, release_P );
165
enable( was_enabled );
168
void Gesture::grab_mouse( bool grab_P )
172
KXErrorHandler handler;
173
static int mask[] = { 0, Button1MotionMask, Button2MotionMask, Button3MotionMask,
174
Button4MotionMask, Button5MotionMask, ButtonMotionMask, ButtonMotionMask,
175
ButtonMotionMask, ButtonMotionMask };
176
#define XCapL KKeyNative::modXLock()
177
#define XNumL KKeyNative::modXNumLock()
178
#define XScrL KKeyNative::modXScrollLock()
179
unsigned int mods[ 8 ] =
181
0, XCapL, XNumL, XNumL | XCapL,
182
XScrL, XScrL | XCapL,
183
XScrL | XNumL, XScrL | XNumL | XCapL
191
XGrabButton( qt_xdisplay(), button, mods[ i ], qt_xrootwin(), False,
192
ButtonPressMask | ButtonReleaseMask | mask[ button ], GrabModeAsync, GrabModeAsync,
194
bool err = handler.error( true );
195
kdDebug( 1217 ) << "Gesture grab:" << err << endl;
199
kdDebug( 1217 ) << "Gesture ungrab" << endl;
200
XUngrabButton( qt_xdisplay(), button, AnyModifier, qt_xrootwin());
204
void Gesture::set_mouse_button( unsigned int button_P )
206
if( button == button_P )
218
void Gesture::set_timeout( int timeout_P )
226
points = new point[ MAX_POINTS ]; // CHECKME
243
bool Stroke::record( int x, int y )
245
if( point_count >= MAX_POINTS )
247
if( point_count == -1 )
250
points[ point_count ].x = x;
251
points[ point_count ].y = y;
257
// interpolate between last and current point
258
int delx = x - points[ point_count ].x;
259
int dely = y - points[ point_count ].y;
260
if( abs( delx ) > abs( dely )) // step by the greatest delta direction
262
float iy = points[ point_count ].y;
263
// go from the last point to the current, whatever direction it may be
264
for( int ix = points[ point_count ].x;
265
( delx > 0 ) ? ( ix < x ) : ( ix > x );
266
( delx > 0 ) ? ++ix : --ix )
268
// step the other axis by the correct increment
270
iy -= fabs( dely / ( float ) delx );
272
iy += fabs( dely / ( float ) delx );
273
// add the interpolated point
275
if( point_count >= MAX_POINTS )
277
points[ point_count ].x = ix;
278
points[ point_count ].y = ( int )iy;
280
// add the last point
282
if( point_count >= MAX_POINTS )
284
points[ point_count ].x = x;
285
points[ point_count ].y = y;
286
// update metrics, it's ok to do it only for the last point
297
{ // same thing, but for dely larger than delx case...
298
float ix = points[ point_count ].x;
299
// go from the last point to the current, whatever direction it may be
300
for( int iy = points[ point_count ].y;
301
( dely > 0 ) ? ( iy < y ) : ( iy > y );
302
( dely > 0 ) ? ++iy : --iy )
304
// step the other axis by the correct increment
306
ix -= fabs( delx / ( float ) dely );
308
ix += fabs( delx / ( float ) dely );
309
// add the interpolated point
311
if( point_count >= MAX_POINTS )
313
points[ point_count ].x = ( int )ix;
314
points[ point_count ].y = iy;
316
// add the last point
318
if( point_count >= MAX_POINTS )
320
points[ point_count ].x = x;
321
points[ point_count ].y = y;
322
// update metrics, ts's ok to do it only for the last point
336
char* Stroke::translate( int min_bin_points_percentage_P, int scale_ratio_P, int min_points_P )
338
if( point_count < min_points_P )
340
// determine size of grid
341
delta_x = max_x - min_x;
342
delta_y = max_y - min_y;
343
if( delta_x > scale_ratio_P * delta_y )
345
int avg_y = ( max_y + min_y ) / 2;
346
min_y = avg_y - delta_x / 2;
347
max_y = avg_y + delta_x / 2;
348
delta_y = max_y - min_y;
350
else if( delta_y > scale_ratio_P * delta_x )
352
int avg_x = ( max_x + min_x ) / 2;
353
min_x = avg_x - delta_y / 2;
354
max_x = avg_x + delta_y / 2;
355
delta_x = max_x - min_x;
357
// calculate bin boundary positions
358
bound_x_1 = min_x + delta_x / 3;
359
bound_x_2 = min_x + 2 * delta_x / 3;
360
bound_y_1 = min_y + delta_y / 3;
361
bound_y_2 = min_y + 2 * delta_y / 3;
363
int sequence_count = 0;
364
// points-->sequence translation scratch variables
368
// build string by placing points in bins, collapsing bins and discarding
369
// those with too few points...
374
// figure out which bin the point falls in
375
current_bin = bin( points[ pos ].x, points[ pos ].y );
376
// if this is the first point, consider it the previous bin, too.
378
prev_bin = current_bin;
379
if( prev_bin == current_bin )
382
{ // we are moving to a new bin -- consider adding to the sequence
383
// CHECKME tohle taky konfigurovatelne ?
384
if( bin_count >= ( min_bin_points_percentage_P * point_count / 100 )
385
|| sequence_count == 0 )
387
if( sequence_count >= MAX_SEQUENCE )
389
ret_val[ sequence_count++ ] = prev_bin + '0';
391
// restart counting points in the new bin
393
prev_bin = current_bin;
397
// add the last run of points to the sequence
398
if( sequence_count >= MAX_SEQUENCE - 1 )
400
ret_val[ sequence_count++ ] = current_bin + '0';
401
ret_val[ sequence_count ] = 0; // endmark
405
/* figure out which bin the point falls in */
406
int Stroke::bin( int x, int y )
420
} // namespace KHotKeys
422
#include "gestures.moc"