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