LibreOffice Module apple_remote (master) 1
MultiClickRemoteBehavior.m
Go to the documentation of this file.
1/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*****************************************************************************
3 * MultiClickRemoteBehavior.m
4 * RemoteControlWrapper
5 *
6 * Created by Martin Kahr on 11.03.06 under a MIT-style license.
7 * Copyright (c) 2006 martinkahr.com. All rights reserved.
8 *
9 * Code modified and adapted to OpenOffice.org
10 * by Eric Bachard on 11.08.2008 under the same License
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 * THE SOFTWARE.
29 *
30 *****************************************************************************/
31
33
34static const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE = 0.35;
35static const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL = 0.4;
36
37@implementation MultiClickRemoteBehavior
38
39- (id) init {
40 if ( (self = [super init]) ) {
42 }
43 return self;
44}
45
46// Delegates are not retained!
47// http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/chapter_6_section_4.html
48// Delegating objects do not (and should not) retain their delegates.
49// However, clients of delegating objects (applications, usually) are responsible for ensuring that their delegates are around
50// to receive delegation messages. To do this, they may have to retain the delegate.
51- (void) setDelegate: (id) _delegate {
52 if ( _delegate && ( [_delegate respondsToSelector:@selector(remoteButton:pressedDown:clickCount:)] == NO )) return; // return what ?
53
54 delegate = _delegate;
55}
56- (id) delegate {
57 return delegate;
58}
59
61 return simulateHoldEvents;
62}
63- (void) setSimulateHoldEvent: (BOOL) value {
65}
66
67- (BOOL) simulatesHoldForButtonIdentifier: (RemoteControlEventIdentifier) identifier remoteControl: (RemoteControl*) remoteControl {
68 // we do that check only for the normal button identifiers as we would check for hold support for hold events instead
69 if (identifier > (1 << EVENT_TO_HOLD_EVENT_OFFSET)) return NO;
70
71 return [self simulateHoldEvent] && [remoteControl sendsEventForButtonIdentifier: (identifier << EVENT_TO_HOLD_EVENT_OFFSET)]==NO;
72}
73
75 return clickCountEnabledButtons != 0;
76}
77- (void) setClickCountingEnabled: (BOOL) value {
78 if (value) {
79 [self setClickCountEnabledButtons: kRemoteButtonPlus | kRemoteButtonMinus | kRemoteButtonPlay | kRemoteButtonLeft | kRemoteButtonRight | kRemoteButtonMenu | kMetallicRemote2009ButtonPlay | kMetallicRemote2009ButtonMiddlePlay];
80 } else {
81 [self setClickCountEnabledButtons: 0];
82 }
83}
84
85- (unsigned int) clickCountEnabledButtons {
87}
88- (void) setClickCountEnabledButtons: (unsigned int)value {
90}
91
92- (NSTimeInterval) maximumClickCountTimeDifference {
94}
95- (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff {
96 maxClickTimeDifference = timeDiff;
97}
98
99- (void) sendSimulatedHoldEvent: (id) time {
100 BOOL startSimulateHold = NO;
102 @synchronized(self) {
103 startSimulateHold = (lastHoldEvent>0 && lastHoldEventTime == [time doubleValue]);
104 }
105 if (startSimulateHold) {
107 event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
108 [delegate remoteButton:event pressedDown: YES clickCount: 1];
109 }
110}
111
112- (void) executeClickCountEvent: (NSArray*) values {
113 RemoteControlEventIdentifier event = [[values objectAtIndex: 0] unsignedIntValue];
114 NSTimeInterval eventTimePoint = [[values objectAtIndex: 1] doubleValue];
115
116 BOOL finishedClicking = NO;
117 int finalClickCount = eventClickCount;
118
119 @synchronized(self) {
120 finishedClicking = (event != lastClickCountEvent || eventTimePoint == lastClickCountEventTime);
121 if (finishedClicking) {
122 eventClickCount = 0;
125 }
126 }
127
128 if (finishedClicking) {
129 [delegate remoteButton:event pressedDown: YES clickCount:finalClickCount];
130 // trigger a button release event, too
131 [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
132 [delegate remoteButton:event pressedDown: NO clickCount:finalClickCount];
133 }
134}
135
136- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl {
137 if (!delegate) return;
138
139 BOOL clickCountingForEvent = ([self clickCountEnabledButtons] & event) == event;
140
141 if ([self simulatesHoldForButtonIdentifier: event remoteControl: remoteControl] && lastClickCountEvent==0) {
142 if (pressedDown) {
143 // wait to see if it is a hold
144 lastHoldEvent = event;
145 lastHoldEventTime = [NSDate timeIntervalSinceReferenceDate];
146 [self performSelector:@selector(sendSimulatedHoldEvent:)
147 withObject:[NSNumber numberWithDouble:lastHoldEventTime]
148 afterDelay:HOLD_RECOGNITION_TIME_INTERVAL];
149 return;
150 } else {
152 // it was a hold
153 // send an event for "hold release"
154 event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
155 lastHoldEvent = 0;
157
158 [delegate remoteButton:event pressedDown: pressedDown clickCount:1];
159 return;
160 } else {
162 @synchronized(self) {
163 lastHoldEvent = 0;
164 }
165
166 // in case click counting is enabled we have to setup the state for that, too
167 if (clickCountingForEvent) {
168 lastClickCountEvent = previousEvent;
170 NSNumber* eventNumber;
171 NSNumber* timeNumber;
172 eventClickCount = 1;
173 timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
174 eventNumber= [NSNumber numberWithUnsignedInt:previousEvent];
175 NSTimeInterval diffTime = maxClickTimeDifference-([NSDate timeIntervalSinceReferenceDate]-lastHoldEventTime);
176 [self performSelector: @selector(executeClickCountEvent:)
177 withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
178 afterDelay: diffTime];
179 // we do not return here because we are still in the press-release event
180 // that will be consumed below
181 } else {
182 // trigger the pressed down event that we consumed first
183 [delegate remoteButton:event pressedDown: YES clickCount:1];
184 }
185 }
186 }
187 }
188
189 if (clickCountingForEvent) {
190 if (pressedDown == NO) return;
191
192 NSNumber* eventNumber;
193 NSNumber* timeNumber;
194 @synchronized(self) {
195 lastClickCountEventTime = [NSDate timeIntervalSinceReferenceDate];
196 if (lastClickCountEvent == event) {
198 } else {
199 eventClickCount = 1;
200 }
201 lastClickCountEvent = event;
202 timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
203 eventNumber= [NSNumber numberWithUnsignedInt:event];
204 }
205 [self performSelector: @selector(executeClickCountEvent:)
206 withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
207 afterDelay: maxClickTimeDifference];
208 } else {
209 [delegate remoteButton:event pressedDown: pressedDown clickCount:1];
210 }
211
212}
213
214@end
215
216/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL
static const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE
#define EVENT_TO_HOLD_EVENT_OFFSET
Definition: RemoteControl.h:50
RemoteControlEventIdentifier
Definition: RemoteControl.h:54
BOOL sendsEventForButtonIdentifier:(RemoteControlEventIdentifier identifier)
Definition: RemoteControl.m:96
Any value
A behavior that adds multiclick and hold events on top of a device.
NSTimeInterval maximumClickCountTimeDifference()
RemoteControlEventIdentifier lastClickCountEvent
RemoteControlEventIdentifier lastHoldEvent
const wchar_t *typedef BOOL
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int