API  0.9.6
 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 
34 CPKeyDown = 10;
35 CPKeyUp = 11;
46 
47 // iPhone Event Types
52 
54 CPShiftKeyMask = 1 << 17;
55 CPControlKeyMask = 1 << 18;
57 CPCommandKeyMask = 1 << 20;
59 CPHelpKeyMask = 1 << 22;
62 
84 CPAnyEventMask = 0xffffffff;
85 
90 CPF1FunctionKey = "\uF704";
91 CPF2FunctionKey = "\uF705";
92 CPF3FunctionKey = "\uF706";
93 CPF4FunctionKey = "\uF707";
94 CPF5FunctionKey = "\uF708";
95 CPF6FunctionKey = "\uF709";
96 CPF7FunctionKey = "\uF70A";
97 CPF8FunctionKey = "\uF70B";
98 CPF9FunctionKey = "\uF70C";
99 CPF10FunctionKey = "\uF70D";
100 CPF11FunctionKey = "\uF70E";
101 CPF12FunctionKey = "\uF70F";
102 CPF13FunctionKey = "\uF710";
103 CPF14FunctionKey = "\uF711";
104 CPF15FunctionKey = "\uF712";
105 CPF16FunctionKey = "\uF713";
106 CPF17FunctionKey = "\uF714";
107 CPF18FunctionKey = "\uF715";
108 CPF19FunctionKey = "\uF716";
109 CPF20FunctionKey = "\uF717";
110 CPF21FunctionKey = "\uF718";
111 CPF22FunctionKey = "\uF719";
112 CPF23FunctionKey = "\uF71A";
113 CPF24FunctionKey = "\uF71B";
114 CPF25FunctionKey = "\uF71C";
115 CPF26FunctionKey = "\uF71D";
116 CPF27FunctionKey = "\uF71E";
117 CPF28FunctionKey = "\uF71F";
118 CPF29FunctionKey = "\uF720";
119 CPF30FunctionKey = "\uF721";
120 CPF31FunctionKey = "\uF722";
121 CPF32FunctionKey = "\uF723";
122 CPF33FunctionKey = "\uF724";
123 CPF34FunctionKey = "\uF725";
124 CPF35FunctionKey = "\uF726";
127 CPHomeFunctionKey = "\uF729";
129 CPEndFunctionKey = "\uF72B";
138 CPStopFunctionKey = "\uF734";
139 CPMenuFunctionKey = "\uF735";
140 CPUserFunctionKey = "\uF736";
149 CPPrevFunctionKey = "\uF73F";
150 CPNextFunctionKey = "\uF740";
153 CPUndoFunctionKey = "\uF743";
154 CPRedoFunctionKey = "\uF744";
155 CPFindFunctionKey = "\uF745";
156 CPHelpFunctionKey = "\uF746";
160 
161 
163 CPDOMEventMouseDown = "mousedown";
164 CPDOMEventMouseUp = "mouseup";
165 CPDOMEventMouseMoved = "mousemove";
167 CPDOMEventKeyUp = "keyup";
168 CPDOMEventKeyDown = "keydown";
169 CPDOMEventKeyPress = "keypress";
170 CPDOMEventCopy = "copy";
171 CPDOMEventPaste = "paste";
172 CPDOMEventScrollWheel = "mousewheel";
173 CPDOMEventTouchStart = "touchstart";
174 CPDOMEventTouchMove = "touchmove";
175 CPDOMEventTouchEnd = "touchend";
176 CPDOMEventTouchCancel = "touchcancel";
177 
178 var _CPEventPeriodicEventPeriod = 0,
179  _CPEventPeriodicEventTimer = nil,
180  _CPEventUpperCaseRegex = new RegExp("[A-Z]"),
181  _CPEventStartupMilliseconds = new Date().getTime();
182 
188 @implementation CPEvent : CPObject
189 {
190  CPEventType _type;
191  CPPoint _location;
192  unsigned _modifierFlags;
193  CPTimeInterval _timestamp;
194  CPGraphicsContext _context;
195  int _eventNumber;
196  unsigned _clickCount;
197  float _pressure;
198  CPWindow _window;
199  Number _windowNumber;
200  CPString _characters;
201  CPString _charactersIgnoringModifiers
202  BOOL _isARepeat;
203  unsigned _keyCode;
204  DOMEvent _DOMEvent;
205  int _data1;
206  int _data2;
207 
208  float _deltaX;
209  float _deltaY;
210  float _deltaZ;
211 }
212 
216 + (CPTimeInterval)currentTimestamp
217 {
218  return (new Date().getTime() - _CPEventStartupMilliseconds) / 1000;
219 }
220 
238 + (CPEvent)keyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
239  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
240  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
241 {
242  return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
243  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
244  characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
245 }
246 
262 + (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
263  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
264  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
265 {
266  return [[self alloc] _initMouseEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
267  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
268 }
269 
285 + (CPEvent)otherEventWithType:(CPEventType)anEventType location:(CGPoint)aLocation modifierFlags:(unsigned)modifierFlags
286  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
287  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
288 {
289  return [[self alloc] _initOtherEventWithType:anEventType location:aLocation modifierFlags:modifierFlags
290  timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
291 }
292 
293 - (id)_initWithType:(CPEventType)anEventType
294 {
295  if (self = [super init])
296  {
297  _type = anEventType;
298 
299  // Make sure these are 0 rather than nil.
300  _deltaX = 0;
301  _deltaY = 0;
302  _deltaZ = 0;
303  }
304 
305  return self;
306 }
307 
308 /* @ignore */
309 - (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
310  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
311  eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
312 {
313  if (self = [self _initWithType:anEventType])
314  {
315  _location = CPPointCreateCopy(aPoint);
316  _modifierFlags = modifierFlags;
317  _timestamp = aTimestamp;
318  _context = aGraphicsContext;
319  _eventNumber = anEventNumber;
320  _clickCount = aClickCount;
321  _pressure = aPressure;
322  _window = [CPApp windowWithWindowNumber:aWindowNumber];
323  }
324 
325  return self;
326 }
327 
328 /* @ignore */
329 - (id)_initKeyEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned int)modifierFlags
330  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
331  characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
332 {
333  if (self = [self _initWithType:anEventType])
334  {
335  _location = CPPointCreateCopy(aPoint);
336  _modifierFlags = modifierFlags;
337  _timestamp = aTimestamp;
338  _context = aGraphicsContext;
339  _characters = characters;
340  _charactersIgnoringModifiers = unmodCharacters;
341  _isARepeat = isARepeat;
342  _keyCode = code;
343  _windowNumber = aWindowNumber;
344  }
345 
346  return self;
347 }
348 
349 /* @ignore */
350 - (id)_initOtherEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
351  timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
352  subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
353 {
354  if (self = [self _initWithType:anEventType])
355  {
356  _location = CPPointCreateCopy(aPoint);
357  _modifierFlags = modifierFlags;
358  _timestamp = aTimestamp;
359  _context = aGraphicsContext;
360  _subtype = aSubtype;
361  _data1 = aData1;
362  _data2 = aData2;
363  }
364 
365  return self;
366 }
367 
376 - (CGPoint)locationInWindow
377 {
378  return _CGPointMakeCopy(_location);
379 }
380 
381 - (CGPoint)globalLocation
382 {
383  var theWindow = [self window],
384  location = [self locationInWindow];
385 
386  if (theWindow)
387  return [theWindow convertBaseToGlobal:location];
388 
389  return location;
390 }
391 
395 - (unsigned)modifierFlags
396 {
397  return _modifierFlags;
398 }
399 
403 - (CPTimeInterval)timestamp
404 {
405  return _timestamp;
406 }
407 
411 - (CPEventType)type
412 {
413  return _type;
414 }
415 
419 - (CPWindow)window
420 {
421  if (!_window)
422  _window = [CPApp windowWithWindowNumber:_windowNumber];
423 
424  return _window;
425 }
426 
430 - (int)windowNumber
431 {
432  return _windowNumber;
433 }
434 
435 // Mouse Event Information
439 - (int)buttonNumber
440 {
441  if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
442  return 1;
443 
444  return 0;
445 }
446 
450 - (int)clickCount
451 {
452  return _clickCount;
453 }
454 
460 - (CPString)characters
461 {
462  return _characters;
463 }
464 
470 - (CPString)charactersIgnoringModifiers
471 {
472  return _charactersIgnoringModifiers;
473 }
474 
480 - (BOOL)isARepeat
481 {
482  return _isARepeat;
483 }
484 
490 - (unsigned short)keyCode
491 {
492  return _keyCode;
493 }
494 
495 + (CGPoint)mouseLocation
496 {
497  // FIXME: this is incorrect, we shouldn't depend on the current event.
498  var event = [CPApp currentEvent],
499  eventWindow = [event window];
500 
501  if (eventWindow)
502  return [eventWindow convertBaseToGlobal:[event locationInWindow]];
503 
504  return [event locationInWindow];
505 }
506 
507 - (float)pressure
508 {
509  return _pressure;
510 }
511 
512 /*
513  @ignore
514 */
515 - (DOMEvent)_DOMEvent
516 {
517  return _DOMEvent;
518 }
519 
520 - (int)data1
521 {
522  return _data1;
523 }
524 
525 - (int)data2
526 {
527  return _data2;
528 }
529 
530 // Getting Scroll Wheel Event Information
534 - (float)deltaX
535 {
536  return _deltaX;
537 }
538 
542 - (float)deltaY
543 {
544  return _deltaY;
545 }
546 
550 - (float)deltaZ
551 {
552  return _deltaZ;
553 }
554 
555 - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
556 {
557  if (!aKeyEquivalent)
558  return NO;
559 
560  if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
561  aKeyEquivalentModifierMask |= CPShiftKeyMask;
562 
563  // Windows and Linux don't have command keys, so just switch it to ctrl.
564  if (!CPBrowserIsOperatingSystem(CPMacOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
565  {
566  aKeyEquivalentModifierMask |= CPControlKeyMask;
567  aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
568  }
569 
570  if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
571  return NO;
572 
573  // Treat \r and \n as the same key equivalent. See issue #710.
574  if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
575  return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
576 
577  return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
578 }
579 
580 - (BOOL)_couldBeKeyEquivalent
581 {
582  if (_type !== CPKeyDown)
583  return NO;
584 
585  var characterCount = _characters.length;
586 
587  if (!characterCount)
588  return NO;
589 
590  if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
591  return YES;
592 
593  // Cocoa allows almost any key as a key equivalent unless the first responder is a
594  // text field (presumably a subclass of NSText.)
595  var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
596 
597  // Some keys are accepted as key equivalents even if the first responder is a text
598  // field.
599  for (var i = 0; i < characterCount; i++)
600  {
601  var c = _characters.charAt(i);
602 
603  if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
604  c === CPEnterCharacter ||
605  c === CPNewlineCharacter ||
607  c === CPEscapeFunctionKey)
608  {
609  return YES;
610  }
611  }
612 
613  return !firstResponderIsText;
614 }
615 
622 + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
623 {
624  _CPEventPeriodicEventPeriod = aPeriod;
625 
626  // FIXME: OH TIMERS!!!
627  _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
628 }
629 
633 + (void)stopPeriodicEvents
634 {
635  if (_CPEventPeriodicEventTimer === nil)
636  return;
637 
638  window.clearTimeout(_CPEventPeriodicEventTimer);
639 
640  _CPEventPeriodicEventTimer = nil;
641 }
642 
643 - (CPString)description
644 {
645  switch (_type)
646  {
647  case CPKeyDown:
648  case CPKeyUp:
649  case CPFlagsChanged:
650  return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ chars=\"%@\" unmodchars=\"%@\" repeat=%d keyCode=%d", _type, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _characters, _charactersIgnoringModifiers, _isARepeat, _keyCode];
651  case CPLeftMouseDown:
652  case CPLeftMouseUp:
653  case CPRightMouseDown:
654  case CPRightMouseUp:
655  case CPMouseMoved:
656  case CPLeftMouseDragged:
657  case CPRightMouseDragged:
658  case CPMouseEntered:
659  case CPMouseExited:
660  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, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _eventNumber, _clickCount, [self buttonNumber], _pressure];
661  default:
662  return [CPString stringWithFormat:@"CPEvent: type=%d loc=%@ time=%.1f flags=0x%X win=%@ winNum=%d ctxt=%@ subtype=%d data1=%d data2=%d", _type, CPStringFromPoint(_location), _timestamp, _modifierFlags, _window, _windowNumber, _context, _subtype, _data1, _data2];
663  }
664 }
665 
666 @end
667 
668 function _CPEventFirePeriodEvent()
669 {
670  [CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:_CGPointMakeZero() modifierFlags:0 timestamp:[CPEvent currentTimestamp] windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
671 }
672 
674 
675 function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
676 {
677  aNativeEvent.isa = CPEventClass;
678 
679  aNativeEvent._type = anEventType;
680  aNativeEvent._location = aPoint;
681  aNativeEvent._modifierFlags = modifierFlags;
682  aNativeEvent._timestamp = aTimestamp;
683  aNativeEvent._windowNumber = aWindowNumber;
684  aNativeEvent._window = nil;
685  aNativeEvent._context = aGraphicsContext;
686  aNativeEvent._eventNumber = anEventNumber;
687  aNativeEvent._clickCount = aClickCount;
688  aNativeEvent._pressure = aPressure;
689 
690  return aNativeEvent;
691 }