vfs: check userland buffers before reading them.
[haiku.git] / src / kits / shared / ShakeTrackingFilter.cpp
blobe486d100ad5dd05b6213773b174930ff1172e5a4
1 /*
2 * Copyright 2009, Alexandre Deckner, alex@zappotek.com
3 * Distributed under the terms of the MIT License.
4 */
6 /*!
7 \class ShakeTrackingFilter
8 \brief A simple mouse shake detection filter
10 * A simple mouse filter that detects quick mouse shakes.
12 * It's detecting rough edges (u-turns) in the mouse movement
13 * and counts them within a time window.
14 * You can configure the message sent, the u-turn count threshold
15 * and the time threshold.
16 * It sends the count along with the message.
17 * For now, detection is limited within the view bounds, but
18 * it might be modified to accept a BRegion mask.
23 #include <ShakeTrackingFilter.h>
25 #include <Message.h>
26 #include <Messenger.h>
27 #include <MessageRunner.h>
28 #include <View.h>
31 const uint32 kMsgCancel = 'Canc';
34 ShakeTrackingFilter::ShakeTrackingFilter(BView* targetView, uint32 messageWhat,
35 uint32 countThreshold, bigtime_t timeThreshold)
37 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
38 fTargetView(targetView),
39 fMessageWhat(messageWhat),
40 fCancelRunner(NULL),
41 fLowPass(8),
42 fLastDelta(0, 0),
43 fCounter(0),
44 fCountThreshold(countThreshold),
45 fTimeThreshold(timeThreshold)
50 ShakeTrackingFilter::~ShakeTrackingFilter()
52 delete fCancelRunner;
56 filter_result
57 ShakeTrackingFilter::Filter(BMessage* message, BHandler** /*_target*/)
59 if (fTargetView == NULL)
60 return B_DISPATCH_MESSAGE;
62 switch (message->what) {
63 case B_MOUSE_MOVED:
65 BPoint position;
66 message->FindPoint("be:view_where", &position);
68 // TODO: allow using BRegion masks
69 if (!fTargetView->Bounds().Contains(position))
70 return B_DISPATCH_MESSAGE;
72 fLowPass.Input(position - fLastPosition);
74 BPoint delta = fLowPass.Output();
76 // normalized dot product
77 float norm = delta.x * delta.x + delta.y * delta.y;
78 if (norm > 0.01) {
79 delta.x /= norm;
80 delta.y /= norm;
83 norm = fLastDelta.x * fLastDelta.x + fLastDelta.y * fLastDelta.y;
84 if (norm > 0.01) {
85 fLastDelta.x /= norm;
86 fLastDelta.y /= norm;
89 float dot = delta.x * fLastDelta.x + delta.y * fLastDelta.y;
91 if (dot < 0.0) {
92 if (fCounter == 0) {
93 BMessage * cancelMessage = new BMessage(kMsgCancel);
94 fCancelRunner = new BMessageRunner(BMessenger(fTargetView),
95 cancelMessage, fTimeThreshold, 1);
98 fCounter++;
100 if (fCounter >= fCountThreshold) {
101 BMessage shakeMessage(fMessageWhat);
102 shakeMessage.AddUInt32("count", fCounter);
103 BMessenger messenger(fTargetView);
104 messenger.SendMessage(&shakeMessage);
108 fLastDelta = fLowPass.Output();
109 fLastPosition = position;
111 return B_DISPATCH_MESSAGE;
114 case kMsgCancel:
115 delete fCancelRunner;
116 fCancelRunner = NULL;
117 fCounter = 0;
118 return B_SKIP_MESSAGE;
120 default:
121 break;
124 return B_DISPATCH_MESSAGE;
128 // #pragma mark -
131 LowPassFilter::LowPassFilter(uint32 size)
133 fSize(size)
135 fPoints = new BPoint[fSize];
139 LowPassFilter::~LowPassFilter()
141 delete [] fPoints;
145 void
146 LowPassFilter::Input(const BPoint& p)
148 // A fifo buffer that maintains a sum of its elements
149 fSum -= fPoints[0];
150 for (uint32 i = 0; i < fSize - 1; i++)
151 fPoints[i] = fPoints[i + 1];
152 fPoints[fSize - 1] = p;
153 fSum += p;
157 BPoint
158 LowPassFilter::Output() const
160 return BPoint(fSum.x / (float) fSize, fSum.y / (float) fSize);