API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPEvent.j
Go to the documentation of this file.
1 /*
2  * CPEvent.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 @class CPTextField
27 
28 @global CPApp
29 
30 var _CPEventPeriodicEventPeriod = 0,
31  _CPEventPeriodicEventTimer = nil,
32  _CPEventUpperCaseRegex = new RegExp("[A-Z]"),
33  _CPEventStartupMilliseconds = new Date().getTime();
34 
40 @implementation CPEvent : CPObject
41 {
42  CPEventType _type;
43  CGPoint _location;
44  unsigned _modifierFlags;
45  CPTimeInterval _timestamp;
46  CPGraphicsContext _context;
47  int _eventNumber;
48  unsigned _clickCount;
49  float _pressure;
50  CPWindow _window;
51  Number _windowNumber;
52  CPString _characters;
53  CPString _charactersIgnoringModifiers
54  BOOL _isARepeat;
55  unsigned _keyCode;
56  DOMEvent _DOMEvent;
57  int _data1;
58  int _data2;
59  short _subtype;
60 
61  float _deltaX;
62  float _deltaY;
63  float _deltaZ;
64 
65 #if PLATFORM(DOM)
66  BOOL _suppressCappuccinoCut;
67  BOOL _suppressCappuccinoPaste;
68 #endif
69 }
70 
74 + (CPTimeInterval)currentTimestamp
75 {
76  return (new Date().getTime() - _CPEventStartupMilliseconds) / 1000;
77 }
78 
96 + (CPEvent)keyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
97  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
98  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
99 {
100  return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
101  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
102  characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
103 }
104 
120 + (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
121  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
122  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
123 {
124  return [[self alloc] _initMouseEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
125  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
126 }
127 
143 + (CPEvent)otherEventWithType:(CPEventType)anEventType location:(CGPoint)aLocation modifierFlags:(unsigned)modifierFlags
144  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
145  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
146 {
147  return [[self alloc] _initOtherEventWithType:anEventType location:aLocation modifierFlags:modifierFlags
148  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
149 }
150 
151 - (id)_initWithType:(CPEventType)anEventType
152 {
153  if (self = [super init])
154  {
155  _type = anEventType;
156 
157  // Make sure these are 0 rather than nil.
158  _deltaX = 0;
159  _deltaY = 0;
160  _deltaZ = 0;
161  }
162 
163  return self;
164 }
165 
166 /* @ignore */
167 - (id)_initMouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
168  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
169  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
170 {
171  if (self = [self _initWithType:anEventType])
172  {
173  _location = CGPointCreateCopy(aPoint);
174  _modifierFlags = modifierFlags;
175  _timestamp = aTimestamp;
176  _context = aGraphicsContext;
177  _eventNumber = anEventNumber;
178  _clickCount = aClickCount;
179  _pressure = aPressure;
180  _window = [CPApp windowWithWindowNumber:aWindowNumber];
181  }
182 
183  return self;
184 }
185 
186 /* @ignore */
187 - (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
188  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
189  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
190 {
191  if (self = [self _initWithType:anEventType])
192  {
193  _location = CGPointCreateCopy(aPoint);
194  _modifierFlags = modifierFlags;
195  _timestamp = aTimestamp;
196  _context = aGraphicsContext;
197  _characters = characters;
198  _charactersIgnoringModifiers = unmodCharacters;
199  _isARepeat = isARepeat;
200  _keyCode = code;
201  _windowNumber = aWindowNumber;
202  }
203 
204  return self;
205 }
206 
207 /* @ignore */
208 - (id)_initOtherEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
209  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
210  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
211 {
212  if (self = [self _initWithType:anEventType])
213  {
214  _location = CGPointCreateCopy(aPoint);
215  _modifierFlags = modifierFlags;
216  _timestamp = aTimestamp;
217  _context = aGraphicsContext;
218  _subtype = aSubtype;
219  _data1 = aData1;
220  _data2 = aData2;
221  }
222 
223  return self;
224 }
225 
234 - (CGPoint)locationInWindow
235 {
236  return CGPointMakeCopy(_location);
237 }
238 
239 - (CGPoint)globalLocation
240 {
241  var theWindow = [self window],
242  location = [self locationInWindow];
243 
244  if (theWindow)
245  return [theWindow convertBaseToGlobal:location];
246 
247  return location;
248 }
249 
253 - (unsigned)modifierFlags
254 {
255  return _modifierFlags;
256 }
257 
261 - (CPTimeInterval)timestamp
262 {
263  return _timestamp;
264 }
265 
269 - (CPEventType)type
270 {
271  return _type;
272 }
273 
277 - (CPWindow)window
278 {
279  if (!_window)
280  _window = [CPApp windowWithWindowNumber:_windowNumber];
281 
282  return _window;
283 }
284 
288 - (int)windowNumber
289 {
290  return _windowNumber;
291 }
292 
293 // Mouse Event Information
297 - (int)buttonNumber
298 {
299  if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
300  return 1;
301 
302  return 0;
303 }
304 
308 - (int)clickCount
309 {
310  return _clickCount;
311 }
312 
318 - (CPString)characters
319 {
320  return _characters;
321 }
322 
328 - (CPString)charactersIgnoringModifiers
329 {
330  return _charactersIgnoringModifiers;
331 }
332 
338 - (BOOL)isARepeat
339 {
340  return _isARepeat;
341 }
342 
348 - (unsigned short)keyCode
349 {
350  return _keyCode;
351 }
352 
353 + (CGPoint)mouseLocation
354 {
355  // FIXME: this is incorrect, we shouldn't depend on the current event.
356  var event = [CPApp currentEvent],
357  eventWindow = [event window];
358 
359  if (eventWindow)
360  return [eventWindow convertBaseToGlobal:[event locationInWindow]];
361 
362  return [event locationInWindow];
363 }
364 
365 - (float)pressure
366 {
367  return _pressure;
368 }
369 
370 /*
371  @ignore
372 */
373 - (DOMEvent)_DOMEvent
374 {
375  return _DOMEvent;
376 }
377 
378 - (int)data1
379 {
380  return _data1;
381 }
382 
383 - (int)data2
384 {
385  return _data2;
386 }
387 
388 // Getting Scroll Wheel Event Information
392 - (float)deltaX
393 {
394  return _deltaX;
395 }
396 
400 - (float)deltaY
401 {
402  return _deltaY;
403 }
404 
408 - (float)deltaZ
409 {
410  return _deltaZ;
411 }
412 
413 - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
414 {
415  if (!aKeyEquivalent)
416  return NO;
417 
418  if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
419  aKeyEquivalentModifierMask |= CPShiftKeyMask;
420 
421  // Windows and Linux don't have command keys, so just switch it to ctrl.
422  if (!CPBrowserIsOperatingSystem(CPMacOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
423  {
424  aKeyEquivalentModifierMask |= CPControlKeyMask;
425  aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
426  }
427 
428  if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
429  return NO;
430 
431  // Treat \r and \n as the same key equivalent. See issue #710.
432  if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
433  return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
434 
435  return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
436 }
437 
438 - (BOOL)_couldBeKeyEquivalent
439 {
440  if (_type !== CPKeyDown)
441  return NO;
442 
443  var characterCount = _characters.length;
444 
445  if (!characterCount)
446  return NO;
447 
448  if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
449  return YES;
450 
451  // Cocoa allows almost any key as a key equivalent unless the first responder is a
452  // text field (presumably a subclass of NSText.)
453  var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
454 
455  // Some keys are accepted as key equivalents even if the first responder is a text
456  // field.
457  for (var i = 0; i < characterCount; i++)
458  {
459  var c = _characters.charAt(i);
460 
461  if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
462  c === CPEnterCharacter ||
463  c === CPNewlineCharacter ||
465  c === CPEscapeFunctionKey)
466  {
467  return YES;
468  }
469  }
470 
471  return !firstResponderIsText;
472 }
473 
482 - (BOOL)_platformIsEffectingCutOrPaste
483 {
484 #if PLATFORM(DOM)
485  return _suppressCappuccinoCut || _suppressCappuccinoPaste;
486 #else
487  return NO;
488 #endif
489 }
490 
491 
498 + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
499 {
500  _CPEventPeriodicEventPeriod = aPeriod;
501 
502  // FIXME: OH TIMERS!!!
503  _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
504 }
505 
509 + (void)stopPeriodicEvents
510 {
511  if (_CPEventPeriodicEventTimer === nil)
512  return;
513 
514  window.clearTimeout(_CPEventPeriodicEventTimer);
515 
516  _CPEventPeriodicEventTimer = nil;
517 }
518 
519 - (CPString)description
520 {
521  switch (_type)
522  {
523  case CPKeyDown:
524  case CPKeyUp:
525  case CPFlagsChanged:
526  return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ chars=\"%@\" unmodchars=\"%@\" repeat=%d keyCode=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _characters, _charactersIgnoringModifiers, _isARepeat, _keyCode];
527  case CPLeftMouseDown:
528  case CPLeftMouseUp:
529  case CPRightMouseDown:
530  case CPRightMouseUp:
531  case CPMouseMoved:
532  case CPLeftMouseDragged:
533  case CPRightMouseDragged:
534  case CPMouseEntered:
535  case CPMouseExited:
536  return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ evNum=%d click=%d buttonNumber=%d pressure=%f", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _eventNumber, _clickCount, [self buttonNumber], _pressure];
537  default:
538  return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ subtype=%d data1=%d data2=%d", _type, CGStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _subtype, _data1, _data2];
539  }
540 }
541 
542 @end
543 
544 function _CPEventFirePeriodEvent()
545 {
546  [CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:CGPointMakeZero() modifierFlags:0 timestamp:[CPEvent currentTimestamp] windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
547 }
548 
549 var CPEventClass = [CPEvent class];
550 
551 function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
552 {
553  aNativeEvent.isa = CPEventClass;
554 
555  aNativeEvent._type = anEventType;
556  aNativeEvent._location = aPoint;
557  aNativeEvent._modifierFlags = modifierFlags;
558  aNativeEvent._timestamp = aTimestamp;
559  aNativeEvent._windowNumber = aWindowNumber;
560  aNativeEvent._window = nil;
561  aNativeEvent._context = aGraphicsContext;
562  aNativeEvent._eventNumber = anEventNumber;
563  aNativeEvent._clickCount = aClickCount;
564  aNativeEvent._pressure = aPressure;
565 
566  return aNativeEvent;
567 }