mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-11 19:17:07 +00:00
A whole bunch of textfield and key event fixes.
This commit is contained in:
1 parent
1381bb5c54
commit
56a739655f
7 files changed
+506
-123
No files matched your search
+17
-2
@@ -319,7 +319,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
else
|
||||
{
|
||||
[[[CPApp mainWindow] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
[[[self keyWindow] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,13 +548,28 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
_currentEvent = anEvent;
|
||||
|
||||
var willPropagate = [[[anEvent window] platformWindow] _willPropagateCurrentDOMEvent];
|
||||
|
||||
// temporarily pretend we won't propagate the event. we'll restore the saved value later
|
||||
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
|
||||
// Check if this is a candidate for key equivalent...
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
||||
{
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
var characters = [anEvent characters],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Unconditionally propagate on these keys to solve browser copy paste bugs
|
||||
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if we make it this far, then restore the original willPropagate value
|
||||
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
||||
|
||||
if (_eventListeners.length)
|
||||
{
|
||||
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
|
||||
|
||||
@@ -31,6 +31,11 @@ CPKHTMLBrowserEngine = 3;
|
||||
CPOperaBrowserEngine = 4;
|
||||
CPWebKitBrowserEngine = 5;
|
||||
|
||||
// Operating Systems
|
||||
CPMacOperatingSystem = 0;
|
||||
CPWindowsOperatingSystem = 1;
|
||||
CPOtherOperatingSystem = 2;
|
||||
|
||||
// Features
|
||||
CPCSSRGBAFeature = 1 << 5;
|
||||
|
||||
@@ -183,11 +188,20 @@ function CPFeatureIsCompatible(aFeature)
|
||||
|
||||
function CPBrowserIsEngine(anEngine)
|
||||
{
|
||||
return PLATFORM_ENGINE == anEngine;
|
||||
return PLATFORM_ENGINE === anEngine;
|
||||
}
|
||||
|
||||
if (USER_AGENT.indexOf("Mac") != -1)
|
||||
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
||||
{
|
||||
return OPERATING_SYSTEM === anOperatingSystem;
|
||||
}
|
||||
|
||||
OPERATING_SYSTEM = CPOtherOperatingSystem;
|
||||
|
||||
if (USER_AGENT.indexOf("Mac") !== -1)
|
||||
{
|
||||
OPERATING_SYSTEM = CPMacOperatingSystem;
|
||||
|
||||
CPPlatformActionKeyMask = CPCommandKeyMask;
|
||||
|
||||
CPUndoKeyEquivalent = @"Z";
|
||||
@@ -198,6 +212,9 @@ if (USER_AGENT.indexOf("Mac") != -1)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (USER_AGENT.indexOf("Windows") !== -1)
|
||||
OPERATING_SYSTEM = CPWindowsOperatingSystem;
|
||||
|
||||
CPPlatformActionKeyMask = CPControlKeyMask;
|
||||
|
||||
CPUndoKeyEquivalent = @"Z";
|
||||
|
||||
+18
-2
@@ -639,6 +639,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
else
|
||||
[[self window] selectNextKeyView:self];
|
||||
|
||||
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
|
||||
[[[self window] firstResponder] selectText:self];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
else
|
||||
@@ -781,11 +784,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement];
|
||||
|
||||
if (element.parentNode === _DOMElement && ([self isEditable] || [self isSelectable]))
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
if (([self isEditable] || [self isSelectable]))
|
||||
{
|
||||
if ([[self window] firstResponder] === self)
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
else
|
||||
{
|
||||
[[self window] makeFirstResponder:self];
|
||||
window.setTimeout(function() {[self selectText:sender];}, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
{
|
||||
[self selectText:sender];
|
||||
}
|
||||
|
||||
#pragma mark Setting the Delegate
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
|
||||
@@ -1738,6 +1738,9 @@ CPTexturedBackgroundWindowMask
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillCloseNotification object:self];
|
||||
|
||||
[self orderOut:nil];
|
||||
|
||||
if ([self isFullBridge])
|
||||
[[self platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
// Managing Main Status
|
||||
|
||||
@@ -30,6 +30,10 @@ var PrimaryPlatformWindow = NULL;
|
||||
|
||||
Object _charCodes;
|
||||
unsigned _keyCode;
|
||||
unsigned _lastKey;
|
||||
BOOL _capsLockActive;
|
||||
BOOL _ignoreNativeCopyOrCutEvent;
|
||||
BOOL _ignoreNativePastePreparation;
|
||||
|
||||
BOOL _DOMEventMode;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
* until the first key is released. This can cause a key event to be fired with
|
||||
* a keyCode for the first key and a charCode for the second key.
|
||||
*
|
||||
* Safari in keypress
|
||||
* Safari 2 in keypress (not supported)
|
||||
*
|
||||
* charCode keyCode which
|
||||
* ENTER: 13 13 13
|
||||
@@ -117,27 +117,10 @@
|
||||
|
||||
@import "CPPlatform.j"
|
||||
@import "CPPlatformWindow.j"
|
||||
@import "CPPlatformWindow+DOMKeys.j"
|
||||
|
||||
#import "../../CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var DoubleClick = "dblclick",
|
||||
MouseDown = "mousedown",
|
||||
MouseUp = "mouseup",
|
||||
MouseMove = "mousemove",
|
||||
MouseDrag = "mousedrag",
|
||||
KeyUp = "keyup",
|
||||
KeyDown = "keydown",
|
||||
KeyPress = "keypress",
|
||||
Copy = "copy",
|
||||
Paste = "paste",
|
||||
Resize = "resize",
|
||||
ScrollWheel = "mousewheel",
|
||||
TouchStart = "touchstart",
|
||||
TouchMove = "touchmove",
|
||||
TouchEnd = "touchend",
|
||||
TouchCancel = "touchcancel";
|
||||
|
||||
// Define up here so compressor knows about em.
|
||||
var CPDOMEventGetClickCount,
|
||||
CPDOMEventStop,
|
||||
@@ -148,9 +131,12 @@ var CPDOMEventGetClickCount,
|
||||
//might be mac only, we should investigate futher later.
|
||||
var KeyCodesToPrevent = {},
|
||||
CharacterKeysToPrevent = {},
|
||||
KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '33':1, '34':1, '35':1, '36':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 };
|
||||
MozKeyCodeToKeyCodeMap = {
|
||||
61: 187, // =, equals
|
||||
59: 186 // ;, semicolon
|
||||
};
|
||||
|
||||
var CTRL_KEY_CODE = 17;
|
||||
KeyCodesToPrevent[CPKeyCodes.A] = YES;
|
||||
|
||||
var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
@@ -251,6 +237,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
_DOMBodyElement.webkitTouchCallout = "none";
|
||||
|
||||
// This guy fixes an issue in Firefox where if you focus the URL field, we stop getting key events
|
||||
_DOMFocusElement = theDocument.createElement("input");
|
||||
|
||||
_DOMFocusElement.style.position = "absolute";
|
||||
@@ -261,11 +248,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_DOMBodyElement.appendChild(_DOMFocusElement);
|
||||
|
||||
// Create Native Pasteboard handler.
|
||||
_DOMPasteboardElement = theDocument.createElement("input");
|
||||
_DOMPasteboardElement = theDocument.createElement("textarea");
|
||||
|
||||
_DOMPasteboardElement.style.position = "absolute";
|
||||
_DOMPasteboardElement.style.top = "-10000px";
|
||||
_DOMPasteboardElement.style.zIndex = "99";
|
||||
_DOMPasteboardElement.style.zIndex = "999";
|
||||
|
||||
_DOMBodyElement.appendChild(_DOMPasteboardElement);
|
||||
|
||||
@@ -283,6 +270,14 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
|
||||
resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
|
||||
|
||||
copyEventSelector = @selector(copyEvent:),
|
||||
copyEventImplementation = class_getMethodImplementation(theClass, copyEventSelector),
|
||||
copyEventCallback = function (anEvent) {copyEventImplementation(self, nil, anEvent); },
|
||||
|
||||
pasteEventSelector = @selector(pasteEvent:),
|
||||
pasteEventImplementation = class_getMethodImplementation(theClass, pasteEventSelector),
|
||||
pasteEventCallback = function (anEvent) {pasteEventImplementation(self, nil, anEvent); },
|
||||
|
||||
keyEventSelector = @selector(keyEvent:),
|
||||
keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector),
|
||||
keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); },
|
||||
@@ -299,6 +294,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
|
||||
touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); };
|
||||
|
||||
|
||||
if (theDocument.addEventListener)
|
||||
{
|
||||
if ([CPPlatform supportsDragAndDrop])
|
||||
@@ -315,6 +311,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
theDocument.addEventListener("mousedown", mouseEventCallback, NO);
|
||||
theDocument.addEventListener("mousemove", mouseEventCallback, NO);
|
||||
|
||||
theDocument.addEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.addEventListener("beforecut", copyEventCallback, NO);
|
||||
theDocument.addEventListener("beforepaste", pasteEventCallback, NO);
|
||||
|
||||
theDocument.addEventListener("keyup", keyEventCallback, NO);
|
||||
theDocument.addEventListener("keydown", keyEventCallback, NO);
|
||||
theDocument.addEventListener("keypress", keyEventCallback, NO);
|
||||
@@ -342,6 +342,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
theDocument.removeEventListener("keydown", keyEventCallback, NO);
|
||||
theDocument.removeEventListener("keypress", keyEventCallback, NO);
|
||||
|
||||
theDocument.removeEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.removeEventListener("beforecut", copyEventCallback, NO);
|
||||
theDocument.removeEventListener("beforepaste", pasteEventCallback, NO);
|
||||
|
||||
theDocument.removeEventListener("touchstart", touchEventCallback, NO);
|
||||
theDocument.removeEventListener("touchend", touchEventCallback, NO);
|
||||
theDocument.removeEventListener("touchmove", touchEventCallback, NO);
|
||||
@@ -538,12 +542,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
|
||||
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
|
||||
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
|
||||
|
||||
|
||||
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
|
||||
StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
|
||||
|
||||
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
|
||||
StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
|
||||
CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
|
||||
KeyCodesToPrevent[aDOMEvent.keyCode];
|
||||
KeyCodesToPrevent[aDOMEvent.keyCode]);
|
||||
|
||||
var isNativePasteEvent = NO,
|
||||
isNativeCopyOrCutEvent = NO,
|
||||
@@ -552,56 +555,80 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
switch (aDOMEvent.type)
|
||||
{
|
||||
case "keydown": // Grab and store the keycode now since it is correct and consistent at this point.
|
||||
_keyCode = aDOMEvent.keyCode;
|
||||
if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap)
|
||||
_keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode];
|
||||
else
|
||||
_keyCode = aDOMEvent.keyCode;
|
||||
|
||||
var characters = String.fromCharCode(_keyCode).toLowerCase();
|
||||
overrideCharacters = modifierFlags & CPShiftKeyMask ? characters.toUpperCase() : characters;
|
||||
|
||||
// If this could be a native PASTE event, then we need to further examine it before
|
||||
// sending a CPEvent. Select our element to see if anything gets pasted in it.
|
||||
if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask))
|
||||
overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters;
|
||||
|
||||
// check for caps lock state
|
||||
if (_keyCode === CPKeyCodes.CAPS_LOCK)
|
||||
_capsLockActive = YES;
|
||||
|
||||
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask | CPAlternateKeyMask))
|
||||
{
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
|
||||
isNativePasteEvent = YES;
|
||||
//we are simply going to skip all keypress events that use cmd/ctrl key
|
||||
//this lets us be consistent in all browsers and send on the keydown
|
||||
//which means we can cancel the event early enough, but only if sendEvent needs to
|
||||
|
||||
var eligibleForCopyPaste = [self _validateCopyCutOrPasteEvent:aDOMEvent flags:modifierFlags];
|
||||
|
||||
// If this could be a native PASTE event, then we need to further examine it before
|
||||
// sending a CPEvent. Select our element to see if anything gets pasted in it.
|
||||
if (characters === "v" && eligibleForCopyPaste)
|
||||
{
|
||||
if (!_ignoreNativePastePreparation)
|
||||
{
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
}
|
||||
|
||||
isNativePasteEvent = YES;
|
||||
}
|
||||
|
||||
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
|
||||
// can capture our internal Cappuccino pasteboard.
|
||||
else if ((characters == "c" || characters == "x") && eligibleForCopyPaste)
|
||||
{
|
||||
isNativeCopyOrCutEvent = YES;
|
||||
|
||||
if (_ignoreNativeCopyOrCutEvent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (CPKeyCodes.firesKeyPressEvent(_keyCode, _lastKey, aDOMEvent.shiftKey, aDOMEvent.ctrlKey, aDOMEvent.altKey))
|
||||
{
|
||||
// this branch is taken by events which fire keydown, keypress, and keyup.
|
||||
// this is the only time we'll ALLOW character keys to propagate (needed for text fields)
|
||||
StopDOMEventPropagation = NO;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//this branch is taken by "remedial" key events
|
||||
// In this state we continue to keypress and send the CPEvent
|
||||
}
|
||||
|
||||
// Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have
|
||||
// a complete set of information yet.
|
||||
|
||||
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
|
||||
// can capture our internal Cappuccino pasteboard.
|
||||
else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
|
||||
isNativeCopyOrCutEvent = YES;
|
||||
case "keypress":
|
||||
// we unconditionally break on keypress events with modifiers,
|
||||
// because we forced the event to be sent on the keydown
|
||||
if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask | CPAlternateKeyMask)))
|
||||
break;
|
||||
|
||||
// Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events.
|
||||
// So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support...
|
||||
else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
|
||||
return;
|
||||
|
||||
// Or, if this is not one of those special keycodes, and also not a ctrl+event
|
||||
else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
|
||||
return;
|
||||
|
||||
// If this is in fact our broke state, continue to keypress and send the keydown.
|
||||
case "keypress": // If the source of this event is our pasteboard element, then simply let it continue
|
||||
// as normal, so that the paste event can successfully complete.
|
||||
|
||||
if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
|
||||
return;
|
||||
|
||||
var keyCode = _keyCode,
|
||||
charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
|
||||
isARepeat = (_charCodes[keyCode] != nil);
|
||||
|
||||
_lastKey = keyCode;
|
||||
_charCodes[keyCode] = charCode;
|
||||
|
||||
var characters = overrideCharacters || String.fromCharCode(charCode),
|
||||
charactersIgnoringModifiers = characters.toLowerCase();
|
||||
|
||||
// Safari won't send proper capitalization during cmd-key events
|
||||
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && (modifierFlags & CPShiftKeyMask))
|
||||
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive))
|
||||
characters = characters.toUpperCase();
|
||||
|
||||
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
|
||||
@@ -612,7 +639,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
{
|
||||
_pasteboardKeyDownEvent = event;
|
||||
window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -620,12 +646,20 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
case "keyup": var keyCode = aDOMEvent.keyCode,
|
||||
charCode = _charCodes[keyCode];
|
||||
|
||||
_keyCode = -1;
|
||||
_lastKey = -1;
|
||||
_charCodes[keyCode] = nil;
|
||||
|
||||
_ignoreNativeCopyOrCutEvent = NO;
|
||||
_ignoreNativePastePreparation = NO;
|
||||
|
||||
// check for caps lock state
|
||||
if (keyCode === CPKeyCodes.CAPS_LOCK)
|
||||
_capsLockActive = NO;
|
||||
|
||||
var characters = String.fromCharCode(charCode),
|
||||
charactersIgnoringModifiers = characters.toLowerCase();
|
||||
|
||||
if (!(modifierFlags & CPShiftKeyMask))
|
||||
if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive)
|
||||
characters = charactersIgnoringModifiers;
|
||||
|
||||
event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags
|
||||
@@ -633,40 +667,126 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode];
|
||||
break;
|
||||
}
|
||||
|
||||
if (event)
|
||||
|
||||
if (event && !isNativePasteEvent)
|
||||
{
|
||||
event._DOMEvent = aDOMEvent;
|
||||
|
||||
|
||||
[CPApp sendEvent:event];
|
||||
|
||||
if (isNativeCopyOrCutEvent)
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
types = [pasteboard types];
|
||||
|
||||
// If this is a native copy event, then check if the pasteboard has anything in it.
|
||||
if (types.length)
|
||||
{
|
||||
if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
|
||||
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
|
||||
else
|
||||
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
|
||||
|
||||
_DOMPasteboardElement.select();
|
||||
|
||||
window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
[self _primePasteboardElement];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (StopDOMEventPropagation)
|
||||
CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)copyEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
if ([self _validateCopyCutOrPasteEvent:aDOMEvent flags:CPPlatformActionKeyMask] && !_ignoreNativeCopyOrCutEvent)
|
||||
{
|
||||
//we have to send out a fake copy or cut event so that we can force the copy/cut mechanisms to take place
|
||||
var cut = aDOMEvent.type === "beforecut",
|
||||
keyCode = cut ? CPKeyCodes.X : CPKeyCodes.C,
|
||||
characters = cut ? "x" : "c",
|
||||
timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
|
||||
windowNumber = [[CPApp keyWindow] windowNumber],
|
||||
modifierFlags = CPPlatformActionKeyMask;
|
||||
|
||||
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil
|
||||
characters:characters charactersIgnoringModifiers:characters isARepeat:NO keyCode:keyCode];
|
||||
|
||||
event._DOMEvent = aDOMEvent;
|
||||
[CPApp sendEvent:event];
|
||||
|
||||
[self _primePasteboardElement];
|
||||
|
||||
//then we have to IGNORE the real keyboard event to prevent a double copy
|
||||
//safari also sends the beforecopy event twice, so we additionally check here and prevent two events
|
||||
_ignoreNativeCopyOrCutEvent = YES;
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)pasteEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
if ([self _validateCopyCutOrPasteEvent:aDOMEvent flags:CPPlatformActionKeyMask])
|
||||
{
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
_ignoreNativePastePreparation = YES;
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)_validateCopyCutOrPasteEvent:(DOMEvent)aDOMEvent flags:(unsigned)modifierFlags
|
||||
{
|
||||
return (
|
||||
((aDOMEvent.target || aDOMEvent.srcElement).nodeName.toUpperCase() !== "INPUT" &&
|
||||
(aDOMEvent.target || aDOMEvent.srcElement).nodeName.toUpperCase() !== "TEXTAREA"
|
||||
) || aDOMEvent.target === _DOMPasteboardElement
|
||||
) &&
|
||||
(modifierFlags & CPPlatformActionKeyMask);
|
||||
}
|
||||
|
||||
- (void)_primePasteboardElement
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
types = [pasteboard types];
|
||||
|
||||
if (types.length)
|
||||
{
|
||||
if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
|
||||
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
|
||||
else
|
||||
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
|
||||
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
|
||||
window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)_checkPasteboardElement
|
||||
{
|
||||
var value = _DOMPasteboardElement.value;
|
||||
|
||||
if ([value length])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
if ([pasteboard _stateUID] != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
[self _clearPasteboardElement];
|
||||
|
||||
[CPApp sendEvent:_pasteboardKeyDownEvent];
|
||||
|
||||
_pasteboardKeyDownEvent = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)_clearPasteboardElement
|
||||
{
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMPasteboardElement.blur();
|
||||
}
|
||||
|
||||
- (void)scrollEvent:(DOMEvent)aDOMEvent
|
||||
@@ -1077,8 +1197,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
StopDOMEventPropagation = !aFlag;
|
||||
}
|
||||
|
||||
- (BOOL)_willPropagateCurrentDOMEvent
|
||||
{
|
||||
return !StopDOMEventPropagation;
|
||||
}
|
||||
|
||||
- (CPWindow)hitTest:(CPPoint)location
|
||||
{if (self._only) return self._only;
|
||||
{
|
||||
if (self._only)
|
||||
return self._only;
|
||||
|
||||
var levels = _windowLevels,
|
||||
layers = _windowLayers,
|
||||
levelCount = levels.length,
|
||||
@@ -1101,37 +1229,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
return theWindow;
|
||||
}
|
||||
|
||||
- (void)_checkPasteboardElement
|
||||
{
|
||||
var value = _DOMPasteboardElement.value;
|
||||
|
||||
if ([value length])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
if ([pasteboard _stateUID] != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
[self _clearPasteboardElement];
|
||||
|
||||
[CPApp sendEvent:_pasteboardKeyDownEvent];
|
||||
|
||||
_pasteboardKeyDownEvent = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)_clearPasteboardElement
|
||||
{
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMPasteboardElement.blur();
|
||||
}
|
||||
|
||||
/*!
|
||||
When using command (mac) or control (windows), keys are propagated to the browser by default.
|
||||
To prevent a character key from propagating (to prevent its default action, and instead use it
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* CPPlatformWindow+DOMKeys.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// Keycodes taken and modified from Google Closure, available under Apache 2 License
|
||||
|
||||
CPKeyCodes = {
|
||||
BACKSPACE: 8,
|
||||
TAB: 9,
|
||||
NUM_CENTER: 12,
|
||||
ENTER: 13,
|
||||
SHIFT: 16,
|
||||
CTRL: 17,
|
||||
ALT: 18,
|
||||
PAUSE: 19,
|
||||
CAPS_LOCK: 20,
|
||||
ESC: 27,
|
||||
SPACE: 32,
|
||||
PAGE_UP: 33, // also NUM_NORTH_EAST
|
||||
PAGE_DOWN: 34, // also NUM_SOUTH_EAST
|
||||
END: 35, // also NUM_SOUTH_WEST
|
||||
HOME: 36, // also NUM_NORTH_WEST
|
||||
LEFT: 37, // also NUM_WEST
|
||||
UP: 38, // also NUM_NORTH
|
||||
RIGHT: 39, // also NUM_EAST
|
||||
DOWN: 40, // also NUM_SOUTH
|
||||
PRINT_SCREEN: 44,
|
||||
INSERT: 45, // also NUM_INSERT
|
||||
DELETE: 46, // also NUM_DELETE
|
||||
ZERO: 48,
|
||||
ONE: 49,
|
||||
TWO: 50,
|
||||
THREE: 51,
|
||||
FOUR: 52,
|
||||
FIVE: 53,
|
||||
SIX: 54,
|
||||
SEVEN: 55,
|
||||
EIGHT: 56,
|
||||
NINE: 57,
|
||||
QUESTION_MARK: 63, // needs localization
|
||||
A: 65,
|
||||
B: 66,
|
||||
C: 67,
|
||||
D: 68,
|
||||
E: 69,
|
||||
F: 70,
|
||||
G: 71,
|
||||
H: 72,
|
||||
I: 73,
|
||||
J: 74,
|
||||
K: 75,
|
||||
L: 76,
|
||||
M: 77,
|
||||
N: 78,
|
||||
O: 79,
|
||||
P: 80,
|
||||
Q: 81,
|
||||
R: 82,
|
||||
S: 83,
|
||||
T: 84,
|
||||
U: 85,
|
||||
V: 86,
|
||||
W: 87,
|
||||
X: 88,
|
||||
Y: 89,
|
||||
Z: 90,
|
||||
META: 91,
|
||||
CONTEXT_MENU: 93,
|
||||
NUM_ZERO: 96,
|
||||
NUM_ONE: 97,
|
||||
NUM_TWO: 98,
|
||||
NUM_THREE: 99,
|
||||
NUM_FOUR: 100,
|
||||
NUM_FIVE: 101,
|
||||
NUM_SIX: 102,
|
||||
NUM_SEVEN: 103,
|
||||
NUM_EIGHT: 104,
|
||||
NUM_NINE: 105,
|
||||
NUM_MULTIPLY: 106,
|
||||
NUM_PLUS: 107,
|
||||
NUM_MINUS: 109,
|
||||
NUM_PERIOD: 110,
|
||||
NUM_DIVISION: 111,
|
||||
F1: 112,
|
||||
F2: 113,
|
||||
F3: 114,
|
||||
F4: 115,
|
||||
F5: 116,
|
||||
F6: 117,
|
||||
F7: 118,
|
||||
F8: 119,
|
||||
F9: 120,
|
||||
F10: 121,
|
||||
F11: 122,
|
||||
F12: 123,
|
||||
NUMLOCK: 144,
|
||||
SEMICOLON: 186, // needs localization
|
||||
DASH: 189, // needs localization
|
||||
EQUALS: 187, // needs localization
|
||||
COMMA: 188, // needs localization
|
||||
PERIOD: 190, // needs localization
|
||||
SLASH: 191, // needs localization
|
||||
APOSTROPHE: 192, // needs localization
|
||||
SINGLE_QUOTE: 222, // needs localization
|
||||
OPEN_SQUARE_BRACKET: 219, // needs localization
|
||||
BACKSLASH: 220, // needs localization
|
||||
CLOSE_SQUARE_BRACKET: 221, // needs localization
|
||||
WIN_KEY: 224,
|
||||
MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
|
||||
WIN_IME: 229
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* Returns true if the key fires a keypress event in the current browser.
|
||||
*
|
||||
* Accoridng to MSDN [1] IE only fires keypress events for the following keys:
|
||||
* - Letters: A - Z (uppercase and lowercase)
|
||||
* - Numerals: 0 - 9
|
||||
* - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~
|
||||
* - System: ESC, SPACEBAR, ENTER
|
||||
*
|
||||
* That's not entirely correct though, for instance there's no distinction
|
||||
* between upper and lower case letters.
|
||||
*
|
||||
* [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx)
|
||||
*
|
||||
* Safari is similar to IE, but does not fire keypress for ESC.
|
||||
*
|
||||
* Additionally, IE6 does not fire keydown or keypress events for letters when
|
||||
* the control or alt keys are held down and the shift key is not. IE7 does
|
||||
* fire keydown in these cases, though, but not keypress.
|
||||
*
|
||||
* @param keyCode A key code.
|
||||
* @param opt_heldKeyCode Key code of a currently-held key.
|
||||
* @param opt_shiftKey Whether the shift key is held down.
|
||||
* @param opt_ctrlKey Whether the control key is held down.
|
||||
* @param opt_altKey Whether the alt key is held down.
|
||||
* @return Returns YES if it's a key that fires a keypress event.
|
||||
*/
|
||||
CPKeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, opt_shiftKey, opt_ctrlKey, opt_altKey)
|
||||
{
|
||||
if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
|
||||
return true;
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem) && opt_altKey)
|
||||
return CPKeyCodes.isCharacterKey(keyCode);
|
||||
|
||||
// Alt but not AltGr which is represented as Alt+Ctrl.
|
||||
if (opt_altKey && !opt_ctrlKey)
|
||||
return false;
|
||||
|
||||
// Saves Ctrl or Alt + key for IE7, which won't fire keypress.
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !opt_shiftKey && (opt_ctrlKey || opt_altKey))
|
||||
return false;
|
||||
|
||||
// When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it
|
||||
// continues to fire keydown events as the event repeats.
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && opt_ctrlKey && opt_heldKeyCode == keyCode)
|
||||
return false;
|
||||
|
||||
switch (keyCode)
|
||||
{
|
||||
case CPKeyCodes.ENTER: return true;
|
||||
case CPKeyCodes.ESC: return !CPBrowserIsEngine(CPWebKitBrowserEngine);
|
||||
}
|
||||
|
||||
return CPKeyCodes.isCharacterKey(keyCode);
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* Test for whether or not a given keyCode represents a character key.
|
||||
*
|
||||
* @param keyCode A key code.
|
||||
* @return Returns YES if the keyCode is a character key.
|
||||
*/
|
||||
CPKeyCodes.isCharacterKey = function(keyCode)
|
||||
{
|
||||
if (keyCode >= CPKeyCodes.ZERO && keyCode <= CPKeyCodes.NINE)
|
||||
return true;
|
||||
|
||||
if (keyCode >= CPKeyCodes.NUM_ZERO && keyCode <= CPKeyCodes.NUM_MULTIPLY)
|
||||
return true;
|
||||
|
||||
if (keyCode >= CPKeyCodes.A && keyCode <= CPKeyCodes.Z)
|
||||
return true;
|
||||
|
||||
switch (keyCode)
|
||||
{
|
||||
case CPKeyCodes.SPACE:
|
||||
case CPKeyCodes.QUESTION_MARK:
|
||||
case CPKeyCodes.NUM_PLUS:
|
||||
case CPKeyCodes.NUM_MINUS:
|
||||
case CPKeyCodes.NUM_PERIOD:
|
||||
case CPKeyCodes.NUM_DIVISION:
|
||||
case CPKeyCodes.SEMICOLON:
|
||||
case CPKeyCodes.DASH:
|
||||
case CPKeyCodes.EQUALS:
|
||||
case CPKeyCodes.COMMA:
|
||||
case CPKeyCodes.PERIOD:
|
||||
case CPKeyCodes.SLASH:
|
||||
case CPKeyCodes.APOSTROPHE:
|
||||
case CPKeyCodes.SINGLE_QUOTE:
|
||||
case CPKeyCodes.OPEN_SQUARE_BRACKET:
|
||||
case CPKeyCodes.BACKSLASH:
|
||||
case CPKeyCodes.CLOSE_SQUARE_BRACKET:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user