mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 07:37:58 +02:00
1656 lines
52 KiB
ObjectPascal
1656 lines
52 KiB
ObjectPascal
unit customdrawn_cocoaproc;
|
||
|
||
{$mode objfpc}{$H+}
|
||
{$include customdrawndefines.inc}
|
||
|
||
interface
|
||
|
||
uses
|
||
// rtl+ftl
|
||
Types, Classes, SysUtils, Math,
|
||
CGGeometry,
|
||
fpimage, fpcanvas,
|
||
// Custom Drawn Canvas
|
||
IntfGraphics, lazcanvas, customdrawnproc,
|
||
// Libs
|
||
MacOSAll, CocoaAll, CocoaUtils, CocoaGDIObjects, LazSysUtils,
|
||
//
|
||
LMessages, StdCtrls, LCLIntf,
|
||
Forms, Controls, LCLMessageGlue, WSControls, LCLType, LCLProc, GraphType;
|
||
|
||
type
|
||
TCocoaForm = objcclass;
|
||
TCocoaCustomControl = objcclass;
|
||
|
||
TCocoaWindow = class(TCDForm)
|
||
public
|
||
CocoaForm: TCocoaForm;
|
||
ClientArea: TCocoaCustomControl;
|
||
end;
|
||
|
||
{ TCocoaForm }
|
||
|
||
TCocoaForm = objcclass(NSWindow, NSWindowDelegateProtocol)
|
||
protected
|
||
function windowShouldClose(sender : id): LongBool; message 'windowShouldClose:';
|
||
procedure windowWillClose(notification: NSNotification); message 'windowWillClose:';
|
||
procedure windowDidBecomeKey(notification: NSNotification); message 'windowDidBecomeKey:';
|
||
procedure windowDidResignKey(notification: NSNotification); message 'windowDidResignKey:';
|
||
procedure windowDidResize(notification: NSNotification); message 'windowDidResize:';
|
||
public
|
||
WindowHandle: TCocoaWindow;
|
||
function acceptsFirstResponder: Boolean; override;
|
||
// Mouse events
|
||
procedure mouseUp(event: NSEvent); override;
|
||
procedure mouseDown(event: NSEvent); override;
|
||
procedure mouseDragged(event: NSEvent); override;
|
||
procedure mouseEntered(event: NSEvent); override;
|
||
procedure mouseExited(event: NSEvent); override;
|
||
procedure mouseMoved(event: NSEvent); override;
|
||
// Keyboard events
|
||
procedure keyDown(theEvent: NSEvent); override;
|
||
procedure keyUp(theEvent: NSEvent); override;
|
||
function MacKeyCodeToLCLKey(AKeyEvent: NSEvent; var SendKeyUpDown, SendChar: Boolean; var AUTF8Char: TUTF8Char): Word; message 'MacKeyCodeToLCLKey:sendkey:sendchar:AUTF8Char:';
|
||
//
|
||
function lclIsVisible: Boolean; message 'lclIsVisible';
|
||
procedure lclInvalidateRect(const r: TRect); message 'lclInvalidateRect:';
|
||
procedure lclInvalidate; message 'lclInvalidate';
|
||
procedure lclLocalToScreen(var X,Y: Integer); message 'lclLocalToScreen::';
|
||
function lclFrame: TRect; message 'lclFrame';
|
||
procedure lclSetFrame(const r: TRect); message 'lclSetFrame:';
|
||
function lclClientFrame: TRect; message 'lclClientFrame';
|
||
procedure lclSetClientFrame(const r: TRect); message 'lclSetClientFrame:';
|
||
// callback routines
|
||
procedure CallbackActivate; message 'CallbackActivate';
|
||
procedure CallbackDeactivate; message 'CallbackDeactivate';
|
||
procedure CallbackCloseQuery(var CanClose: Boolean); message 'CallbackCloseQuery:';
|
||
procedure CallbackResize; message 'CallbackResize';
|
||
// Accessibility
|
||
function accessibilityAttributeValue(attribute: NSString): id; override;
|
||
end;
|
||
|
||
{ TCocoaCustomControl }
|
||
|
||
TCocoaCustomControl = objcclass(NSControl)
|
||
public
|
||
//callback : TCommonCallback;
|
||
WindowHandle: TCocoaWindow;
|
||
Context : TCocoaContext;
|
||
procedure drawRect(dirtyRect: NSRect); override;
|
||
procedure Draw(ControlContext: NSGraphicsContext; const Abounds, dirty:NSRect); message 'draw:Context:bounds:';
|
||
public
|
||
// Keyboard events
|
||
function acceptsFirstResponder: Boolean; override;
|
||
procedure keyDown(theEvent: NSEvent); override;
|
||
procedure keyUp(theEvent: NSEvent); override;
|
||
//
|
||
function lclInitWithCreateParams(const AParams: TCreateParams): id; message 'lclInitWithCreateParams:';
|
||
//
|
||
function lclIsVisible: Boolean; message 'lclIsVisible';
|
||
procedure lclInvalidateRect(const r: TRect); message 'lclInvalidateRect:';
|
||
procedure lclInvalidate; message 'lclInvalidate';
|
||
procedure lclLocalToScreen(var X,Y: Integer); message 'lclLocalToScreen::';
|
||
function lclParent: id; message 'lclParent';
|
||
function lclFrame: TRect; message 'lclFrame';
|
||
procedure lclSetFrame(const r: TRect); message 'lclSetFrame:';
|
||
function lclClientFrame: TRect; message 'lclClientFrame';
|
||
// Accessibility
|
||
class function LazRoleToCocoaRole(ALazRole: TLazAccessibilityRole): NSString; message 'LazRoleToCocoaRole:';
|
||
function accessibilityAttributeValue(attribute: NSString): id; override;
|
||
function accessibilityFocusedUIElement: id; override;
|
||
end;
|
||
|
||
TSelectionInfo = class
|
||
public
|
||
SelectedText: string;
|
||
CaretPos: TPoint;
|
||
SelLength: Integer;
|
||
SelStart: Integer;
|
||
end;
|
||
|
||
TVisibleTextInfo = class
|
||
public
|
||
VisibleLineStart, VisibleLineCount: Integer;
|
||
// now as a character index in relation to the entire text string
|
||
VisibleTextStart, VisibleTextLength: Integer;
|
||
end;
|
||
|
||
{ TCocoaAccessibleObject }
|
||
|
||
TCocoaAccessibleObject = objcclass(NSObject)
|
||
public
|
||
// Accessibility
|
||
LCLControl: TControl;
|
||
LCLAcc: TLazAccessibleObject;
|
||
//
|
||
LCLInjectedControl: TCustomControl;
|
||
LCLBaseControl: TCDBaseControl;
|
||
procedure ReadInjectedAndBaseControl; message 'ReadInjectedAndBaseControl';
|
||
function GetSelectedTextInfo: TSelectionInfo; message 'GetSelectedTextInfo';
|
||
function GetVisibleTextInfo: TVisibleTextInfo; message 'GetVisibleTextInfo';
|
||
//NSAccessibilityCategory = objccategory external (NSObject)
|
||
function accessibilityAttributeNames: NSArray; override;
|
||
function accessibilityAttributeValue(attribute: NSString): id; override;
|
||
function accessibilityIsAttributeSettable(attribute: NSString): Boolean; override;
|
||
procedure accessibilitySetValue_forAttribute(_value: id; attribute: NSString); override;
|
||
function accessibilityParameterizedAttributeNames: NSArray; override;
|
||
function accessibilityAttributeValue_forParameter(attribute: NSString; parameter: id): id; override;
|
||
function accessibilityActionNames: NSArray; override;
|
||
function accessibilityActionDescription(action: NSString): NSString; override;
|
||
procedure accessibilityPerformAction(action: NSString); override;
|
||
function accessibilityIsIgnored: Boolean; override;
|
||
function accessibilityHitTest(point: NSPoint): id; override;
|
||
function accessibilityFocusedUIElement: id; override;
|
||
{function accessibilityIndexOfChild(child: id): NSUInteger; message 'accessibilityIndexOfChild:';
|
||
function accessibilityArrayAttributeCount(attribute: NSString): NSUInteger; message 'accessibilityArrayAttributeCount:';
|
||
function accessibilityArrayAttributeValues_index_maxCount(attribute: NSString; index: NSUInteger; maxCount: NSUInteger): NSArray; message 'accessibilityArrayAttributeValues:index:maxCount:';}
|
||
end;
|
||
|
||
{ TCocoaMenu }
|
||
|
||
TCocoaMenu = objcclass(NSMenu)
|
||
public
|
||
procedure lclItemSelected(sender: id); message 'lclItemSelected:';
|
||
end;
|
||
|
||
{ TCocoaMenuItem }
|
||
|
||
TCocoaMenuItem = objcclass(NSMenuItem)
|
||
public
|
||
procedure lclItemSelected(sender: id); message 'lclItemSelected:';
|
||
end;
|
||
|
||
procedure SetViewDefaults(AView: NSView);
|
||
|
||
function Cocoa_RawImage_CreateBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: HBitmap; ASkipMask: Boolean): Boolean;
|
||
function RawImage_DescriptionToBitmapType(ADesc: TRawImageDescription; out bmpType: TCocoaBitmapType): Boolean;
|
||
|
||
function CalcNSWindowStyle(const AWinControl: TWinControl; const AParams: TCreateParams): NSUInteger;
|
||
function LCLCoordToCocoa(AControl: TControl; ACoord: TPoint): NSPoint;
|
||
function CocoaCoordToLCL(AControl: TControl; ACoord: NSPoint): TPoint;
|
||
|
||
implementation
|
||
|
||
uses customdrawnwsforms, customdrawnprivate;
|
||
|
||
(*
|
||
About Mac Key codes:
|
||
unfortunately, mac key codes are keyboard specific:
|
||
that is, there is no universal VK_A, but every keyboard has its code for VK_A
|
||
Key codes depend on physical key position on the keyboard: considering a
|
||
QWERTY keyboard and an AZERTY one, keycode(Q) of first one = keycode(A) of
|
||
the second one, and so on.
|
||
For "printable" keys we can rely on kEventParamKeyMacCharCodes and
|
||
kEventParamKeyUnicodes event parameters to obtain an ascii/unicode value
|
||
that we can translate to the appropriate VK_ code
|
||
For non printable keys (Function, ins, arrow and so on...) we use the raw
|
||
keycodes, since it looks like they are constant across all keyboards
|
||
|
||
So, here are constants for non-printable keys (MK means "Mac Key").
|
||
These constants were extracted using KeyCodes program by Peter Maurer
|
||
(http://www.petermaurer.de/nasi.php?section=keycodes)
|
||
|
||
Some keys were taken from the ancient "Macintosh Toolbox Essentials", page 87
|
||
http://developer.apple.com/documentation/mac/pdf/MacintoshToolboxEssentials.pdf
|
||
*)
|
||
|
||
const
|
||
MK_ENTER = $24;
|
||
MK_SPACE = $31;
|
||
MK_ESC = $35;
|
||
MK_F1 = $7A;
|
||
MK_F2 = $78;
|
||
MK_F3 = $63;
|
||
MK_F4 = $76;
|
||
MK_F5 = $60;
|
||
MK_F6 = $61;
|
||
MK_F7 = $62;
|
||
MK_F8 = $64;
|
||
MK_F9 = $65;
|
||
MK_F10 = $6D;
|
||
MK_F11 = $67;
|
||
MK_F12 = $6F;
|
||
MK_F13 = $69; MK_PRNSCR = MK_F13; //Print screen = F13
|
||
MK_F14 = $6B; MK_SCRLOCK = MK_F14; //Scroll Lock = F14
|
||
MK_F15 = $71; MK_PAUSE = MK_F15; //Pause = F15
|
||
MK_POWER = $7F7F;
|
||
MK_TAB = $30;
|
||
MK_INS = $72; MK_HELP = MK_INS; //old macs call this key "help"
|
||
MK_DEL = $75;
|
||
MK_HOME = $73;
|
||
MK_END = $77;
|
||
MK_PAGUP = $74;
|
||
MK_PAGDN = $79;
|
||
MK_UP = $7E;
|
||
MK_DOWN = $7D;
|
||
MK_LEFT = $7B;
|
||
MK_RIGHT = $7C;
|
||
MK_NUMLOCK = $47;
|
||
MK_NUMPAD0 = $52;
|
||
MK_NUMPAD1 = $53;
|
||
MK_NUMPAD2 = $54;
|
||
MK_NUMPAD3 = $55;
|
||
MK_NUMPAD4 = $56;
|
||
MK_NUMPAD5 = $57;
|
||
MK_NUMPAD6 = $58;
|
||
MK_NUMPAD7 = $59;
|
||
MK_NUMPAD8 = $5b;
|
||
MK_NUMPAD9 = $5c;
|
||
MK_PADEQUALS = $51; //only present in old mac keyboards?
|
||
MK_PADDIV = $4B;
|
||
MK_PADMULT = $43;
|
||
MK_PADSUB = $4E;
|
||
MK_PADADD = $45;
|
||
MK_PADDEC = $41;
|
||
MK_PADENTER = $4C; //enter on numeric keypad
|
||
MK_BACKSPACE = $33;
|
||
MK_CAPSLOCK = $39;
|
||
|
||
|
||
//Modifiers codes - you'll never get these directly
|
||
|
||
MK_SHIFTKEY = $38;
|
||
MK_CTRL = $3B;
|
||
MK_ALT = $3A; MK_OPTION = MK_ALT;
|
||
MK_COMMAND = $37; MK_APPLE = MK_COMMAND;
|
||
|
||
MK_TILDE = 50; // `/~ key
|
||
MK_MINUS = 27; // -/_ key
|
||
MK_EQUAL = 24; // =/+ key
|
||
MK_BACKSLASH = 42; // \ | key
|
||
MK_LEFTBRACKET = 33; // [ { key
|
||
MK_RIGHTBRACKET = 30; // ] } key
|
||
MK_SEMICOLON = 41; // ; : key
|
||
MK_QUOTE = 39; // ' " key
|
||
MK_COMMA = 43; // , < key
|
||
MK_PERIOD = 47; // . > key
|
||
MK_SLASH = 44; // / ? key
|
||
|
||
function Cocoa_RawImage_CreateBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: HBitmap; ASkipMask: Boolean): Boolean;
|
||
const
|
||
ALIGNMAP: array[TRawImageLineEnd] of TCocoaBitmapAlignment = (cbaByte, cbaByte, cbaWord, cbaDWord, cbaQWord, cbaDQWord);
|
||
var
|
||
ADesc: TRawImageDescription absolute ARawImage.Description;
|
||
bmpType: TCocoaBitmapType;
|
||
begin
|
||
Result := RawImage_DescriptionToBitmapType(ADesc, bmpType);
|
||
if not Result then begin
|
||
debugln(['TCarbonWidgetSet.RawImage_CreateBitmaps TODO Depth=',ADesc.Depth,' alphaprec=',ADesc.AlphaPrec,' byteorder=',ord(ADesc.ByteOrder),' alpha=',ADesc.AlphaShift,' red=',ADesc.RedShift,' green=',adesc.GreenShift,' blue=',adesc.BlueShift]);
|
||
exit;
|
||
end;
|
||
ABitmap := HBITMAP(TCocoaBitmap.Create(ADesc.Width, ADesc.Height, ADesc.Depth, ADesc.BitsPerPixel, ALIGNMAP[ADesc.LineEnd], bmpType, ARawImage.Data));
|
||
|
||
if ASkipMask or (ADesc.MaskBitsPerPixel = 0)
|
||
then AMask := 0
|
||
else AMask := HBITMAP(TCocoaBitmap.Create(ADesc.Width, ADesc.Height, 1, ADesc.MaskBitsPerPixel, ALIGNMAP[ADesc.MaskLineEnd], cbtMask, ARawImage.Mask));
|
||
|
||
Result := True;
|
||
end;
|
||
|
||
function RawImage_DescriptionToBitmapType(
|
||
ADesc: TRawImageDescription;
|
||
out bmpType: TCocoaBitmapType): Boolean;
|
||
begin
|
||
Result := False;
|
||
|
||
if ADesc.Format = ricfGray
|
||
then
|
||
begin
|
||
if ADesc.Depth = 1 then bmpType := cbtMono
|
||
else bmpType := cbtGray;
|
||
end
|
||
else if ADesc.Depth = 1
|
||
then bmpType := cbtMono
|
||
else if ADesc.AlphaPrec <> 0
|
||
then begin
|
||
if ADesc.ByteOrder = riboMSBFirst
|
||
then begin
|
||
if (ADesc.AlphaShift = 24)
|
||
and (ADesc.RedShift = 16)
|
||
and (ADesc.GreenShift = 8 )
|
||
and (ADesc.BlueShift = 0 )
|
||
then bmpType := cbtARGB
|
||
else
|
||
if (ADesc.AlphaShift = 0)
|
||
and (ADesc.RedShift = 24)
|
||
and (ADesc.GreenShift = 16 )
|
||
and (ADesc.BlueShift = 8 )
|
||
then bmpType := cbtRGBA
|
||
else
|
||
if (ADesc.AlphaShift = 0 )
|
||
and (ADesc.RedShift = 8 )
|
||
and (ADesc.GreenShift = 16)
|
||
and (ADesc.BlueShift = 24)
|
||
then bmpType := cbtBGRA
|
||
else Exit;
|
||
end
|
||
else begin
|
||
if (ADesc.AlphaShift = 24)
|
||
and (ADesc.RedShift = 16)
|
||
and (ADesc.GreenShift = 8 )
|
||
and (ADesc.BlueShift = 0 )
|
||
then bmpType := cbtBGRA
|
||
else
|
||
if (ADesc.AlphaShift = 0 )
|
||
and (ADesc.RedShift = 8 )
|
||
and (ADesc.GreenShift = 16)
|
||
and (ADesc.BlueShift = 24)
|
||
then bmpType := cbtARGB
|
||
else
|
||
if (ADesc.AlphaShift = 24 )
|
||
and (ADesc.RedShift = 0 )
|
||
and (ADesc.GreenShift = 8)
|
||
and (ADesc.BlueShift = 16)
|
||
then bmpType := cbtRGBA
|
||
else Exit;
|
||
end;
|
||
end
|
||
else begin
|
||
bmpType := cbtRGB;
|
||
end;
|
||
|
||
Result := True;
|
||
end;
|
||
|
||
function CalcNSWindowStyle(const AWinControl: TWinControl;
|
||
const AParams: TCreateParams): NSUInteger;
|
||
var
|
||
lForm: TCustomForm absolute AWinControl;
|
||
begin
|
||
case lForm.BorderStyle of
|
||
bsNone: Result := NSBorderlessWindowMask;
|
||
bsSingle: Result := NSTitledWindowMask or NSClosableWindowMask;
|
||
// bsToolWindow should be created by building a NSPanel instead of a NSWindow
|
||
bsToolWindow: Result := NSTitledWindowMask or NSClosableWindowMask;
|
||
bsSizeToolWin: Result := NSClosableWindowMask or NSResizableWindowMask;
|
||
else
|
||
Result := NSTitledWindowMask or NSClosableWindowMask or NSResizableWindowMask;
|
||
end;
|
||
|
||
if biMinimize in lForm.BorderIcons then Result := Result or NSMiniaturizableWindowMask;
|
||
end;
|
||
|
||
function LCLCoordToCocoa(AControl: TControl; ACoord: TPoint): NSPoint;
|
||
begin
|
||
Result.x := ACoord.X;
|
||
Result.y := Screen.Height - ACoord.Y;
|
||
if AControl <> nil then Result.y := Result.y - AControl.Height;
|
||
end;
|
||
|
||
function CocoaCoordToLCL(AControl: TControl; ACoord: NSPoint): TPoint;
|
||
begin
|
||
|
||
end;
|
||
|
||
{ TCocoaForm }
|
||
|
||
function TCocoaForm.windowShouldClose(sender: id): LongBool;
|
||
var
|
||
canClose : Boolean;
|
||
begin
|
||
canClose:=true;
|
||
CallbackCloseQuery(canClose);
|
||
Result:=canClose;
|
||
end;
|
||
|
||
procedure TCocoaForm.windowWillClose(notification: NSNotification);
|
||
begin
|
||
LCLSendCloseUpMsg(WindowHandle.LCLForm);
|
||
end;
|
||
|
||
procedure TCocoaForm.windowDidBecomeKey(notification: NSNotification);
|
||
begin
|
||
CallbackActivate;
|
||
end;
|
||
|
||
procedure TCocoaForm.windowDidResignKey(notification: NSNotification);
|
||
begin
|
||
CallbackDeactivate;
|
||
end;
|
||
|
||
procedure TCocoaForm.windowDidResize(notification: NSNotification);
|
||
begin
|
||
CallbackResize;
|
||
end;
|
||
|
||
function TCocoaForm.acceptsFirstResponder: Boolean;
|
||
begin
|
||
Result:=true;
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseUp(event: NSEvent);
|
||
var
|
||
mp : NSPoint;
|
||
begin
|
||
mp:=event.locationInWindow;
|
||
mp.y:=NSView(event.window.contentView).bounds.size.height-mp.y;
|
||
callbackMouseUp(WindowHandle, round(mp.x), round(mp.y), mbLeft);
|
||
inherited mouseUp(event);
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseDown(event: NSEvent);
|
||
var
|
||
mp : NSPoint;
|
||
begin
|
||
mp:=event.locationInWindow;
|
||
mp.y:=NSView(event.window.contentView).bounds.size.height-mp.y;
|
||
callbackMouseDown(WindowHandle, round(mp.x), round(mp.y), mbLeft);
|
||
inherited mouseDown(event);
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseDragged(event: NSEvent);
|
||
var
|
||
mp : NSPoint;
|
||
begin
|
||
mp:=event.locationInWindow;
|
||
mp.y:=NSView(event.window.contentView).bounds.size.height-mp.y;
|
||
callbackMouseMove(WindowHandle, round(mp.x), round(mp.y));
|
||
inherited mouseMoved(event);
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseMoved(event: NSEvent);
|
||
var
|
||
mp : NSPoint;
|
||
begin
|
||
mp:=event.locationInWindow;
|
||
mp.y:=NSView(event.window.contentView).bounds.size.height-mp.y;
|
||
callbackMouseMove(WindowHandle, round(mp.x), round(mp.y));
|
||
inherited mouseMoved(event);
|
||
end;
|
||
|
||
procedure TCocoaForm.keyDown(theEvent: NSEvent);
|
||
var
|
||
lKey: Word;
|
||
lUTF8Char: TUTF8Char;
|
||
lSendKey, lSendChar: Boolean;
|
||
begin
|
||
//inherited keyDown(theEvent); Don't call inherited or else Cocoa will think you didn't handle the event and beep on key input
|
||
lKey := MacKeyCodeToLCLKey(theEvent, lSendKey, lSendChar, lUTF8Char);
|
||
{$ifdef VerboseCDKeyInput}
|
||
DebugLn(Format('[TCocoaForm] KeyDown CocoaKeyCode=%x UTF8Char=%s', [theEvent.keyCode(), lUTF8Char]));
|
||
{$endif}
|
||
if lSendKey then CallbackKeyDown(WindowHandle, lKey);
|
||
if lSendChar then CallbackKeyChar(WindowHandle, 0, lUTF8Char);
|
||
end;
|
||
|
||
procedure TCocoaForm.keyUp(theEvent: NSEvent);
|
||
var
|
||
lKey: Word;
|
||
lUTF8Char: TUTF8Char;
|
||
lSendKey, lSendChar: Boolean;
|
||
begin
|
||
//inherited keyUp(theEvent); Don't call inherited or else Cocoa will think you didn't handle the event and beep on key input
|
||
lKey := MacKeyCodeToLCLKey(theEvent, lSendKey, lSendChar, lUTF8Char);
|
||
if lSendKey then CallbackKeyUp(WindowHandle, lKey);
|
||
end;
|
||
|
||
function TCocoaForm.MacKeyCodeToLCLKey(AKeyEvent: NSEvent; var SendKeyUpDown, SendChar: Boolean; var AUTF8Char: TUTF8Char): Word;
|
||
var
|
||
KeyCode: Word;
|
||
ExtendedKeysSupport: Boolean;
|
||
{ TextLen : UInt32;
|
||
CharLen : integer;}
|
||
characters: string;
|
||
charactersIgnoringModifiers: string;
|
||
(* widebuf: array[1..2] of widechar;
|
||
U: Cardinal;
|
||
Layout: UCKeyboardLayoutPtr;
|
||
KeyboardLayout: KeyboardLayoutRef;*)
|
||
begin
|
||
SendKeyUpDown := False;
|
||
SendChar := False;
|
||
Result := VK_UNKNOWN;
|
||
AUTF8Char := '';
|
||
ExtendedKeysSupport := Application.ExtendedKeysSupport;
|
||
|
||
// Obtain data from the event
|
||
KeyCode := AKeyEvent.keyCode();
|
||
characters := NSStringToString(AKeyEvent.characters());
|
||
charactersIgnoringModifiers := NSStringToString(AKeyEvent.charactersIgnoringModifiers());
|
||
|
||
// IsSysKey:=(GetCurrentEventKeyModifiers and cmdKey)>0;
|
||
|
||
//non-printable keys (see mackeycodes.inc)
|
||
//for these keys, only send keydown/keyup (not char or UTF8KeyPress)
|
||
case KeyCode of
|
||
MK_F1 : Result:=VK_F1;
|
||
MK_F2 : Result:=VK_F2;
|
||
MK_F3 : Result:=VK_F3;
|
||
MK_F4 : Result:=VK_F4;
|
||
MK_F5 : Result:=VK_F5;
|
||
MK_F6 : Result:=VK_F6;
|
||
MK_F7 : Result:=VK_F7;
|
||
MK_F8 : Result:=VK_F8;
|
||
MK_F9 : Result:=VK_F9;
|
||
MK_F10 : Result:=VK_F10;
|
||
MK_F11 : Result:=VK_F11;
|
||
MK_F12 : Result:=VK_F12;
|
||
{ MK_F13 : Result:=VK_SNAPSHOT;
|
||
MK_F14 : Result:=VK_SCROLL;
|
||
MK_F15 : Result:=VK_PAUSE;}
|
||
MK_POWER : Result:=VK_LCL_POWER;
|
||
MK_TAB : Result:=VK_TAB; //strangely enough, tab is "non printable"
|
||
MK_INS : Result:=VK_INSERT;
|
||
MK_DEL : Result:=VK_DELETE;
|
||
MK_HOME : Result:=VK_HOME;
|
||
MK_END : Result:=VK_END;
|
||
MK_PAGUP : Result:=VK_PRIOR;
|
||
MK_PAGDN : Result:=VK_NEXT;
|
||
MK_UP : Result:=VK_UP;
|
||
MK_DOWN : Result:=VK_DOWN;
|
||
MK_LEFT : Result:= VK_LEFT;
|
||
MK_RIGHT : Result:= VK_RIGHT;
|
||
MK_NUMLOCK : Result:= VK_NUMLOCK;
|
||
MK_BACKSPACE: Result:= VK_BACK;
|
||
// MK_CAPSLOCK : Result:= VK_CAPSLOCK; <- We don't seam to receive it at all
|
||
//Modifiers codes - you'll never get these directly
|
||
{MK_SHIFTKEY = $38;
|
||
MK_CTRL = $3B;
|
||
MK_ALT = $3A; MK_OPTION = MK_ALT;
|
||
MK_COMMAND = $37; MK_APPLE = MK_COMMAND;}
|
||
end;
|
||
|
||
if Result<>VK_UNKNOWN then
|
||
begin
|
||
//stop here, we won't send char or UTF8KeyPress
|
||
SendKeyUpDown:=true;
|
||
Exit;
|
||
end;
|
||
|
||
// Now other keys which might also send utf8keypress
|
||
|
||
case KeyCode of
|
||
MK_NUMPAD0: Result:=VK_NUMPAD0;
|
||
MK_NUMPAD1: Result:=VK_NUMPAD1;
|
||
MK_NUMPAD2: Result:=VK_NUMPAD2;
|
||
MK_NUMPAD3: Result:=VK_NUMPAD3;
|
||
MK_NUMPAD4: Result:=VK_NUMPAD4;
|
||
MK_NUMPAD5: Result:=VK_NUMPAD5;
|
||
MK_NUMPAD6: Result:=VK_NUMPAD6;
|
||
MK_NUMPAD7: Result:=VK_NUMPAD7;
|
||
MK_NUMPAD8: Result:=VK_NUMPAD8;
|
||
MK_NUMPAD9: Result:=VK_NUMPAD9;
|
||
MK_PADDIV : Result:=VK_DIVIDE;
|
||
MK_PADMULT : Result:=VK_MULTIPLY;
|
||
MK_PADSUB : Result:=VK_SUBTRACT;
|
||
MK_PADADD : Result:=VK_ADD;
|
||
MK_PADDEC : Result:=VK_DECIMAL;
|
||
MK_PADENTER:
|
||
begin
|
||
Result:=VK_RETURN;
|
||
AUTF8Char:=#13;
|
||
end;
|
||
MK_TILDE: Result := VK_LCL_TILDE; // `/~ key
|
||
MK_MINUS: Result := VK_LCL_MINUS;
|
||
MK_EQUAL: Result := VK_LCL_EQUAL;
|
||
MK_BACKSLASH: Result := VK_LCL_BACKSLASH;
|
||
MK_LEFTBRACKET: Result := VK_LCL_OPEN_BRACKET;
|
||
MK_RIGHTBRACKET: Result := VK_LCL_CLOSE_BRACKET;
|
||
MK_SEMICOLON: Result := VK_LCL_SEMI_COMMA;
|
||
MK_QUOTE: Result := VK_LCL_QUOTE;
|
||
MK_COMMA: Result := VK_LCL_COMMA;
|
||
MK_PERIOD: Result := VK_LCL_POINT;
|
||
MK_SLASH: Result := VK_LCL_SLASH;
|
||
end;
|
||
|
||
if Result<>VK_UNKNOWN then SendKeyUpDown:=true;
|
||
|
||
if AUTF8Char <> '' then
|
||
begin
|
||
SendChar := True;
|
||
Exit;
|
||
end;
|
||
|
||
if Length(charactersIgnoringModifiers) = 1 then
|
||
begin
|
||
case charactersIgnoringModifiers[1] of
|
||
'a'..'z':
|
||
begin
|
||
Result:=VK_A+ord(charactersIgnoringModifiers[1])-ord('a');
|
||
AUTF8Char := charactersIgnoringModifiers;
|
||
end;
|
||
'A'..'Z':
|
||
begin
|
||
Result:=ord(charactersIgnoringModifiers[1]);
|
||
AUTF8Char := charactersIgnoringModifiers;
|
||
end;
|
||
#27 : Result:=VK_ESCAPE;
|
||
#8 : Result:=VK_BACK;
|
||
' ' :
|
||
begin
|
||
Result:=VK_SPACE;
|
||
AUTF8Char := charactersIgnoringModifiers;
|
||
end;
|
||
#13 : Result:=VK_RETURN;
|
||
'0'..'9':
|
||
begin
|
||
Result:=VK_0+ord(charactersIgnoringModifiers[1])-ord('0');
|
||
AUTF8Char := charactersIgnoringModifiers;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
if Result<>VK_UNKNOWN then SendKeyUpDown:=true;
|
||
if AUTF8Char <> '' then SendChar := True;
|
||
|
||
if Length(characters) > 1 then
|
||
begin
|
||
// ToDo: Merge the accents into the UTF-8 character if necessary
|
||
AUTF8Char := characters;
|
||
//
|
||
SendChar := True;
|
||
end;
|
||
|
||
if Result = VK_UNKNOWN then
|
||
DebugLn('[MacKeyCodeToLCLKey] Unknown Key! KeyCode=%d characters=%s charactersIgnoringModifiers=%s',
|
||
[KeyCode, characters, charactersIgnoringModifiers]);
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseEntered(event: NSEvent);
|
||
begin
|
||
inherited mouseEntered(event);
|
||
end;
|
||
|
||
procedure TCocoaForm.mouseExited(event: NSEvent);
|
||
begin
|
||
inherited mouseExited(event);
|
||
end;
|
||
|
||
function TCocoaForm.lclIsVisible:Boolean;
|
||
begin
|
||
Result:=isVisible;
|
||
end;
|
||
|
||
procedure TCocoaForm.lclInvalidateRect(const r:TRect);
|
||
begin
|
||
contentView.lclInvalidateRect(r);
|
||
end;
|
||
|
||
procedure TCocoaForm.lclInvalidate;
|
||
begin
|
||
contentView.lclInvalidate;
|
||
end;
|
||
|
||
procedure TCocoaForm.lclLocalToScreen(var X,Y:Integer);
|
||
var
|
||
f : NSRect;
|
||
begin
|
||
if Assigned(screen) then begin
|
||
f:=frame;
|
||
x:=Round(f.origin.x+x);
|
||
y:=Round(screen.frame.size.height-f.size.height-f.origin.y);
|
||
end;
|
||
end;
|
||
|
||
function TCocoaForm.lclFrame:TRect;
|
||
begin
|
||
if Assigned(screen)
|
||
then NSToLCLRect(frame, screen.frame.size.height, Result)
|
||
else NSToLCLRect(frame, Result);
|
||
end;
|
||
|
||
procedure TCocoaForm.lclSetFrame(const r:TRect);
|
||
var
|
||
ns: NSRect;
|
||
begin
|
||
if Assigned(screen)
|
||
then LCLToNSRect(r, screen.frame.size.height, ns)
|
||
else LCLToNSRect(r, ns);
|
||
setFrame_display(ns, isVisible);
|
||
end;
|
||
|
||
function TCocoaForm.lclClientFrame:TRect;
|
||
var
|
||
wr : NSRect;
|
||
b : CGGeometry.CGRect;
|
||
begin
|
||
wr:=frame;
|
||
b:=contentView.frame;
|
||
Result.Left:=Round(b.origin.x);
|
||
Result.Top:=Round(wr.size.height-b.origin.y);
|
||
Result.Right:=Round(b.origin.x+b.size.width);
|
||
Result.Bottom:=Round(Result.Top+b.size.height);
|
||
end;
|
||
|
||
procedure TCocoaForm.lclSetClientFrame(const r: TRect);
|
||
var
|
||
ns, lAdjustedRect: NSRect;
|
||
lTitleBarHeight: Single;
|
||
begin
|
||
if Assigned(screen)
|
||
then LCLToNSRect(r, screen.frame.size.height, ns)
|
||
else LCLToNSRect(r, ns);
|
||
// LCL coordinates are for the client area of the Window, while setFrame_display
|
||
// includes the title bar too, so we need to consider this here, but in a clever
|
||
// way, as to keep the window position the same
|
||
lAdjustedRect := frameRectForContentRect(ns);
|
||
lTitleBarHeight := lAdjustedRect.size.height - ns.size.height;
|
||
ns.origin.y := ns.origin.y - lTitleBarHeight;
|
||
ns.size.height := lAdjustedRect.size.height;
|
||
|
||
setFrame_display(ns, isVisible);
|
||
end;
|
||
|
||
procedure TCocoaForm.CallbackActivate;
|
||
begin
|
||
LCLSendActivateMsg(WindowHandle.LCLForm, WA_ACTIVE, false);
|
||
end;
|
||
|
||
procedure TCocoaForm.CallbackDeactivate;
|
||
begin
|
||
LCLSendActivateMsg(WindowHandle.LCLForm, WA_INACTIVE, false);
|
||
end;
|
||
|
||
procedure TCocoaForm.CallbackCloseQuery(var CanClose: Boolean);
|
||
begin
|
||
// Message results : 0 - do nothing, 1 - destroy window
|
||
CanClose:=LCLSendCloseQueryMsg(WindowHandle.LCLForm)>0;
|
||
end;
|
||
|
||
procedure TCocoaForm.CallbackResize;
|
||
var
|
||
sz : NSSize;
|
||
r : TRect;
|
||
begin
|
||
sz := frame.size;
|
||
TCDWSCustomForm.GetClientBounds(TWinControl(WindowHandle.LCLForm), r);
|
||
if Assigned(WindowHandle.LCLForm) then
|
||
LCLSendSizeMsg(WindowHandle.LCLForm, Round(sz.width), Round(sz.height), SIZENORMAL);
|
||
end;
|
||
|
||
function TCocoaForm.accessibilityAttributeValue(attribute: NSString): id;
|
||
var
|
||
lStrAttr: String;
|
||
lAResult: NSArray;
|
||
lMAResult: NSMutableArray;
|
||
begin
|
||
Result := inherited accessibilityAttributeValue(attribute);
|
||
|
||
{$ifdef VerboseCDAccessibility}
|
||
//lStrAttr := NSStringToString(attribute);
|
||
//DebugLn('[TCocoaCustomControl.accessibilityAttributeValue] attribute='+lStrAttr);
|
||
{$endif}
|
||
|
||
// Cocoa by default merges the window and it's main subcontrol into 1 things
|
||
// And Finder and other Cocoa apps follow this, so let's do it like that too
|
||
//
|
||
// If we want to put all items inside a sub-window in the window then we could
|
||
// activate the code bellow, but then we have to solve parent missmatch errors which we get
|
||
//
|
||
// Curiously, even while not being in the list of elements,
|
||
// TCocoaCustomControl.accessibilityAttributeValue is executed
|
||
// as if it spoke for the window and not for itself, this adding the sub-window
|
||
// duplicates all out accessibility entries (appear once for the window and once for the sub-window)
|
||
(* if attribute.isEqualToString(NSAccessibilityChildrenAttribute) then
|
||
begin
|
||
// Strangely Cocoa doesn't add automatically the client area to the array
|
||
{$ifdef VerboseCDAccessibility}
|
||
//DebugLn('[TCocoaForm.accessibilityAttributeValue] NSAccessibilityChildrenAttribute');
|
||
{$endif}
|
||
lAResult := NSArray(Result);
|
||
lMAResult := lAResult.mutableCopy();
|
||
lMAResult.addObject(WindowHandle.ClientArea);
|
||
Result := lMAResult;
|
||
end; *)
|
||
end;
|
||
|
||
{ TCocoaCustomControl }
|
||
|
||
procedure TCocoaCustomControl.drawRect(dirtyRect:NSRect);
|
||
begin
|
||
inherited drawRect(dirtyRect);
|
||
Draw(NSGraphicsContext.currentContext, bounds, dirtyRect);
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.Draw(ControlContext: NSGraphicsContext;
|
||
const Abounds, dirty:NSRect);
|
||
var
|
||
lWidth, lHeight: Integer;
|
||
lBitmap, lMask: HBITMAP;
|
||
lRawImage: TRawImage;
|
||
AImage: TLazIntfImage;
|
||
ACanvas: TLazCanvas;
|
||
{$IFDEF VerboseCDPaintProfiler}
|
||
lTimeStart, lNativeStart: TDateTime;
|
||
{$ENDIF}
|
||
begin
|
||
{$IFDEF VerboseCDPaintProfiler}
|
||
lTimeStart := NowUTC();
|
||
{$ENDIF}
|
||
if not Assigned(Context) then Context:=TCocoaContext.Create;
|
||
|
||
Context.ctx:=ControlContext;
|
||
lWidth := Round(bounds.size.width);
|
||
lHeight := Round(bounds.size.height);
|
||
if Context.InitDraw(lWidth, lHeight) then
|
||
begin
|
||
// Prepare the non-native image and canvas
|
||
UpdateControlLazImageAndCanvas(WindowHandle.Image,
|
||
WindowHandle.Canvas, lWidth, lHeight, clfRGB24UpsideDown);
|
||
DrawFormBackground(WindowHandle.Image, WindowHandle.Canvas, WindowHandle.LCLForm);
|
||
WindowHandle.Canvas.NativeDC := PtrInt(Context);
|
||
|
||
// Draw the form
|
||
RenderForm(WindowHandle.Image, WindowHandle.Canvas, WindowHandle.LCLForm);
|
||
|
||
{$IFDEF VerboseCDPaintProfiler}
|
||
lNativeStart := NowUTC();
|
||
{$ENDIF}
|
||
|
||
// Now render it into the control
|
||
WindowHandle.Image.GetRawImage(lRawImage);
|
||
Cocoa_RawImage_CreateBitmaps(lRawImage, lBitmap, lMask, True);
|
||
Context.DrawBitmap(0, 0, TCocoaBitmap(lBitmap));
|
||
end;
|
||
{$IFDEF VerboseCDPaintProfiler}
|
||
DebugLn(Format('[TCocoaCustomControl.Draw] Paint LCL-CustomDrawn: %d ms Native: %d ms',
|
||
[DateTimeToMilliseconds(lNativeStart - lTimeStart),
|
||
DateTimeToMilliseconds(NowUTC() - lNativeStart)]));
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function TCocoaCustomControl.acceptsFirstResponder: Boolean;
|
||
begin
|
||
Result := True;
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.keyDown(theEvent: NSEvent);
|
||
begin
|
||
//DebugLn('[TCocoaCustomControl] KeyDown='+IntToHex(theEvent.keyCode(), 4));
|
||
WindowHandle.CocoaForm.keyDown(theEvent);
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.keyUp(theEvent: NSEvent);
|
||
begin
|
||
WindowHandle.CocoaForm.keyUp(theEvent);
|
||
end;
|
||
|
||
function RectToViewCoord(view: NSView; const r: TRect): NSRect;
|
||
var
|
||
b: NSRect;
|
||
begin
|
||
if not Assigned(view) then Exit;
|
||
b:=view.bounds;
|
||
Result.origin.x:=r.Left;
|
||
Result.origin.y:=b.size.height-r.Top;
|
||
Result.size.width:=r.Right-r.Left;
|
||
Result.size.height:=r.Bottom-r.Top;
|
||
end;
|
||
|
||
function TCocoaCustomControl.lclInitWithCreateParams(const AParams:TCreateParams): id;
|
||
var
|
||
p: NSView;
|
||
ns: NSRect;
|
||
begin
|
||
p:=nil;
|
||
if (AParams.WndParent<>0) then begin
|
||
if (NSObject(AParams.WndParent).isKindOfClass_(NSView)) then
|
||
p:=NSView(AParams.WndParent)
|
||
else if (NSObject(AParams.WndParent).isKindOfClass_(NSWindow)) then
|
||
p:=NSWindow(AParams.WndParent).contentView;
|
||
end;
|
||
with AParams do
|
||
if Assigned(p)
|
||
then LCLToNSRect(Types.Bounds(X,Y,Width, Height), p.frame.size.height, ns)
|
||
else LCLToNSRect(Types.Bounds(X,Y,Width, Height), ns);
|
||
|
||
Result:=initWithFrame(ns);
|
||
if not Assigned(Result) then Exit;
|
||
|
||
if Assigned(p) then p.addSubview(Self);
|
||
SetViewDefaults(Self);
|
||
end;
|
||
|
||
function TCocoaCustomControl.lclIsVisible:Boolean;
|
||
begin
|
||
Result:=not isHidden;
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.lclInvalidateRect(const r:TRect);
|
||
begin
|
||
setNeedsDisplayInRect(RectToViewCoord(Self, r));
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.lclInvalidate;
|
||
begin
|
||
setNeedsDisplay_(True);
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.lclLocalToScreen(var X,Y:Integer);
|
||
begin
|
||
|
||
end;
|
||
|
||
function TCocoaCustomControl.lclParent:id;
|
||
begin
|
||
Result:=superView;
|
||
end;
|
||
|
||
function TCocoaCustomControl.lclFrame: TRect;
|
||
var
|
||
v : NSView;
|
||
begin
|
||
v:=superview;
|
||
if Assigned(v)
|
||
then NSToLCLRect(frame, v.frame.size.height, Result)
|
||
else NSToLCLRect(frame, Result);
|
||
end;
|
||
|
||
procedure TCocoaCustomControl.lclSetFrame(const r:TRect);
|
||
var
|
||
ns : NSRect;
|
||
begin
|
||
if Assigned(superview)
|
||
then LCLToNSRect(r, superview.frame.size.height, ns)
|
||
else LCLToNSRect(r, ns);
|
||
setFrame(ns);
|
||
end;
|
||
|
||
function TCocoaCustomControl.lclClientFrame:TRect;
|
||
var
|
||
r: NSRect;
|
||
begin
|
||
r:=bounds;
|
||
Result.Left:=0;
|
||
Result.Top:=0;
|
||
Result.Right:=Round(r.size.width);
|
||
Result.Bottom:=Round(r.size.height);
|
||
end;
|
||
|
||
class function TCocoaCustomControl.LazRoleToCocoaRole(
|
||
ALazRole: TLazAccessibilityRole): NSString;
|
||
begin
|
||
case ALazRole of
|
||
larAnimation: Result := NSAccessibilityImageRole;
|
||
larButton: Result := NSAccessibilityButtonRole;
|
||
larCell: Result := NSAccessibilityCellRole;
|
||
larChart: Result := NSAccessibilityImageRole;
|
||
larCheckBox: Result := NSAccessibilityCheckBoxRole;
|
||
larClock: Result := NSAccessibilityStaticTextRole;
|
||
larColorPicker: Result := NSAccessibilityColorWellRole;
|
||
larComboBox: Result := NSAccessibilityComboBoxRole;
|
||
larDateField: Result := NSAccessibilityStaticTextRole;//('AXDateField');
|
||
larGrid: Result := NSAccessibilityGridRole;
|
||
larGroup: Result := NSAccessibilityGroupRole;
|
||
larImage: Result := NSAccessibilityImageRole;
|
||
larLabel: Result := NSAccessibilityStaticTextRole;
|
||
larListBox: Result := NSAccessibilityListRole;
|
||
larListItem: Result := NSAccessibilityStaticTextRole;
|
||
larMenuBar: Result := NSAccessibilityMenuBarRole;
|
||
larMenuItem: Result := NSAccessibilityMenuItemRole;
|
||
larProgressIndicator: Result := NSAccessibilityProgressIndicatorRole;
|
||
larRadioButton: Result := NSAccessibilityRadioButtonRole;
|
||
larResizeGrip: Result := NSAccessibilityStaticTextRole; // VoiceOver cannot handle AXHandle in Mac 10.6, so we fallback to AXStaticText
|
||
larScrollBar: Result := NSAccessibilityScrollBarRole;
|
||
larSpinner: Result := NSAccessibilityIncrementorRole;
|
||
larTabControl: Result := NSAccessibilityTabGroupRole;
|
||
larTextEditorMultiline: Result := NSAccessibilityTextAreaRole;
|
||
larTextEditorSingleline: Result := NSAccessibilityTextFieldRole;
|
||
// NSAccessibilityToolbarRole: NSString; cvar; external;
|
||
larTrackBar: Result := NSAccessibilitySliderRole;
|
||
larTreeView: Result := NSAccessibilityListRole;
|
||
larTreeItem: Result := NSAccessibilityStaticTextRole;
|
||
larWindow: Result := NSAccessibilityWindowRole;//NSAccessibilityUnknownRole;
|
||
else
|
||
Result := NSAccessibilityUnknownRole;
|
||
end;
|
||
end;
|
||
|
||
function TCocoaCustomControl.accessibilityAttributeValue(attribute: NSString): id;
|
||
var
|
||
lStrAttr: String;
|
||
lAResult: NSArray;
|
||
lMAResult: NSMutableArray;
|
||
i: Integer;
|
||
lForm: TCustomForm;
|
||
lFormAcc, lChildAcc: TLazAccessibleObject;
|
||
lAccObject: TCocoaAccessibleObject;
|
||
begin
|
||
Result := inherited accessibilityAttributeValue(attribute);
|
||
|
||
lStrAttr := NSStringToString(attribute);
|
||
//DebugLn('[TCocoaCustomControl.accessibilityAttributeValue] attribute='+lStrAttr);
|
||
|
||
if attribute.isEqualToString(NSAccessibilityRoleAttribute) then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn('[TCocoaCustomControl.accessibilityAttributeValue] NSAccessibilityRoleAttribute');
|
||
{$endif}
|
||
lForm := WindowHandle.LCLForm;
|
||
lFormAcc := lForm.GetAccessibleObject();
|
||
Result := LazRoleToCocoaRole(lFormAcc.AccessibleRole);
|
||
end
|
||
else if attribute.isEqualToString(NSAccessibilityChildrenAttribute) then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
lStrAttr := '[TCocoaCustomControl.accessibilityAttributeValue] NSAccessibilityChildrenAttribute';
|
||
{$endif}
|
||
lAResult := NSArray(Result);
|
||
lMAResult := NSMutableArray.arrayWithCapacity(0); //lAResult.mutableCopy();
|
||
lForm := WindowHandle.LCLForm;
|
||
lFormAcc := lForm.GetAccessibleObject();
|
||
lChildAcc := lFormAcc.GetFirstChildAccessibleObject();
|
||
while lChildAcc <> nil do
|
||
begin
|
||
lAccObject := TCocoaAccessibleObject(lChildAcc.Handle);
|
||
if lAccObject <> nil then
|
||
begin
|
||
lMAResult.addObject(lAccObject);
|
||
{$ifdef VerboseCDAccessibility}
|
||
lStrAttr := lStrAttr + Format(' Adding object %s : %x', [lChildAcc.OwnerControl.ClassName, PtrUInt(lAccObject)]);
|
||
{$endif}
|
||
end;
|
||
lChildAcc := lFormAcc.GetNextChildAccessibleObject();
|
||
end;
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(lStrAttr);
|
||
{$endif}
|
||
Result := lMAResult;
|
||
end;
|
||
end;
|
||
|
||
function TCocoaCustomControl.accessibilityFocusedUIElement: id;
|
||
var
|
||
lForm: TCustomForm;
|
||
// lFormAcc: TLazAccessibleObject;
|
||
lActiveControl: TWinControl;
|
||
begin
|
||
Result := inherited accessibilityFocusedUIElement();
|
||
|
||
lForm := WindowHandle.LCLForm;
|
||
// lFormAcc := lForm.GetAccessibleObject();
|
||
lActiveControl := lForm.ActiveControl;
|
||
if lActiveControl = nil then lActiveControl := lForm;
|
||
|
||
Result := id(lActiveControl.GetAccessibleObject().Handle);
|
||
end;
|
||
|
||
{ TCocoaAccessibleObject }
|
||
|
||
procedure TCocoaAccessibleObject.ReadInjectedAndBaseControl;
|
||
var
|
||
lHandle: TCDWinControl;
|
||
begin
|
||
if not (LCLControl is TWinControl) then Exit;
|
||
|
||
if LCLBaseControl = nil then
|
||
begin
|
||
lHandle := TCDWinControl(TWinControl(LCLControl).Handle);
|
||
LCLBaseControl := lHandle;
|
||
if lHandle <> nil then
|
||
LCLInjectedControl := lHandle.CDControl
|
||
else
|
||
LCLInjectedControl := nil;
|
||
end;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.GetSelectedTextInfo: TSelectionInfo;
|
||
var
|
||
lCustomEdit: TCustomEdit;
|
||
begin
|
||
// initialization
|
||
Result := TSelectionInfo.Create;
|
||
|
||
if LCLControl is TCustomEdit then
|
||
begin
|
||
lCustomEdit := TCustomEdit(LCLControl);
|
||
Result.SelectedText := lCustomEdit.SelText;
|
||
Result.CaretPos := lCustomEdit.CaretPos;
|
||
Result.SelLength := lCustomEdit.SelLength;
|
||
Result.SelStart := lCustomEdit.SelStart;
|
||
end;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.GetVisibleTextInfo: TVisibleTextInfo;
|
||
var
|
||
lCustomMemo: TCustomMemo;
|
||
lCustomEdit: TCustomEdit;
|
||
lDC: HDC;
|
||
lOldFont: HFont;
|
||
lTM: TTextMetric;
|
||
lRect: TRect;
|
||
lLines: TStrings = nil;
|
||
lScrollBar: TControlScrollbar = nil;
|
||
i: Integer;
|
||
lScrollPos, lScrollRange, lScrollPage: Integer;
|
||
lStr: String;
|
||
begin
|
||
// initialization
|
||
Result := TVisibleTextInfo.Create;
|
||
Result.VisibleLineCount := 1;
|
||
|
||
if LCLControl is TCustomMemo then
|
||
begin
|
||
lCustomMemo := TCustomMemo(LCLControl);
|
||
lDC := LCLIntf.GetDC(lCustomMemo.Handle);
|
||
lOldFont := SelectObject(lDC, lCustomMemo.Font.Handle);
|
||
try
|
||
GetTextMetrics(lDC, lTM);
|
||
lRect := LCLControl.ClientRect;
|
||
Result.VisibleLineCount := (lRect.Bottom - lRect.Top) div
|
||
(lTM.tmHeight + lTM.tmExternalLeading);
|
||
finally
|
||
SelectObject(lDC, lOldFont);
|
||
ReleaseDC(lCustomMemo.Handle, lDC);
|
||
end;
|
||
|
||
lLines := lCustomMemo.Lines;
|
||
lScrollBar := lCustomMemo.VertScrollBar;
|
||
end;
|
||
|
||
// With a TStrings and a ScrollBar we can get the visible range info
|
||
if (lLines <> nil) and (lScrollBar <> nil) then
|
||
begin
|
||
lScrollPos := lScrollBar.Position;
|
||
lScrollRange := lScrollBar.Range;
|
||
lScrollPage := lScrollBar.Page;
|
||
Result.VisibleLineStart := Round((lScrollPos / lScrollRange) * lLines.Count);
|
||
Result.VisibleLineCount := Round((lScrollPage / lScrollRange) * lLines.Count);
|
||
Result.VisibleLineCount := Min(Result.VisibleLineCount, lLines.Count - 1 - Result.VisibleLineStart); // sanity correction
|
||
|
||
// using the calculated info get the character indexes
|
||
for i := 0 to Result.VisibleLineStart + Result.VisibleLineCount do
|
||
begin
|
||
if i < Result.VisibleLineStart then
|
||
begin
|
||
lStr := lLines.Strings[i];
|
||
Result.VisibleTextStart := Result.VisibleTextStart + UTF8Length(lStr) + 1; // +1 for the Mac line ending
|
||
end
|
||
else
|
||
begin
|
||
lStr := lLines.Strings[i];
|
||
Result.VisibleTextLength := Result.VisibleTextLength + UTF8Length(lStr) + 1; // +1 for the Mac line ending
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
{
|
||
See the documentation about accessibility Roles and their required attributes:
|
||
http://developer.apple.com/library/mac/documentation/UserExperience/Reference/Accessibility_RoleAttribute_Ref/Role.html
|
||
}
|
||
function TCocoaAccessibleObject.accessibilityAttributeNames: NSArray;
|
||
var
|
||
lResult: NSMutableArray;
|
||
lCocoaRole: NSString;
|
||
|
||
// Basic elements which most roles have
|
||
procedure AddBasicAttributes;
|
||
begin
|
||
lResult.addObject(NSAccessibilityDescriptionAttribute);
|
||
lResult.addObject(NSAccessibilityEnabledAttribute);
|
||
lResult.addObject(NSAccessibilityFocusedAttribute);
|
||
lResult.addObject(NSAccessibilityParentAttribute);
|
||
lResult.addObject(NSAccessibilityPositionAttribute);
|
||
lResult.addObject(NSAccessibilityRoleAttribute);
|
||
lResult.addObject(NSAccessibilitySizeAttribute);
|
||
lResult.addObject(NSAccessibilityTitleAttribute);
|
||
lResult.addObject(NSAccessibilityTopLevelUIElementAttribute);
|
||
lResult.addObject(NSAccessibilityWindowAttribute);
|
||
end;
|
||
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format('[TCocoaAccessibleObject.accessibilityAttributeNames] Self=%x', [PtrUInt(Self)]));
|
||
{$endif}
|
||
lResult := NSMutableArray.array_();
|
||
|
||
lCocoaRole := TCocoaCustomControl.LazRoleToCocoaRole(LCLAcc.AccessibleRole);
|
||
//larAnimation
|
||
//larButton
|
||
if lCocoaRole.isEqualToString(NSAccessibilityButtonRole) then
|
||
begin
|
||
AddBasicAttributes();
|
||
lResult.addObject(NSAccessibilityRoleDescriptionAttribute);
|
||
end
|
||
//larCell
|
||
//larChart
|
||
//larCheckBox
|
||
//larClock
|
||
//larColorPicker
|
||
//larComboBox
|
||
//larDateField
|
||
//larGrid
|
||
//larGroup
|
||
//larImage
|
||
//larLabel
|
||
else if lCocoaRole.isEqualToString(NSAccessibilityStaticTextRole) then
|
||
begin
|
||
AddBasicAttributes();
|
||
lResult.addObject(NSAccessibilityValueAttribute);
|
||
end
|
||
//larListBox
|
||
//larListItem
|
||
//larMenuBar
|
||
//larMenuItem
|
||
//larProgressIndicator
|
||
//larRadioButton
|
||
//larResizeGrip
|
||
//larScrollBar
|
||
//larSpinner
|
||
//larTabControl
|
||
//larTextEditorMultiline
|
||
//larTextEditorSingleline
|
||
else if lCocoaRole.isEqualToString(NSAccessibilityTextFieldRole) then
|
||
begin
|
||
AddBasicAttributes();
|
||
lResult.addObject(NSAccessibilityNumberOfCharactersAttribute); // Number of characters in an editable text field. Must not be settable.
|
||
lResult.addObject(NSAccessibilitySelectedTextAttribute); // Currently selected text of a UI element. May be settable.
|
||
lResult.addObject(NSAccessibilitySelectedTextRangeAttribute); // Position and length (in characters) of a selected portion of text in the UI element. May be settable.
|
||
lResult.addObject(NSAccessibilityValueAttribute); // The element’s value. May be settable.
|
||
lResult.addObject(NSAccessibilityVisibleCharacterRangeAttribute); // Range of characters that are scrolled into view in an editable text element. May be settable.
|
||
end
|
||
//larTrackBar
|
||
//larTreeView
|
||
//larTreeItem
|
||
//larWindow
|
||
else
|
||
begin
|
||
AddBasicAttributes();
|
||
end;
|
||
|
||
// This one we use to put LCL object and class names to help debugging =)
|
||
lResult.addObject(NSAccessibilityUnitDescriptionAttribute);
|
||
|
||
Result := lResult;
|
||
end;
|
||
|
||
// Note that if there is an injected control we will send information about it instead
|
||
// of about the host control
|
||
function TCocoaAccessibleObject.accessibilityAttributeValue(attribute: NSString): id;
|
||
var
|
||
lStrAttr: String;
|
||
lTmpStr: string;
|
||
//
|
||
lSize: TSize;
|
||
lPoint: TPoint;
|
||
lBool: Boolean;
|
||
lInt: Integer;
|
||
//
|
||
lAResult: NSArray;
|
||
lMAResult: NSMutableArray;
|
||
lNSSize: NSSize;
|
||
lNSPoint: NSPoint;
|
||
lNSRange: NSRange;
|
||
//
|
||
i: Integer;
|
||
lChildAcc: TLazAccessibleObject;
|
||
lForm: TCustomForm;
|
||
lParent: TWinControl;
|
||
lSelInfo: TSelectionInfo;
|
||
lVisibleTextInfo: TVisibleTextInfo;
|
||
|
||
function GetControlText: string;
|
||
begin
|
||
Result := LCLControl.Caption;
|
||
end;
|
||
|
||
begin
|
||
//Result := inherited accessibilityAttributeValue(attribute); -> This raises errors, so don't
|
||
Result := nil;
|
||
ReadInjectedAndBaseControl();
|
||
|
||
lStrAttr := NSStringToString(attribute);
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format(':>[TCocoaAccessibleObject.accessibilityAttributeValue] Self=%x LCLControl=%x',
|
||
[PtrUInt(Self), PtrUInt(LCLControl)]));
|
||
{$endif}
|
||
|
||
//
|
||
// Role
|
||
//
|
||
if attribute.isEqualToString(NSAccessibilityRoleAttribute) then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityRoleAttribute');
|
||
{$endif}
|
||
Result := TCocoaCustomControl.LazRoleToCocoaRole(LCLAcc.AccessibleRole);
|
||
end
|
||
//
|
||
// RoleDescription
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityRoleDescriptionAttribute) then
|
||
begin
|
||
Result := NSStringUtf8(LCLControl.Caption);
|
||
end
|
||
//
|
||
// Value
|
||
//
|
||
// The element’s value. May be settable.
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityValueAttribute) then
|
||
begin
|
||
Result := NSStringUtf8(LCLControl.Caption);
|
||
end
|
||
{else if attribute = NSAccessibilityMinValueAttribute: NSString; cvar; external;
|
||
NSAccessibilityMaxValueAttribute: NSString; cvar; external;}
|
||
//
|
||
// Enabled
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityEnabledAttribute) then
|
||
begin
|
||
Result := NSNumber.numberWithBool(LCLControl.Enabled);
|
||
end
|
||
//
|
||
// Focused
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityFocusedAttribute) then
|
||
begin
|
||
if LCLControl is TWinControl then
|
||
begin
|
||
lBool := TWinControl(LCLControl).Focused;
|
||
if (not lBool) and (LCLInjectedControl <> nil) then
|
||
lBool := LCLInjectedControl.Focused;
|
||
Result := NSNumber.numberWithBool(lBool);
|
||
end
|
||
else Result := NSNumber.numberWithBool(False);
|
||
end
|
||
//
|
||
// Parent
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityParentAttribute) or
|
||
attribute.isEqualToString(NSAccessibilityTopLevelUIElementAttribute) then
|
||
begin
|
||
lParent := LCLControl.Parent;
|
||
if lParent <> nil then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityParentAttribute Self=%s Parent=%s',
|
||
[LCLControl.ClassName, lParent.ClassName]));
|
||
{$endif}
|
||
// if the parent is a form, pass to the custom control
|
||
if lParent is TCustomForm then
|
||
begin
|
||
Result := TCocoaWindow(lParent.Handle).CocoaForm;//ClientArea;
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':<[TCocoaAccessibleObject.accessibilityAttributeValue] Parent is TCustomForm');
|
||
{$endif}
|
||
end
|
||
else
|
||
Result := TCocoaAccessibleObject(lParent.GetAccessibleObject().Handle);
|
||
end
|
||
else
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':<[TCocoaAccessibleObject.accessibilityAttributeValue] ERROR: Parent is nil!');
|
||
{$endif}
|
||
Result := nil;
|
||
end;
|
||
end
|
||
//
|
||
// Children
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityChildrenAttribute)
|
||
or attribute.isEqualToString(NSAccessibilityVisibleChildrenAttribute) then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityChildrenAttribute');
|
||
{$endif}
|
||
lAResult := NSArray(Result);
|
||
lMAResult := lAResult.mutableCopy();
|
||
//if Self.LCLInjectedControl = nil then
|
||
for i := 0 to LCLAcc.GetChildAccessibleObjectsCount() - 1 do
|
||
begin
|
||
lChildAcc := LCLAcc.GetChildAccessibleObject(i);
|
||
lMAResult.addObject(TCocoaAccessibleObject(lChildAcc.Handle));
|
||
end;
|
||
Result := lMAResult;
|
||
end
|
||
//
|
||
// Window
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityWindowAttribute) then
|
||
begin
|
||
lForm := Forms.GetParentForm(LCLControl);
|
||
//Result := TCocoaAccessibleObject(lForm.GetAccessibleObject().Handle);
|
||
Result := TCocoaWindow(lForm.Handle).CocoaForm;//ClientArea;
|
||
end
|
||
else if attribute.isEqualToString(NSAccessibilitySelectedChildrenAttribute) then
|
||
begin
|
||
|
||
end
|
||
//
|
||
// Position is in screen coordinates!
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityPositionAttribute) then
|
||
begin
|
||
lPoint := LCLControl.ClientToScreen(Types.Point(0, 0));
|
||
lNSPoint := LCLCoordToCocoa(LCLControl, lPoint);
|
||
Result := NSValue.valueWithPoint(lNSPoint);
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityPositionAttribute Result=%d,%d', [lPoint.X, lPoint.Y]));
|
||
{$endif}
|
||
end
|
||
//
|
||
// Size
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilitySizeAttribute) then
|
||
begin
|
||
lSize := LCLAcc.Size;
|
||
lNSSize.width := lSize.CX;
|
||
lNSSize.height := lSize.CY;
|
||
Result := NSValue.valueWithSize(lNSSize);
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilitySizeAttribute Result=%d,%d', [lSize.CX, lSize.CY]));
|
||
{$endif}
|
||
end
|
||
//
|
||
// NumberOfCharacters
|
||
//
|
||
// Number of characters in an editable text field. Must not be settable.
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityNumberOfCharactersAttribute) then
|
||
begin
|
||
lTmpStr := LCLControl.Caption;
|
||
lInt := UTF8Length(lTmpStr);
|
||
Result := NSNumber.numberWithInt(lInt);
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityNumberOfCharactersAttribute Text=%s Result=%d', [lTmpStr, lInt]));
|
||
{$endif}
|
||
end
|
||
//
|
||
// SelectedText
|
||
//
|
||
// Currently selected text of a UI element. May be settable.
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilitySelectedTextAttribute) then
|
||
begin
|
||
lSelInfo := GetSelectedTextInfo();
|
||
try
|
||
Result := NSStringUtf8(lSelInfo.SelectedText);
|
||
finally
|
||
lSelInfo.Free;
|
||
end;
|
||
//{$ifdef VerboseCDAccessibility}
|
||
//DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilitySizeAttribute Result=%d,%d', [lSize.CX, lSize.CY]));
|
||
//{$endif}
|
||
end
|
||
//
|
||
// SelectedTextRange
|
||
//
|
||
// Position and length (in characters) of a selected portion of text in the UI element. May be settable.
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilitySelectedTextRangeAttribute) then
|
||
begin
|
||
lSelInfo := GetSelectedTextInfo();
|
||
try
|
||
lNSRange.location := lSelInfo.SelStart;
|
||
lNSRange.length := lSelInfo.SelLength;
|
||
Result := NSValue.valueWithRange(lNSRange);
|
||
finally
|
||
lSelInfo.Free;
|
||
end;
|
||
//{$ifdef VerboseCDAccessibility}
|
||
//DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilitySizeAttribute Result=%d,%d', [lSize.CX, lSize.CY]));
|
||
//{$endif}
|
||
end
|
||
//
|
||
// VisibleCharacterRange
|
||
//
|
||
// Range of characters that are scrolled into view in an editable text element. May be settable.
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityVisibleCharacterRangeAttribute) then
|
||
begin
|
||
lVisibleTextInfo := GetVisibleTextInfo();
|
||
try
|
||
lNSRange.location := lVisibleTextInfo.VisibleTextStart;
|
||
lNSRange.length := lVisibleTextInfo.VisibleTextLength;
|
||
Result := NSValue.valueWithRange(lNSRange);
|
||
finally
|
||
lVisibleTextInfo.Free;
|
||
end;
|
||
//{$ifdef VerboseCDAccessibility}
|
||
//DebugLn(Format(':<[TCocoaAccessibleObject.accessibilityAttributeValue] NSAccessibilityVisibleCharacterRangeAttribute Result=%d,%d', [lSize.CX, lSize.CY]));
|
||
//{$endif}
|
||
end
|
||
//
|
||
// This one we use to put LCL object and class names to help debugging =)
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityUnitDescriptionAttribute) then
|
||
begin
|
||
Result := NSStringUtf8(LCLControl.Name+':'+LCLControl.ClassName);
|
||
end;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityIsAttributeSettable(
|
||
attribute: NSString): Boolean;
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn('[TCocoaAccessibleObject.accessibilityIsAttributeSettable]');
|
||
{$endif}
|
||
Result := False;
|
||
|
||
//
|
||
// Value - The element’s value. May be settable.
|
||
//
|
||
if attribute.isEqualToString(NSAccessibilityValueAttribute) then
|
||
begin
|
||
if LCLAcc.AccessibleRole in [larComboBox, larTextEditorMultiline, larTextEditorSingleline] then
|
||
begin
|
||
Result := True;
|
||
end;
|
||
end
|
||
//
|
||
// Always Settable attributes
|
||
//
|
||
else if attribute.isEqualToString(NSAccessibilityFocusedAttribute) or
|
||
attribute.isEqualToString(NSAccessibilitySelectedTextAttribute) or
|
||
attribute.isEqualToString(NSAccessibilitySelectedTextRangeAttribute) or
|
||
attribute.isEqualToString(NSAccessibilityVisibleCharacterRangeAttribute) then
|
||
begin
|
||
Result := True;
|
||
end;
|
||
end;
|
||
|
||
procedure TCocoaAccessibleObject.accessibilitySetValue_forAttribute(_value: id;
|
||
attribute: NSString);
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':>[TCocoaAccessibleObject.accessibilitySetValue_forAttribute]');
|
||
{$endif}
|
||
if attribute.isEqualToString(NSAccessibilityFocusedAttribute) then
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn(':<[TCocoaAccessibleObject.accessibilitySetValue_forAttribute] Control=%s:%s Value=%d',
|
||
[LCLControl.Name, LCLControl.ClassName, NSNumber(value).intValue()]);
|
||
{$endif}
|
||
if not (LCLControl is TWinControl) then Exit;
|
||
if not NSNumber(value).boolValue() then Exit;
|
||
if LCLInjectedControl <> nil then LCLInjectedControl.SetFocus()
|
||
else TWinControl(LCLControl).SetFocus();
|
||
end
|
||
else if attribute.isEqualToString(NSAccessibilityValueAttribute) then
|
||
begin
|
||
LCLControl.Caption := NSStringToString(value);
|
||
end;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityParameterizedAttributeNames: NSArray;
|
||
var
|
||
lResult: NSMutableArray;
|
||
lCocoaRole: NSString;
|
||
begin
|
||
lResult := NSMutableArray.array_();
|
||
|
||
lCocoaRole := TCocoaCustomControl.LazRoleToCocoaRole(LCLAcc.AccessibleRole);
|
||
|
||
Result := lResult;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityAttributeValue_forParameter(
|
||
attribute: NSString; parameter: id): id;
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn('[TCocoaAccessibleObject.accessibilityAttributeValue_forParameter]');
|
||
{$endif}
|
||
Result := nil;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityActionNames: NSArray;
|
||
var
|
||
lResult: NSMutableArray;
|
||
lCocoaRole: NSString;
|
||
begin
|
||
{$ifdef VerboseCDAccessibility}
|
||
DebugLn('[TCocoaAccessibleObject.accessibilityActionNames]');
|
||
{$endif}
|
||
lResult := NSMutableArray.array_();
|
||
|
||
lCocoaRole := TCocoaCustomControl.LazRoleToCocoaRole(LCLAcc.AccessibleRole);
|
||
if lCocoaRole.caseInsensitiveCompare(NSAccessibilityButtonRole) = NSOrderedSame then
|
||
begin
|
||
lResult.addObject(NSAccessibilityPressAction);
|
||
end;
|
||
|
||
Result := lResult;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityActionDescription(action: NSString): NSString;
|
||
begin
|
||
if action = NSAccessibilityPressAction then Result := NSSTR('Press')
|
||
else Result := NSSTR('');
|
||
end;
|
||
|
||
procedure TCocoaAccessibleObject.accessibilityPerformAction(action: NSString);
|
||
begin
|
||
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityIsIgnored: Boolean;
|
||
begin
|
||
Result := LCLAcc.AccessibleRole = larIgnore;
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityHitTest(point: NSPoint): id;
|
||
begin
|
||
Result := inherited accessibilityHitTest(point);
|
||
end;
|
||
|
||
function TCocoaAccessibleObject.accessibilityFocusedUIElement: id;
|
||
begin
|
||
Result := inherited accessibilityFocusedUIElement;
|
||
end;
|
||
|
||
{ TCocoaMenu }
|
||
|
||
procedure TCocoaMenu.lclItemSelected(sender: id);
|
||
begin
|
||
|
||
end;
|
||
|
||
{ TCocoaMenuItem }
|
||
|
||
procedure TCocoaMenuItem.lclItemSelected(sender: id);
|
||
begin
|
||
|
||
end;
|
||
|
||
procedure SetViewDefaults(AView:NSView);
|
||
begin
|
||
if not Assigned(AView) then Exit;
|
||
AView.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin);
|
||
end;
|
||
|
||
end.
|
||
|