/* NSEvent.m The event class Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley Author: Ovidiu Predescu Date: 1996 Author: Felipe A. Rodriguez Date: Sept 1998 This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include @implementation NSEvent // Class variables static NSString *timerKey = @"NSEventTimersKey"; // // Class methods // + (void)initialize { if (self == [NSEvent class]) { NSDebugLog(@"Initialize NSEvent class\n"); [self setVersion:1]; // Initial version } } // // Creating NSEvent objects // + (NSEvent *)enterExitEventWithType:(NSEventType)type location:(NSPoint)location modifierFlags:(unsigned int)flags timestamp:(NSTimeInterval)time windowNumber:(int)windowNum context:(GPSDrawContext *)context eventNumber:(int)eventNum trackingNumber:(int)trackingNum userData:(void *)userData { NSEvent *e = [[[NSEvent alloc] init] autorelease]; // do nothing if if ((type != NSMouseEntered) && (type != NSMouseExited) // event is not of && (type != NSCursorUpdate)) // a desired type return nil; e->event_type = type; // Set the event's e->location_point = location; // fields e->modifier_flags = flags; e->event_time = time; e->window_num = windowNum; e->event_context = context; e->event_data.tracking.event_num = eventNum; e->event_data.tracking.tracking_num = trackingNum; e->event_data.tracking.user_data = userData; return e; } + (NSEvent *)keyEventWithType:(NSEventType)type location:(NSPoint)location modifierFlags:(unsigned int)flags timestamp:(NSTimeInterval)time windowNumber:(int)windowNum context:(GPSDrawContext *)context characters:(NSString *)keys charactersIgnoringModifiers:(NSString *)ukeys isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code { NSEvent *e = [[[NSEvent alloc] init] autorelease]; // do nothing if if ((type != NSKeyDown) && (type != NSKeyUp)) // event is not of return nil; // a desired type e->event_type = type; // Set the event's e->location_point = location; // fields e->modifier_flags = flags; e->event_time = time; e->window_num = windowNum; e->event_context = context; [keys retain]; e->event_data.key.char_keys = keys; [ukeys retain]; e->event_data.key.unmodified_keys = ukeys; e->event_data.key.repeat = repeatKey; e->event_data.key.key_code = code; return e; } + (NSEvent *)mouseEventWithType:(NSEventType)type location:(NSPoint)location modifierFlags:(unsigned int)flags timestamp:(NSTimeInterval)time windowNumber:(int)windowNum context:(GPSDrawContext *)context eventNumber:(int)eventNum clickCount:(int)clickNum pressure:(float)pressureValue { NSEvent *e = [[[NSEvent alloc] init] autorelease]; // do nothing if // event is not of if ((type != NSMouseMoved) && (type != NSLeftMouseUp) // a desired type && (type != NSLeftMouseDown) && (type != NSRightMouseDown) && (type != NSRightMouseUp) && (type != NSLeftMouseDragged) && (type != NSRightMouseDragged)) return nil; e->event_type = type; // Set the event's e->location_point = location; // fields e->modifier_flags = flags; e->event_time = time; e->window_num = windowNum; e->event_context = context; e->event_data.mouse.event_num = eventNum; e->event_data.mouse.click = clickNum; e->event_data.mouse.pressure = pressureValue; return e; } + (NSEvent *)otherEventWithType:(NSEventType)type location:(NSPoint)location modifierFlags:(unsigned int)flags timestamp:(NSTimeInterval)time windowNumber:(int)windowNum context:(GPSDrawContext *)context subtype:(short)subType data1:(int)data1 data2:(int)data2 { NSEvent *e = [[[NSEvent alloc] init] autorelease]; // do nothing if if ((type != NSFlagsChanged) && (type != NSPeriodic)) // event is not of return nil; // a desired type e->event_type = type; // Set the event's e->location_point = location; // fields e->modifier_flags = flags; e->event_time = time; e->window_num = windowNum; e->event_context = context; e->event_data.misc.sub_type = subType; e->event_data.misc.data1 = data1; e->event_data.misc.data2 = data2; return e; } // // Requesting Periodic Events // + (void)startPeriodicEventsAfterDelay:(NSTimeInterval)delaySeconds withPeriod:(NSTimeInterval)periodSeconds { NSTimer* timer; NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary]; NSDebugLog (@"startPeriodicEventsAfterDelay:withPeriod:"); // Check this thread if ([dict objectForKey: timerKey]) // for a pending timer [NSException raise:NSInternalInconsistencyException format:@"Periodic events are already being generated for " @"this thread %x", [NSThread currentThread]]; // If the delay time is 0 then register // a timer immediately. Otherwise // register a timer with no repeat that if (!delaySeconds) // when fired registers the real timer timer = [NSTimer timerWithTimeInterval:periodSeconds // register an target:self // immediate selector:@selector(_timerFired:) // timer userInfo:nil repeats:YES]; else // register a one timer = [NSTimer timerWithTimeInterval:delaySeconds // shot timer to target:self // register a timer selector:@selector(_registerRealTimer:) userInfo:[NSNumber numberWithDouble:periodSeconds] repeats:NO]; [[NSRunLoop currentRunLoop] addTimer: timer forMode: NSEventTrackingRunLoopMode]; [dict setObject: timer forKey: timerKey]; } + (void)_timerFired:(NSTimer*)timer { NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceReferenceDate]; NSApplication *theApp = [NSApplication sharedApplication]; NSEvent* periodicEvent = [self otherEventWithType:NSPeriodic location:NSZeroPoint modifierFlags:0 timestamp:timeInterval windowNumber:0 context:[theApp context] subtype:0 data1:0 data2:0]; NSDebugLog (@"_timerFired:"); [theApp postEvent:periodicEvent atStart:NO]; // place a periodic } // event in the queue + (void)_registerRealTimer:(NSTimer*)timer // this method provides a { // means of delaying the NSTimer* realTimer; // start of periodic events NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary]; NSDebugLog (@"_registerRealTimer:"); realTimer = [NSTimer timerWithTimeInterval:[[timer userInfo] doubleValue] target:self selector:@selector(_timerFired:) userInfo:nil repeats:YES]; // Add the real timer to the timers // dictionary and to the run loop [dict setObject: realTimer forKey: timerKey]; [[NSRunLoop currentRunLoop] addTimer: realTimer forMode: NSEventTrackingRunLoopMode]; } + (void)stopPeriodicEvents { NSTimer* timer; NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary]; NSDebugLog (@"stopPeriodicEvents"); // Remove any existing timer = [dict objectForKey: timerKey]; // timer for this thread [timer invalidate]; [dict removeObjectForKey: timerKey]; } // // Instance methods // - (void)dealloc { if ((event_type == NSKeyUp) || (event_type == NSKeyDown)) { [event_data.key.char_keys release]; [event_data.key.unmodified_keys release]; } [super dealloc]; } // // Getting General Event Information // - (GPSDrawContext *)context { return event_context; } - (NSPoint)locationInWindow { return location_point; } - (unsigned int)modifierFlags { return modifier_flags; } - (NSTimeInterval)timestamp { return event_time; } - (NSEventType)type { return event_type; } - (NSWindow *)window { return [NSWindow windowWithNumber:window_num]; } - (int)windowNumber { return window_num; } // // Getting Key Event Information // - (NSString *)characters { if ((event_type != NSKeyUp) && (event_type != NSKeyDown)) return nil; return event_data.key.char_keys; } - (NSString *)charactersIgnoringModifiers { if ((event_type != NSKeyUp) && (event_type != NSKeyDown)) return nil; return event_data.key.unmodified_keys; } - (BOOL)isARepeat { if ((event_type != NSKeyUp) && (event_type != NSKeyDown)) return NO; return event_data.key.repeat; } - (unsigned short)keyCode { if ((event_type != NSKeyUp) && (event_type != NSKeyDown)) return 0; return event_data.key.key_code; } // // Getting Mouse Event Information // - (int)clickCount { // Make sure it is one of the right event types if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) && (event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) && (event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) && (event_type != NSMouseMoved)) return 0; return event_data.mouse.click; } - (int)eventNumber { // Make sure it is one of the right event types if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) && (event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) && (event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) && (event_type != NSMouseMoved) && (event_type != NSMouseEntered) && (event_type != NSMouseExited)) return 0; if ((event_type == NSMouseEntered) || (event_type == NSMouseExited)) return event_data.tracking.event_num; else return event_data.mouse.event_num; } - (float)pressure { // Make sure it is one of the right event types if ((event_type != NSLeftMouseDown) && (event_type != NSLeftMouseUp) && (event_type != NSRightMouseDown) && (event_type != NSRightMouseUp) && (event_type != NSLeftMouseDragged) && (event_type != NSRightMouseDragged) && (event_type != NSMouseMoved)) return 0; return event_data.mouse.pressure; } // // Getting Tracking Event Information // - (int)trackingNumber { if ((event_type != NSMouseEntered) && (event_type != NSMouseExited) && (event_type != NSCursorUpdate)) return 0; return event_data.tracking.tracking_num; } - (void *)userData { if ((event_type != NSMouseEntered) && (event_type != NSMouseExited) && (event_type != NSCursorUpdate)) return NULL; return event_data.tracking.user_data; } // // Getting Information about Specially Defined Events // - (int)data1 { // Make sure it is one of the right event types if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic)) return 0; return event_data.misc.data1; } - (int)data2 { // Make sure it is one of the right event types if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic)) return 0; return event_data.misc.data2; } - (short)subtype { // Make sure it is one of the right event types if ((event_type != NSFlagsChanged) && (event_type != NSPeriodic)) return 0; return event_data.misc.sub_type;; } // // NSCoding protocol // - (void)encodeWithCoder:aCoder { [aCoder encodeValueOfObjCType: @encode(NSEventType) at: &event_type]; [aCoder encodePoint: location_point]; [aCoder encodeValueOfObjCType: "I" at: &modifier_flags]; [aCoder encodeValueOfObjCType: @encode(NSTimeInterval) at: &event_time]; [aCoder encodeValueOfObjCType: "i" at: &window_num]; // We don't want to encode the context, right? // DPSContext doesn't conform to NSCoding //[aCoder encodeObjectReference: event_context withName: @"Context"]; // Encode the event date based upon the event type switch (event_type) { case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: case NSRightMouseUp: case NSMouseMoved: case NSLeftMouseDragged: case NSRightMouseDragged: [aCoder encodeValuesOfObjCTypes: "iif", &event_data.mouse.event_num, &event_data.mouse.click, &event_data.mouse.pressure]; break; case NSMouseEntered: case NSMouseExited: case NSCursorUpdate: // Can't do anything with the user_data!? [aCoder encodeValuesOfObjCTypes: "ii", &event_data.tracking.event_num, &event_data.tracking.tracking_num]; break; case NSKeyDown: case NSKeyUp: [aCoder encodeValueOfObjCType: @encode(BOOL) at: &event_data.key.repeat]; [aCoder encodeObject: event_data.key.char_keys]; [aCoder encodeObject: event_data.key.unmodified_keys]; [aCoder encodeValueOfObjCType: "S" at: &event_data.key.key_code]; break; case NSFlagsChanged: case NSPeriodic: [aCoder encodeValuesOfObjCTypes: "sii", &event_data.misc.sub_type, &event_data.misc.data1, &event_data.misc.data2]; break; } } - initWithCoder:aDecoder { [aDecoder decodeValueOfObjCType: @encode(NSEventType) at: &event_type]; location_point = [aDecoder decodePoint]; [aDecoder decodeValueOfObjCType: "I" at: &modifier_flags]; [aDecoder decodeValueOfObjCType: @encode(NSTimeInterval) at: &event_time]; [aDecoder decodeValueOfObjCType: "i" at: &window_num]; // Decode the event date based upon the event type switch (event_type) { case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: case NSRightMouseUp: case NSMouseMoved: case NSLeftMouseDragged: case NSRightMouseDragged: [aDecoder decodeValuesOfObjCTypes: "iif", &event_data.mouse.event_num, &event_data.mouse.click, &event_data.mouse.pressure]; break; case NSMouseEntered: case NSMouseExited: case NSCursorUpdate: // Can't do anything with the user_data!? [aDecoder decodeValuesOfObjCTypes: "ii", &event_data.tracking.event_num, &event_data.tracking.tracking_num]; break; case NSKeyDown: case NSKeyUp: [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &event_data.key.repeat]; event_data.key.char_keys = [aDecoder decodeObject]; event_data.key.unmodified_keys = [aDecoder decodeObject]; [aDecoder decodeValueOfObjCType: "S" at: &event_data.key.key_code]; break; case NSFlagsChanged: case NSPeriodic: [aDecoder decodeValuesOfObjCTypes: "sii", &event_data.misc.sub_type, &event_data.misc.data1, &event_data.misc.data2]; break; } return self; } - (NSString*)description { const char* eventTypes[] = { "leftMouseDown", "leftMouseUp", "rightMouseDown", "rightMouseUp", "mouseMoved", "leftMouseDragged", "rightMouseDragged", "mouseEntered", "mouseExited", "keyDown", "keyUp", "flagsChanged", "periodic", "cursorUpdate" }; switch (event_type) { case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: case NSRightMouseUp: case NSMouseMoved: case NSLeftMouseDragged: case NSRightMouseDragged: return [NSString stringWithFormat: @"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u," @" time = %f, window = %d, dpsContext = %p," @" event number = %d, click = %d, pressure = %f", eventTypes[event_type], location_point.x, location_point.y, modifier_flags, event_time, window_num, event_context, event_data.mouse.event_num, event_data.mouse.click, event_data.mouse.pressure]; break; case NSMouseEntered: case NSMouseExited: return [NSString stringWithFormat: @"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u," @" time = %f, window = %d, dpsContext = %p, " @" event number = %d, tracking number = %d, user data = %p", eventTypes[event_type], location_point.x, location_point.y, modifier_flags, event_time, window_num, event_context, event_data.tracking.event_num, event_data.tracking.tracking_num, event_data.tracking.user_data]; break; case NSKeyDown: case NSKeyUp: return [NSString stringWithFormat: @"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u," @" time = %f, window = %d, dpsContext = %p, " @" repeat = %s, keys = %@, ukeys = %@, keyCode = 0x%x", eventTypes[event_type], location_point.x, location_point.y, modifier_flags, event_time, window_num, event_context, (event_data.key.repeat ? "YES" : "NO"), event_data.key.char_keys, event_data.key.unmodified_keys, event_data.key.key_code]; break; case NSFlagsChanged: case NSPeriodic: case NSCursorUpdate: return [NSString stringWithFormat: @"NSEvent: eventType = %s, point = { %f, %f }, modifiers = %u," @" time = %f, window = %d, dpsContext = %p, " @" subtype = %d, data1 = %p, data2 = %p", eventTypes[event_type], location_point.x, location_point.y, modifier_flags, event_time, window_num, event_context, event_data.misc.sub_type, event_data.misc.data1, event_data.misc.data2]; break; } return [super description]; } @end