Как я могу получить доступ к элементам, возвращаемым функцией KeyCharacterMap.getEvents из Delphi?

Я пытаюсь использовать функцию JKeyCharacterMap.getEvents из Delphi, чтобы получить KeyCode из Char.

Поэтому я использую этот код.

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).

Итак, вопрос в том, как я могу получить доступ к элементам, возвращаемым функцией KeyCharacterMap.getEvents из Delphi?

ОБНОВЛЕНИЕ

Я отлаживал, используя точку останова, когда возникает исключение, и приложение не работает с этой функцией Androidapi.JNIBridge.TJNIResolver.GetObjectArrayElement, потому что переменная JNIEnvRes равна нулю

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;

Но я не знаю, что вызывает такое поведение.


person Salvador    schedule 19.06.2016    source источник
comment
Поставьте точку останова на первую строку сбойной функции и пройдитесь по коду, чтобы определить, какая строка вызывает ошибку. Возможно, массив, к которому вы обращаетесь, не существует, по крайней мере, в то время, когда вы его изучаете.   -  person Admiral Noisey Bottom    schedule 19.06.2016
comment
Спасибо за совет, я только что обновил ответ.   -  person Salvador    schedule 20.06.2016


Ответы (1)


В моем тестировании 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 возвращает ожидаемый объект, но следующий WrapJNIReturn терпит неудачу из-за того, что FClassID является nil. 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;
person JRL    schedule 24.06.2016