Landing Recent QUIC Changes.
[chromium-blink-merge.git] / ui / events / test / cocoa_test_event_utils.mm
blobb27cd12259923336123469f0761ce4899ddd7dac
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <Cocoa/Cocoa.h>
6 #include <mach/mach_time.h>
8 #import "ui/events/keycodes/keyboard_code_conversion_mac.h"
9 #include "ui/events/test/cocoa_test_event_utils.h"
11 namespace cocoa_test_event_utils {
13 namespace {
15 // From
16 // http://stackoverflow.com/questions/1597383/cgeventtimestamp-to-nsdate
17 // Which credits Apple sample code for this routine.
18 uint64_t UpTimeInNanoseconds(void) {
19   uint64_t time;
20   uint64_t timeNano;
21   static mach_timebase_info_data_t sTimebaseInfo;
23   time = mach_absolute_time();
25   // Convert to nanoseconds.
27   // If this is the first time we've run, get the timebase.
28   // We can use denom == 0 to indicate that sTimebaseInfo is
29   // uninitialised because it makes no sense to have a zero
30   // denominator is a fraction.
31   if (sTimebaseInfo.denom == 0) {
32     (void) mach_timebase_info(&sTimebaseInfo);
33   }
35   // This could overflow; for testing needs we probably don't care.
36   timeNano = time * sTimebaseInfo.numer / sTimebaseInfo.denom;
37   return timeNano;
40 }  // namespace
42 NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
43                            NSUInteger modifiers) {
44   if (type == NSOtherMouseUp) {
45     // To synthesize middle clicks we need to create a CGEvent with the
46     // "center" button flags so that our resulting NSEvent will have the
47     // appropriate buttonNumber field. NSEvent provides no way to create a
48     // mouse event with a buttonNumber directly.
49     CGPoint location = { point.x, point.y };
50     CGEventRef cg_event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseUp,
51                                                   location,
52                                                   kCGMouseButtonCenter);
53     // Also specify the modifiers for the middle click case. This makes this
54     // test resilient to external modifiers being pressed.
55     CGEventSetFlags(cg_event, modifiers);
56     NSEvent* event = [NSEvent eventWithCGEvent:cg_event];
57     CFRelease(cg_event);
58     return event;
59   }
60   return [NSEvent mouseEventWithType:type
61                             location:point
62                        modifierFlags:modifiers
63                            timestamp:0
64                         windowNumber:0
65                              context:nil
66                          eventNumber:0
67                           clickCount:1
68                             pressure:1.0];
71 NSEvent* MouseEventWithType(NSEventType type, NSUInteger modifiers) {
72   return MouseEventAtPoint(NSZeroPoint, type, modifiers);
75 static NSEvent* MouseEventAtPointInWindow(NSPoint point,
76                                           NSEventType type,
77                                           NSWindow* window,
78                                           NSUInteger clickCount) {
79   return [NSEvent mouseEventWithType:type
80                             location:point
81                        modifierFlags:0
82                            timestamp:0
83                         windowNumber:[window windowNumber]
84                              context:nil
85                          eventNumber:0
86                           clickCount:clickCount
87                             pressure:1.0];
90 NSEvent* RightMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
91   return MouseEventAtPointInWindow(point, NSRightMouseDown, window, 1);
94 NSEvent* RightMouseDownAtPoint(NSPoint point) {
95   return RightMouseDownAtPointInWindow(point, nil);
98 NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
99   return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1);
102 NSEvent* LeftMouseDownAtPoint(NSPoint point) {
103   return LeftMouseDownAtPointInWindow(point, nil);
106 std::pair<NSEvent*,NSEvent*> MouseClickInView(NSView* view,
107                                               NSUInteger clickCount) {
108   const NSRect bounds = [view convertRect:[view bounds] toView:nil];
109   const NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
110   NSEvent* down = MouseEventAtPointInWindow(mid_point, NSLeftMouseDown,
111                                             [view window], clickCount);
112   NSEvent* up = MouseEventAtPointInWindow(mid_point, NSLeftMouseUp,
113                                           [view window], clickCount);
114   return std::make_pair(down, up);
117 NSEvent* KeyEventWithCharacter(unichar c) {
118   return KeyEventWithKeyCode(0, c, NSKeyDown, 0);
121 NSEvent* KeyEventWithType(NSEventType event_type, NSUInteger modifiers) {
122   return KeyEventWithKeyCode(0x78, 'x', event_type, modifiers);
125 NSEvent* KeyEventWithKeyCode(unsigned short key_code,
126                              unichar c,
127                              NSEventType event_type,
128                              NSUInteger modifiers) {
129   NSString* chars = [NSString stringWithCharacters:&c length:1];
130   return [NSEvent keyEventWithType:event_type
131                           location:NSZeroPoint
132                      modifierFlags:modifiers
133                          timestamp:0
134                       windowNumber:0
135                            context:nil
136                         characters:chars
137        charactersIgnoringModifiers:chars
138                          isARepeat:NO
139                            keyCode:key_code];
142 NSEvent* EnterExitEventWithType(NSEventType event_type) {
143   return [NSEvent enterExitEventWithType:event_type
144                                 location:NSZeroPoint
145                            modifierFlags:0
146                                timestamp:0
147                             windowNumber:0
148                                  context:nil
149                              eventNumber:0
150                           trackingNumber:0
151                                 userData:NULL];
154 NSEvent* OtherEventWithType(NSEventType event_type) {
155   return [NSEvent otherEventWithType:event_type
156                             location:NSZeroPoint
157                        modifierFlags:0
158                            timestamp:0
159                         windowNumber:0
160                              context:nil
161                              subtype:0
162                                data1:0
163                                data2:0];
166 NSTimeInterval TimeIntervalSinceSystemStartup() {
167   return UpTimeInNanoseconds() / 1000000000.0;
170 NSEvent* SynthesizeKeyEvent(NSWindow* window,
171                             bool keyDown,
172                             ui::KeyboardCode keycode,
173                             NSUInteger flags) {
174   unichar character;
175   unichar shifted_character;
176   int macKeycode = ui::MacKeyCodeForWindowsKeyCode(
177       keycode, flags, &shifted_character, &character);
179   if (macKeycode < 0)
180     return nil;
182   // Note that, in line with AppKit's documentation (and tracing "real" events),
183   // -[NSEvent charactersIngoringModifiers]" are "the characters generated by
184   // the receiving key event as if no modifier key (except for Shift)".
185   // So |charactersIgnoringModifiers| uses |shifted_character|.
186   NSString* charactersIgnoringModifiers =
187       [[[NSString alloc] initWithCharacters:&shifted_character
188                                      length:1] autorelease];
189   NSString* characters;
190   // The following were determined empirically on OSX 10.9.
191   if (flags & NSControlKeyMask) {
192     // If Ctrl is pressed, Cocoa always puts an empty string into |characters|.
193     characters = [NSString string];
194   } else if (flags & NSCommandKeyMask) {
195     // If Cmd is pressed, Cocoa puts a lowercase character into |characters|,
196     // regardless of Shift. If, however, Alt is also pressed then shift *is*
197     // preserved, but re-mappings for Alt are not implemented. Although we still
198     // need to support Alt for things like Alt+Left/Right which don't care.
199     characters =
200         [[[NSString alloc] initWithCharacters:&character length:1] autorelease];
201   } else {
202     // If just Shift or nothing is pressed, |characters| will match
203     // |charactersIgnoringModifiers|. Alt puts a special character into
204     // |characters| (not |charactersIgnoringModifiers|), but they're not mapped
205     // here.
206     characters = charactersIgnoringModifiers;
207   }
209   NSEventType type = (keyDown ? NSKeyDown : NSKeyUp);
211   // Modifier keys generate NSFlagsChanged event rather than
212   // NSKeyDown/NSKeyUp events.
213   if (keycode == ui::VKEY_CONTROL || keycode == ui::VKEY_SHIFT ||
214       keycode == ui::VKEY_MENU || keycode == ui::VKEY_COMMAND)
215     type = NSFlagsChanged;
217   // For events other than mouse moved, [event locationInWindow] is
218   // UNDEFINED if the event is not NSMouseMoved.  Thus, the (0,0)
219   // location should be fine.
220   NSEvent* event = [NSEvent keyEventWithType:type
221                                     location:NSZeroPoint
222                                modifierFlags:flags
223                                    timestamp:TimeIntervalSinceSystemStartup()
224                                 windowNumber:[window windowNumber]
225                                      context:nil
226                                   characters:characters
227                  charactersIgnoringModifiers:charactersIgnoringModifiers
228                                    isARepeat:NO
229                                      keyCode:(unsigned short)macKeycode];
231   return event;
234 }  // namespace cocoa_test_event_utils