11use std:: sync:: Arc ;
22
3+ use jni:: sys:: jint;
34use jni:: {
45 objects:: { GlobalRef , JClass , JMethodID , JObject , JStaticMethodID , JValue } ,
56 signature:: { Primitive , ReturnType } ,
6- JNIEnv ,
7+ JNIEnv , JNIVersion , JavaVM ,
78} ;
8- use jni_sys:: jint;
99
10- use crate :: {
11- input:: { Keycode , MetaState } ,
12- jni_utils:: CloneJavaVM ,
13- } ;
10+ use crate :: input:: { Keycode , MetaState } ;
1411
1512use crate :: {
1613 error:: { AppError , InternalAppError } ,
@@ -94,7 +91,7 @@ pub enum KeyMapChar {
9491#[ derive( Debug ) ]
9592pub ( crate ) struct KeyCharacterMapBinding {
9693 //vm: JavaVM,
97- klass : GlobalRef ,
94+ klass : GlobalRef < JClass < ' static > > ,
9895 get_method_id : JMethodID ,
9996 get_dead_char_method_id : JStaticMethodID ,
10097 get_keyboard_type_method_id : JMethodID ,
@@ -213,18 +210,31 @@ impl KeyCharacterMapBinding {
213210}
214211
215212/// Describes the keys provided by a keyboard device and their associated labels.
216- #[ derive( Clone , Debug ) ]
213+ #[ derive( Debug ) ]
217214pub struct KeyCharacterMap {
218- jvm : CloneJavaVM ,
215+ jvm : JavaVM ,
219216 binding : Arc < KeyCharacterMapBinding > ,
220- key_map : GlobalRef ,
217+ key_map : GlobalRef < JObject < ' static > > ,
218+ }
219+ impl Clone for KeyCharacterMap {
220+ fn clone ( & self ) -> Self {
221+ let jvm = self . jvm . clone ( ) ;
222+ jvm. attach_current_thread :: < _ , _ , jni:: errors:: Error > ( JNIVersion :: V1_4 , |env| {
223+ Ok ( Self {
224+ jvm : jvm. clone ( ) ,
225+ binding : Arc :: clone ( & self . binding ) ,
226+ key_map : env. new_global_ref ( & self . key_map ) ?,
227+ } )
228+ } )
229+ . expect ( "Failed to attach thread to JVM and clone key map" )
230+ }
221231}
222232
223233impl KeyCharacterMap {
224234 pub ( crate ) fn new (
225- jvm : CloneJavaVM ,
235+ jvm : JavaVM ,
226236 binding : Arc < KeyCharacterMapBinding > ,
227- key_map : GlobalRef ,
237+ key_map : GlobalRef < JObject < ' static > > ,
228238 ) -> Self {
229239 Self {
230240 jvm,
@@ -247,41 +257,39 @@ impl KeyCharacterMap {
247257 /// is caught.
248258 pub fn get ( & self , key_code : Keycode , meta_state : MetaState ) -> Result < KeyMapChar , AppError > {
249259 let key_code: u32 = key_code. into ( ) ;
250- let key_code = key_code as jni_sys :: jint ;
260+ let key_code = key_code as jni :: sys :: jint ;
251261 let meta_state: u32 = meta_state. 0 ;
252- let meta_state = meta_state as jni_sys :: jint ;
262+ let meta_state = meta_state as jni :: sys :: jint ;
253263
254- // Since we expect this API to be called from the `main` thread then we expect to already be
255- // attached to the JVM
256- //
257- // Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
258- // borrow rules that ensure we can only add local references to the top JNI frame.
259- let mut env = self . jvm . get_env ( ) . map_err ( |err| {
260- let err: InternalAppError = err. into ( ) ;
261- err
262- } ) ?;
263- let unicode = self
264- . binding
265- . get ( & mut env, self . key_map . as_obj ( ) , key_code, meta_state) ?;
266- let unicode = unicode as u32 ;
264+ let vm = self . jvm . clone ( ) ;
265+ vm. attach_current_thread :: < _ , _ , InternalAppError > ( JNIVersion :: V1_4 , |env| {
266+ let unicode = self
267+ . binding
268+ . get ( env, self . key_map . as_obj ( ) , key_code, meta_state) ?;
269+ let unicode = unicode as u32 ;
267270
268- const COMBINING_ACCENT : u32 = 0x80000000 ;
269- const COMBINING_ACCENT_MASK : u32 = !COMBINING_ACCENT ;
271+ const COMBINING_ACCENT : u32 = 0x80000000 ;
272+ const COMBINING_ACCENT_MASK : u32 = !COMBINING_ACCENT ;
270273
271- if unicode == 0 {
272- Ok ( KeyMapChar :: None )
273- } else if unicode & COMBINING_ACCENT == COMBINING_ACCENT {
274- let accent = unicode & COMBINING_ACCENT_MASK ;
275- // Safety: assumes Android key maps don't contain invalid unicode characters
276- Ok ( KeyMapChar :: CombiningAccent ( unsafe {
277- char:: from_u32_unchecked ( accent)
278- } ) )
279- } else {
280- // Safety: assumes Android key maps don't contain invalid unicode characters
281- Ok ( KeyMapChar :: Unicode ( unsafe {
282- char:: from_u32_unchecked ( unicode)
283- } ) )
284- }
274+ if unicode == 0 {
275+ Ok ( KeyMapChar :: None )
276+ } else if unicode & COMBINING_ACCENT == COMBINING_ACCENT {
277+ let accent = unicode & COMBINING_ACCENT_MASK ;
278+ // Safety: assumes Android key maps don't contain invalid unicode characters
279+ Ok ( KeyMapChar :: CombiningAccent ( unsafe {
280+ char:: from_u32_unchecked ( accent)
281+ } ) )
282+ } else {
283+ // Safety: assumes Android key maps don't contain invalid unicode characters
284+ Ok ( KeyMapChar :: Unicode ( unsafe {
285+ char:: from_u32_unchecked ( unicode)
286+ } ) )
287+ }
288+ } )
289+ . map_err ( |err| {
290+ let err: InternalAppError = err. into ( ) ;
291+ err. into ( )
292+ } )
285293 }
286294
287295 /// Get the character that is produced by combining the dead key producing accent with the key producing character c.
@@ -297,28 +305,24 @@ impl KeyCharacterMap {
297305 accent_char : char ,
298306 base_char : char ,
299307 ) -> Result < Option < char > , AppError > {
300- let accent_char = accent_char as jni_sys :: jint ;
301- let base_char = base_char as jni_sys :: jint ;
308+ let accent_char = accent_char as jni :: sys :: jint ;
309+ let base_char = base_char as jni :: sys :: jint ;
302310
303- // Since we expect this API to be called from the `main` thread then we expect to already be
304- // attached to the JVM
305- //
306- // Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
307- // borrow rules that ensure we can only add local references to the top JNI frame.
308- let mut env = self . jvm . get_env ( ) . map_err ( |err| {
309- let err: InternalAppError = err. into ( ) ;
310- err
311- } ) ?;
312- let unicode = self
313- . binding
314- . get_dead_char ( & mut env, accent_char, base_char) ?;
315- let unicode = unicode as u32 ;
311+ let vm = self . jvm . clone ( ) ;
312+ vm. attach_current_thread :: < _ , _ , InternalAppError > ( JNIVersion :: V1_4 , |env| {
313+ let unicode = self . binding . get_dead_char ( env, accent_char, base_char) ?;
314+ let unicode = unicode as u32 ;
316315
317- // Safety: assumes Android key maps don't contain invalid unicode characters
318- Ok ( if unicode == 0 {
319- None
320- } else {
321- Some ( unsafe { char:: from_u32_unchecked ( unicode) } )
316+ // Safety: assumes Android key maps don't contain invalid unicode characters
317+ Ok ( if unicode == 0 {
318+ None
319+ } else {
320+ Some ( unsafe { char:: from_u32_unchecked ( unicode) } )
321+ } )
322+ } )
323+ . map_err ( |err| {
324+ let err: InternalAppError = err. into ( ) ;
325+ err. into ( )
322326 } )
323327 }
324328
@@ -332,19 +336,15 @@ impl KeyCharacterMap {
332336 /// a [`AppError::JavaError`] in case there is a spurious JNI error or an exception
333337 /// is caught.
334338 pub fn get_keyboard_type ( & self ) -> Result < KeyboardType , AppError > {
335- // Since we expect this API to be called from the `main` thread then we expect to already be
336- // attached to the JVM
337- //
338- // Safety: there's no other JNIEnv in scope so this env can't be used to subvert the mutable
339- // borrow rules that ensure we can only add local references to the top JNI frame.
340- let mut env = self . jvm . get_env ( ) . map_err ( |err| {
339+ let vm = self . jvm . clone ( ) ;
340+ vm. attach_current_thread :: < _ , _ , InternalAppError > ( JNIVersion :: V1_4 , |env| {
341+ let keyboard_type = self . binding . get_keyboard_type ( env, self . key_map . as_obj ( ) ) ?;
342+ let keyboard_type = keyboard_type as u32 ;
343+ Ok ( keyboard_type. into ( ) )
344+ } )
345+ . map_err ( |err| {
341346 let err: InternalAppError = err. into ( ) ;
342- err
343- } ) ?;
344- let keyboard_type = self
345- . binding
346- . get_keyboard_type ( & mut env, self . key_map . as_obj ( ) ) ?;
347- let keyboard_type = keyboard_type as u32 ;
348- Ok ( keyboard_type. into ( ) )
347+ err. into ( )
348+ } )
349349 }
350350}
0 commit comments