android – 如何从Delphi访问KeyCharacterMap.getEvents函数返回的元素?

我正在尝试使用Delphi的JKeyCharacterMap.getEvents函数从Char获取KeyCode.

所以我正在使用这段代码.

uses
  FMX.Platform.Android,
  Androidapi.Helpers,
  Androidapi.JNIBridge;

var
  s : string;
  PlatformKey : Word;
  FKeyCharacterMap: JKeyCharacterMap;
  events  : TJavaObjectArray<JKeyEvent>;
  event   : JKeyEvent;
  chars: TJavaArray<Char>;
  l : integer;
begin
  FKeyCharacterMap := TJKeyCharacterMap.JavaClass.load(TJKeyCharacterMap.JavaClass.BUILT_IN_KEYBOARD);

  chars    := TJavaArray<Char>.Create(1);
  chars[0] := 'A';
  events   := FKeyCharacterMap.getEvents(chars);

  l := events.Length; //this returns 4
  if l>0 then
  begin
   event := events[0]; // Segmentation fault (11)
   PlatformKey := event.getKeyCode;
  end;

end;

但不幸的是,一旦我尝试访问JKeyCharacterMap.getEvents函数返回的数组的某些元素,我就得到了一个Segmentation fault(11)异常.

所以问题是,如何从Delphi访问KeyCharacterMap.getEvents函数返回的元素?

UPDATE

我使用断点调试,其中引发异常并且App在此函数Androidapi.JNIBridge.TJNIResolver.GetObjectArrayElement上失败,因为JNIEnvRes变量为nil

class function TJNIResolver.GetObjectArrayElement(AArray: JNIObjectArray; Index: JNISize): JNIObject;
begin
  GetJNIEnv;
  //JNIEnvRes is nil
  Result := JNIEnvRes^.GetObjectArrayElement(JNIEnvRes, AArray, Index);
end;

GetJNIEnv函数未能为JNIEnvRes变量赋值.

class function TJNIResolver.GetJNIEnv: PJNIEnv;
begin
  if JNIEnvRes = nil then
    PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @JNIEnvRes, nil);
  Result := JNIEnvRes;
end;

但我不知道是什么导致了这种行为.

最佳答案 在我的测试中,GetJNIEnv运行良好.虽然它似乎返回nil,但它是Delphi的调试器,显示JNIEnvRes的错误值,因为您可以看到Result不是nil:

class function TJNIResolver.GetJNIEnv: PJNIEnv;
begin
  if JNIEnvRes = nil then
    PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @JNIEnvRes, nil);
  Result := JNIEnvRes; 
  // debugger shows JNIEnvRes as nil and Result as not nil
end;

实际上,GetObjectArrayElement正在返回预期的对象,但由于FClassID为nil,后续的WrapJNIReturn是失败的对象.需要FClassID来创建具有适当类的包装器对象.

WrapJNIReturn(AObject, FClassID, FBaseType.Handle, Result);

您有两种方法可以解决这个问题:

1.获取原始项目并将其包装在具有正确类型的对象中

events := FKeyCharacterMap.getEvents(chars);

l := events.Length; //this returns 4
if l>0 then
begin
  //event := events[0]; // Fails!
  event := TJKeyEvent.Wrap(events.GetRawItem(0)); // works
  PlatformKey := event.getKeyCode;
end;

2.使用正确的ClassID将数组包装在一个数组中

events := TJavaObjectArray<JKeyEvent>.Wrap(FKeyCharacterMap.getEvents(chars));

l := events.Length; //this returns 4
if l>0 then
begin
  event := events[0]; // now working well
  PlatformKey := event.getKeyCode;
end;
点赞