API  1.0.0
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 
27 @global CPApp
28 @global CPNewlineCharacter
30 @global CPEnterCharacter
31 
32 @typedef DOMEvent
33 @typedef CPEventType
34 
35 
36 var _CPEventPeriodicEventPeriod = 0,
37  _CPEventPeriodicEventTimer = nil,
38  _CPEventUpperCaseRegex = new RegExp("[A-Z]"),
39  _CPEventStartupMilliseconds = new Date().getTime();
40 
45 @implementation CPEvent : CPObject
46 {
47  CPEventType _type;
48  CGPoint _location;
49  unsigned _modifierFlags;
50  CPTimeInterval _timestamp;
51  CPGraphicsContext _context;
52  int _eventNumber;
53  unsigned _clickCount;
54  float _pressure;
55  CPWindow _window;
56  Number _windowNumber;
57  CPString _characters;
58  CPString _charactersIgnoringModifiers;
59  BOOL _isARepeat;
60  unsigned _keyCode;
61  DOMEvent _DOMEvent;
62  int _data1;
63  int _data2;
64  short _subtype;
65 
66  float _deltaX;
67  float _deltaY;
68  float _deltaZ;
69  float _scrollingDeltaX;
70  float _scrollingDeltaY;
71  BOOL _hasPreciseScrollingDeltas;
72 
73 #if PLATFORM(DOM)
74  BOOL _suppressCappuccinoCut;
75  BOOL _suppressCappuccinoPaste;
76 #endif
77 
78  CPTrackingArea _trackingArea;
79 }
80 
84 + (CPTimeInterval)currentTimestamp
85 {
86  return (new Date().getTime() - _CPEventStartupMilliseconds) / 1000;
87 }
88 
106 + (CPEvent)keyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
107  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
108  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
109 {
110  return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
111  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
112  characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
113 }
114 
130 + (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
131  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
132  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
133 {
134  return [[self alloc] _initMouseEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
135  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
136 }
137 
152 + (id)enterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
153  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
154  eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
155 {
156  return [[self alloc] _initEnterExitEventWithType:anEventType location:aPoint modifierFlags:modifierFlags timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber trackingArea:aTrackingArea];
157 }
158 
174 + (CPEvent)otherEventWithType:(CPEventType)anEventType location:(CGPoint)aLocation modifierFlags:(unsigned)modifierFlags
175  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
176  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
177 {
178  return [[self alloc] _initOtherEventWithType:anEventType location:aLocation modifierFlags:modifierFlags
179  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
180 }
181 
182 - (id)_initWithType:(CPEventType)anEventType
183 {
184  if (self = [super init])
185  {
186  _type = anEventType;
187 
188  // Make sure these are 0 rather than nil.
189  _deltaX = 0;
190  _scrollingDeltaX = 0;
191  _deltaY = 0;
192  _scrollingDeltaY = 0;
193  _deltaZ = 0;
194  }
195 
196  return self;
197 }
198 
199 /* @ignore */
200 - (id)_initMouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
201  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
202  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
203 {
204  if (self = [self _initWithType:anEventType])
205  {
206  _location = CGPointCreateCopy(aPoint);
207  _modifierFlags = modifierFlags;
208  _timestamp = aTimestamp;
209  _context = aGraphicsContext;
210  _eventNumber = anEventNumber;
211  _clickCount = aClickCount;
212  _pressure = aPressure;
213  _window = [CPApp windowWithWindowNumber:aWindowNumber];
214  }
215 
216  return self;
217 }
218 
219 /* @ignore */
220 - (id)_initEnterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
221  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
222  eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
223 {
224  if ((anEventType != CPMouseEntered) && (anEventType != CPMouseExited) && (anEventType != CPCursorUpdate))
225  [CPException raise:CPInternalInconsistencyException reason:"Invalid event type"];
226 
227  if (self = [self _initWithType:anEventType])
228  {
229  _location = CGPointCreateCopy(aPoint);
230  _modifierFlags = modifierFlags;
231  _timestamp = aTimestamp;
232  _context = aGraphicsContext;
233  _eventNumber = anEventNumber;
234  _trackingArea = aTrackingArea;
235  _window = [CPApp windowWithWindowNumber:aWindowNumber];
236  }
237 
238  return self;
239 }
240 
241 /* @ignore */
242 - (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
243  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
244  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
245 {
246  if (self = [self _initWithType:anEventType])
247  {
248  _location = CGPointCreateCopy(aPoint);
249  _modifierFlags = modifierFlags;
250  _timestamp = aTimestamp;
251  _context = aGraphicsContext;
252  _characters = characters;
253  _charactersIgnoringModifiers = unmodCharacters;
254  _isARepeat = isARepeat;
255  _keyCode = code;
256  _windowNumber = aWindowNumber;
257  }
258 
259  return self;
260 }
261 
262 /* @ignore */
263 - (id)_initOtherEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
264  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
265  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
266 {
267  if (self = [self _initWithType:anEventType])
268  {
269  _location = CGPointCreateCopy(aPoint);
270  _modifierFlags = modifierFlags;
271  _timestamp = aTimestamp;
272  _context = aGraphicsContext;
273  _subtype = aSubtype;
274  _data1 = aData1;
275  _data2 = aData2;
276  _windowNumber = aWindowNumber;
277  }
278 
279  return self;
280 }
281 
290 - (CGPoint)locationInWindow
291 {
292  return CGPointMakeCopy(_location);
293 }
294 
295 - (CGPoint)globalLocation
296 {
297  var theWindow = [self window],
298  location = [self locationInWindow];
299 
300  if (theWindow)
301  return [theWindow convertBaseToGlobal:location];
302 
303  return location;
304 }
305 
309 - (unsigned)modifierFlags
310 {
311  return _modifierFlags;
312 }
313 
317 - (CPTimeInterval)timestamp
318 {
319  return _timestamp;
320 }
321 
325 - (CPEventType)type
326 {
327  return _type;
328 }
329 
333 - (CPEventType)subtype
334 {
335  return _subtype;
336 }
337 
341 - (CPWindow)window
342 {
343  if (!_window)
344  _window = [CPApp windowWithWindowNumber:_windowNumber];
345 
346  return _window;
347 }
348 
352 - (int)windowNumber
353 {
354  return _windowNumber;
355 }
356 
357 // Mouse Event Information
361 - (int)buttonNumber
362 {
363  if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
364  return 1;
365 
366  return 0;
367 }
368 
372 - (int)clickCount
373 {
374  return _clickCount;
375 }
376 
382 - (CPString)characters
383 {
384  return _characters;
385 }
386 
392 - (CPString)charactersIgnoringModifiers
393 {
394  return _charactersIgnoringModifiers;
395 }
396 
402 - (BOOL)isARepeat
403 {
404  return _isARepeat;
405 }
406 
412 - (unsigned short)keyCode
413 {
414  return _keyCode;
415 }
416 
417 + (CGPoint)mouseLocation
418 {
419  // FIXME: this is incorrect, we shouldn't depend on the current event.
420  var event = [CPApp currentEvent],
421  eventWindow = [event window];
422 
423  if (eventWindow)
424  return [eventWindow convertBaseToGlobal:[event locationInWindow]];
425 
426  return [event locationInWindow];
427 }
428 
429 - (float)pressure
430 {
431  return _pressure;
432 }
433 
434 /*
435  @ignore
436 */
437 - (DOMEvent)_DOMEvent
438 {
439  return _DOMEvent;
440 }
441 
442 - (int)data1
443 {
444  return _data1;
445 }
446 
447 - (int)data2
448 {
449  return _data2;
450 }
451 
452 // Getting Scroll Wheel Event Information
456 - (float)deltaX
457 {
458  return _deltaX;
459 }
460 
464 - (float)deltaY
465 {
466  return _deltaY;
467 }
468 
472 - (float)deltaZ
473 {
474  return _deltaZ;
475 }
476 
477 - (BOOL)hasPreciseScrollingDeltas
478 {
479  return !!_hasPreciseScrollingDeltas;
480 }
481 
487 - (float)scrollingDeltaX
488 {
489  return _scrollingDeltaX;
490 }
491 
497 - (float)scrollingDeltaY
498 {
499  return _scrollingDeltaY;
500 }
501 
502 - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
503 {
504  if (!aKeyEquivalent)
505  return NO;
506 
507  if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
508  aKeyEquivalentModifierMask |= CPShiftKeyMask;
509 
510  // Windows and Linux don't have command keys, so just switch it to ctrl.
511  if (!CPBrowserIsOperatingSystem(CPMacOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
512  {
513  aKeyEquivalentModifierMask |= CPControlKeyMask;
514  aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
515  }
516 
517  if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
518  return NO;
519 
520  // Treat \r and \n as the same key equivalent. See issue #710.
521  if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
522  return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
523 
524  return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
525 }
526 
527 - (BOOL)_couldBeKeyEquivalent
528 {
529  if (_type !== CPKeyDown)
530  return NO;
531 
532  var characterCount = _characters.length;
533 
534  if (!characterCount)
535  return NO;
536 
537  if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
538  return YES;
539 
540  // Cocoa allows almost any key as a key equivalent unless the first responder is a
541  // text field (presumably a subclass of NSText.)
542  var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
543 
544  // Some keys are accepted as key equivalents even if the first responder is a text
545  // field.
546  for (var i = 0; i < characterCount; i++)
547  {
548  var c = _characters.charAt(i);
549 
550  if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
551  c === CPEnterCharacter ||
552  c === CPNewlineCharacter ||
554  c === CPEscapeFunctionKey)
555  {
556  return YES;
557  }
558  }
559 
560  return !firstResponderIsText;
561 }
562 
571 - (BOOL)_platformIsEffectingCutOrPaste
572 {
573 #if PLATFORM(DOM)
574  return _suppressCappuccinoCut || _suppressCappuccinoPaste;
575 #else
576  return NO;
577 #endif
578 }
579 
580 
587 + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
588 {
589  _CPEventPeriodicEventPeriod = aPeriod;
590 
591  // FIXME: OH TIMERS!!!
592  _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
593 }
594 
598 + (void)stopPeriodicEvents
599 {
600  if (_CPEventPeriodicEventTimer === nil)
601  return;
602 
603  window.clearTimeout(_CPEventPeriodicEventTimer);
604 
605  _CPEventPeriodicEventTimer = nil;
606 }
607 
609 {
610  switch (_type)
611  {
612  case CPKeyDown:
613  case CPKeyUp:
614  case CPFlagsChanged:
615  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];
616  case CPLeftMouseDown:
617  case CPLeftMouseUp:
618  case CPRightMouseDown:
619  case CPRightMouseUp:
620  case CPMouseMoved:
621  case CPLeftMouseDragged:
622  case CPRightMouseDragged:
623  case CPMouseEntered:
624  case CPMouseExited:
625  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];
626  default:
627  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];
628  }
629 }
630 
631 - (CPTrackingArea)trackingArea
632 {
633  if ((_type !== CPMouseEntered) && (_type !== CPMouseExited) && (_type !== CPCursorUpdate))
634  [CPException raise:CPInternalInconsistencyException format:@"You can't call trackingArea for events of type %#x", _type];
635 
636  return _trackingArea;
637 }
638 
639 @end
640 
641 function _CPEventFirePeriodEvent()
642 {
643  [CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:CGPointMakeZero() modifierFlags:0 timestamp:[CPEvent currentTimestamp] windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
644 }
645 
647 
648 function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
649 {
650  aNativeEvent.isa = CPEventClass;
651 
652  aNativeEvent._type = anEventType;
653  aNativeEvent._location = aPoint;
654  aNativeEvent._modifierFlags = modifierFlags;
655  aNativeEvent._timestamp = aTimestamp;
656  aNativeEvent._windowNumber = aWindowNumber;
657  aNativeEvent._window = nil;
658  aNativeEvent._context = aGraphicsContext;
659  aNativeEvent._eventNumber = anEventNumber;
660  aNativeEvent._clickCount = aClickCount;
661  aNativeEvent._pressure = aPressure;
662 
663  return aNativeEvent;
664 }
Used to implement exception handling (creating & raising).
Definition: CPException.h:2
id init()
Definition: CALayer.j:126
CPModeSwitchFunctionKey
void raise:format:(CPString aName, [format] CPString aFormat, [,] ...)
Definition: CPException.j:77
CPOrderedSame
Definition: CPObjJRuntime.j:54
CPEnterCharacter
Definition: CPText.j:49
CPMouseExited
CGPoint locationInWindow()
Definition: CPEvent.j:290
void raise:reason:(CPString aName, [reason] CPString aReason)
Definition: CPException.j:66
CPCursorUpdate
CPMouseMoved
CPMouseEntered
CPAlternateKeyMask
An immutable string (collection of characters).
Definition: CPString.h:2
CPCommandKeyMask
CPRightMouseDragged
CPEscapeFunctionKey
CPFlagsChanged
CPKeyDown
CPWindow window()
Definition: CPEvent.j:341
int length()
Definition: CPString.j:186
CPLeftMouseUp
CPShiftKeyMask
CPEvent otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:(CPEventType anEventType, [location] CGPoint aLocation, [modifierFlags] unsigned modifierFlags, [timestamp] CPTimeInterval aTimestamp, [windowNumber] int aWindowNumber, [context] CPGraphicsContext aGraphicsContext, [subtype] short aSubtype, [data1] int aData1, [data2] int aData2)
Definition: CPEvent.j:174
int buttonNumber()
Definition: CPEvent.j:361
CPUpArrowFunctionKey
function CPBrowserIsOperatingSystem(anOperatingSystem)
CPLeftMouseDragged
CPNewlineCharacter
Definition: CPText.j:52
CPMacOperatingSystem
CPRightMouseUp
CPTimeInterval currentTimestamp()
Definition: CPEvent.j:84
CPLeftMouseDown
CPCarriageReturnCharacter
Definition: CPText.j:54
CPControlKeyMask
Definition: CPEvent.h:2
Class class()
Definition: CPObject.j:179
var CPEventClass
Definition: CPEvent.j:646
CPRightMouseDown
id alloc()
Definition: CPObject.j:130
id stringWithFormat:(CPString format, [,] ...)
Definition: CPString.j:166
FrameUpdater prototype description