|
|
@ -631,7 +631,7 @@ impl SoftwareKeyboard { |
|
|
|
// A reimplementation of `swkbdInputText` from `libctru/source/applets/swkbd.c`. Allows us to
|
|
|
|
// A reimplementation of `swkbdInputText` from `libctru/source/applets/swkbd.c`. Allows us to
|
|
|
|
// get text from the software keyboard and put it directly into a `String` without requiring
|
|
|
|
// get text from the software keyboard and put it directly into a `String` without requiring
|
|
|
|
// an intermediate fixed-size buffer
|
|
|
|
// an intermediate fixed-size buffer
|
|
|
|
unsafe fn swkbd_input_text(swkbd: *mut SwkbdState, buf: &mut Vec<u8>) -> SwkbdButton { |
|
|
|
fn swkbd_input_text(swkbd: &mut SwkbdState, buf: &mut Vec<u8>) -> SwkbdButton { |
|
|
|
use ctru_sys::{ |
|
|
|
use ctru_sys::{ |
|
|
|
MEMPERM_READ, MEMPERM_WRITE, R_FAILED, SWKBD_BUTTON_LEFT, SWKBD_BUTTON_MIDDLE, |
|
|
|
MEMPERM_READ, MEMPERM_WRITE, R_FAILED, SWKBD_BUTTON_LEFT, SWKBD_BUTTON_MIDDLE, |
|
|
|
SWKBD_BUTTON_NONE, SWKBD_BUTTON_RIGHT, SWKBD_D0_CLICK, SWKBD_D1_CLICK0, |
|
|
|
SWKBD_BUTTON_NONE, SWKBD_BUTTON_RIGHT, SWKBD_D0_CLICK, SWKBD_D1_CLICK0, |
|
|
@ -639,22 +639,22 @@ impl SoftwareKeyboard { |
|
|
|
SWKBD_FILTER_CALLBACK, SWKBD_OUTOFMEM, |
|
|
|
SWKBD_FILTER_CALLBACK, SWKBD_OUTOFMEM, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let mut extra = unsafe { (*swkbd).__bindgen_anon_1.extra }; |
|
|
|
let mut extra = unsafe { swkbd.__bindgen_anon_1.extra }; |
|
|
|
|
|
|
|
|
|
|
|
// Calculate shared mem size
|
|
|
|
// Calculate shared mem size
|
|
|
|
let mut shared_mem_size = 0; |
|
|
|
let mut shared_mem_size = 0; |
|
|
|
|
|
|
|
|
|
|
|
shared_mem_size += |
|
|
|
shared_mem_size += |
|
|
|
(std::mem::size_of::<u16>() * ((*swkbd).max_text_len as usize + 1) + 3) & !3; |
|
|
|
(std::mem::size_of::<u16>() * (swkbd.max_text_len as usize + 1) + 3) & !3; |
|
|
|
|
|
|
|
|
|
|
|
let dict_off = shared_mem_size; |
|
|
|
let dict_off = shared_mem_size; |
|
|
|
|
|
|
|
|
|
|
|
shared_mem_size += |
|
|
|
shared_mem_size += |
|
|
|
(std::mem::size_of::<SwkbdDictWord>() * (*swkbd).dict_word_count as usize + 3) & !3; |
|
|
|
(std::mem::size_of::<SwkbdDictWord>() * swkbd.dict_word_count as usize + 3) & !3; |
|
|
|
|
|
|
|
|
|
|
|
let status_off = shared_mem_size; |
|
|
|
let status_off = shared_mem_size; |
|
|
|
|
|
|
|
|
|
|
|
shared_mem_size += if (*swkbd).initial_learning_offset >= 0 { |
|
|
|
shared_mem_size += if swkbd.initial_learning_offset >= 0 { |
|
|
|
std::mem::size_of::<SwkbdStatusData>() |
|
|
|
std::mem::size_of::<SwkbdStatusData>() |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
0 |
|
|
|
0 |
|
|
@ -662,25 +662,25 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
let learning_off = shared_mem_size; |
|
|
|
let learning_off = shared_mem_size; |
|
|
|
|
|
|
|
|
|
|
|
shared_mem_size += if (*swkbd).initial_learning_offset >= 0 { |
|
|
|
shared_mem_size += if swkbd.initial_learning_offset >= 0 { |
|
|
|
std::mem::size_of::<SwkbdLearningData>() |
|
|
|
std::mem::size_of::<SwkbdLearningData>() |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
0 |
|
|
|
0 |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).save_state_flags & (1 << 0) != 0 { |
|
|
|
if swkbd.save_state_flags & (1 << 0) != 0 { |
|
|
|
(*swkbd).status_offset = shared_mem_size as _; |
|
|
|
swkbd.status_offset = shared_mem_size as _; |
|
|
|
shared_mem_size += std::mem::size_of::<SwkbdStatusData>(); |
|
|
|
shared_mem_size += std::mem::size_of::<SwkbdStatusData>(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).save_state_flags & (1 << 1) != 0 { |
|
|
|
if swkbd.save_state_flags & (1 << 1) != 0 { |
|
|
|
(*swkbd).learning_offset = shared_mem_size as _; |
|
|
|
swkbd.learning_offset = shared_mem_size as _; |
|
|
|
shared_mem_size += std::mem::size_of::<SwkbdLearningData>(); |
|
|
|
shared_mem_size += std::mem::size_of::<SwkbdLearningData>(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
shared_mem_size = (shared_mem_size + 0xFFF) & !0xFFF; |
|
|
|
shared_mem_size = (shared_mem_size + 0xFFF) & !0xFFF; |
|
|
|
|
|
|
|
|
|
|
|
(*swkbd).shared_memory_size = shared_mem_size; |
|
|
|
swkbd.shared_memory_size = shared_mem_size; |
|
|
|
|
|
|
|
|
|
|
|
// Allocate shared mem
|
|
|
|
// Allocate shared mem
|
|
|
|
unsafe { SWKBD_SHARED_MEM = libc::memalign(0x1000, shared_mem_size).cast() }; |
|
|
|
unsafe { SWKBD_SHARED_MEM = libc::memalign(0x1000, shared_mem_size).cast() }; |
|
|
@ -688,7 +688,7 @@ impl SoftwareKeyboard { |
|
|
|
let mut swkbd_shared_mem_handle = 0; |
|
|
|
let mut swkbd_shared_mem_handle = 0; |
|
|
|
|
|
|
|
|
|
|
|
if unsafe { SWKBD_SHARED_MEM.is_null() } { |
|
|
|
if unsafe { SWKBD_SHARED_MEM.is_null() } { |
|
|
|
(*swkbd).result = SWKBD_OUTOFMEM; |
|
|
|
swkbd.result = SWKBD_OUTOFMEM; |
|
|
|
return SWKBD_BUTTON_NONE; |
|
|
|
return SWKBD_BUTTON_NONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -705,15 +705,16 @@ impl SoftwareKeyboard { |
|
|
|
if R_FAILED(res) { |
|
|
|
if R_FAILED(res) { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::free(SWKBD_SHARED_MEM); |
|
|
|
libc::free(SWKBD_SHARED_MEM); |
|
|
|
(*swkbd).result = SWKBD_OUTOFMEM; |
|
|
|
swkbd.result = SWKBD_OUTOFMEM; |
|
|
|
return SWKBD_BUTTON_NONE; |
|
|
|
return SWKBD_BUTTON_NONE; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Copy stuff to shared mem
|
|
|
|
// Copy stuff to shared mem
|
|
|
|
if !extra.initial_text.is_null() { |
|
|
|
if !extra.initial_text.is_null() { |
|
|
|
(*swkbd).initial_text_offset = 0; |
|
|
|
swkbd.initial_text_offset = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
let utf16_iter = CStr::from_ptr(extra.initial_text) |
|
|
|
let utf16_iter = CStr::from_ptr(extra.initial_text) |
|
|
|
.to_str() |
|
|
|
.to_str() |
|
|
|
.unwrap() |
|
|
|
.unwrap() |
|
|
@ -724,23 +725,24 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
for ch in utf16_iter { |
|
|
|
for ch in utf16_iter { |
|
|
|
*initial_text_cursor = ch; |
|
|
|
*initial_text_cursor = ch; |
|
|
|
unsafe { initial_text_cursor = initial_text_cursor.add(1) }; |
|
|
|
initial_text_cursor = initial_text_cursor.add(1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !extra.dict.is_null() { |
|
|
|
if !extra.dict.is_null() { |
|
|
|
(*swkbd).dict_offset = dict_off as _; |
|
|
|
swkbd.dict_offset = dict_off as _; |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memcpy( |
|
|
|
libc::memcpy( |
|
|
|
SWKBD_SHARED_MEM.add(dict_off), |
|
|
|
SWKBD_SHARED_MEM.add(dict_off), |
|
|
|
extra.dict.cast(), |
|
|
|
extra.dict.cast(), |
|
|
|
std::mem::size_of::<SwkbdDictWord>() * (*swkbd).dict_word_count as usize, |
|
|
|
std::mem::size_of::<SwkbdDictWord>() * swkbd.dict_word_count as usize, |
|
|
|
) |
|
|
|
) |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).initial_status_offset >= 0 { |
|
|
|
if swkbd.initial_status_offset >= 0 { |
|
|
|
(*swkbd).initial_status_offset = status_off as _; |
|
|
|
swkbd.initial_status_offset = status_off as _; |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memcpy( |
|
|
|
libc::memcpy( |
|
|
|
SWKBD_SHARED_MEM.add(status_off), |
|
|
|
SWKBD_SHARED_MEM.add(status_off), |
|
|
@ -750,8 +752,8 @@ impl SoftwareKeyboard { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).initial_learning_offset >= 0 { |
|
|
|
if swkbd.initial_learning_offset >= 0 { |
|
|
|
(*swkbd).initial_learning_offset = learning_off as _; |
|
|
|
swkbd.initial_learning_offset = learning_off as _; |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memcpy( |
|
|
|
libc::memcpy( |
|
|
|
SWKBD_SHARED_MEM.add(learning_off), |
|
|
|
SWKBD_SHARED_MEM.add(learning_off), |
|
|
@ -762,17 +764,17 @@ impl SoftwareKeyboard { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if extra.callback.is_some() { |
|
|
|
if extra.callback.is_some() { |
|
|
|
(*swkbd).filter_flags |= SWKBD_FILTER_CALLBACK; |
|
|
|
swkbd.filter_flags |= SWKBD_FILTER_CALLBACK; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
(*swkbd).filter_flags &= !SWKBD_FILTER_CALLBACK; |
|
|
|
swkbd.filter_flags &= !SWKBD_FILTER_CALLBACK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Launch swkbd
|
|
|
|
// Launch swkbd
|
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memset( |
|
|
|
libc::memset( |
|
|
|
std::ptr::addr_of_mut!((*swkbd).__bindgen_anon_1.reserved).cast(), |
|
|
|
std::ptr::addr_of_mut!(swkbd.__bindgen_anon_1.reserved).cast(), |
|
|
|
0, |
|
|
|
0, |
|
|
|
std::mem::size_of_val(&(*swkbd).__bindgen_anon_1.reserved), |
|
|
|
swkbd.__bindgen_anon_1.reserved.len(), |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if extra.callback.is_some() { |
|
|
|
if extra.callback.is_some() { |
|
|
@ -784,7 +786,7 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
aptLaunchLibraryApplet( |
|
|
|
aptLaunchLibraryApplet( |
|
|
|
APPID_SOFTWARE_KEYBOARD, |
|
|
|
APPID_SOFTWARE_KEYBOARD, |
|
|
|
swkbd.cast(), |
|
|
|
swkbd as *mut _ as *mut _, |
|
|
|
std::mem::size_of::<SwkbdState>(), |
|
|
|
std::mem::size_of::<SwkbdState>(), |
|
|
|
swkbd_shared_mem_handle, |
|
|
|
swkbd_shared_mem_handle, |
|
|
|
); |
|
|
|
); |
|
|
@ -796,20 +798,18 @@ impl SoftwareKeyboard { |
|
|
|
let _ = svcCloseHandle(swkbd_shared_mem_handle); |
|
|
|
let _ = svcCloseHandle(swkbd_shared_mem_handle); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let button = match (*swkbd).result { |
|
|
|
let button = match swkbd.result { |
|
|
|
SWKBD_D1_CLICK0 | SWKBD_D2_CLICK0 => SWKBD_BUTTON_LEFT, |
|
|
|
SWKBD_D1_CLICK0 | SWKBD_D2_CLICK0 => SWKBD_BUTTON_LEFT, |
|
|
|
SWKBD_D2_CLICK1 => SWKBD_BUTTON_MIDDLE, |
|
|
|
SWKBD_D2_CLICK1 => SWKBD_BUTTON_MIDDLE, |
|
|
|
SWKBD_D0_CLICK | SWKBD_D1_CLICK1 | SWKBD_D2_CLICK2 => SWKBD_BUTTON_RIGHT, |
|
|
|
SWKBD_D0_CLICK | SWKBD_D1_CLICK1 | SWKBD_D2_CLICK2 => SWKBD_BUTTON_RIGHT, |
|
|
|
_ => SWKBD_BUTTON_NONE, |
|
|
|
_ => SWKBD_BUTTON_NONE, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let text16 = if (*swkbd).text_length > 0 { |
|
|
|
let text16 = if swkbd.text_length > 0 { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
widestring::Utf16Str::from_slice(std::slice::from_raw_parts( |
|
|
|
widestring::Utf16Str::from_slice(std::slice::from_raw_parts( |
|
|
|
SWKBD_SHARED_MEM |
|
|
|
SWKBD_SHARED_MEM.add(swkbd.text_offset as _).cast::<u16>(), |
|
|
|
.add((*swkbd).text_offset as _) |
|
|
|
swkbd.text_length as usize, |
|
|
|
.cast::<u16>(), |
|
|
|
|
|
|
|
(*swkbd).text_length as usize, |
|
|
|
|
|
|
|
)) |
|
|
|
)) |
|
|
|
.unwrap() |
|
|
|
.unwrap() |
|
|
|
} |
|
|
|
} |
|
|
@ -819,21 +819,21 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
buf.extend(text16.encode_utf8()); |
|
|
|
buf.extend(text16.encode_utf8()); |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).save_state_flags & (1 << 0) != 0 { |
|
|
|
if swkbd.save_state_flags & (1 << 0) != 0 { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memcpy( |
|
|
|
libc::memcpy( |
|
|
|
extra.status_data.cast(), |
|
|
|
extra.status_data.cast(), |
|
|
|
SWKBD_SHARED_MEM.add((*swkbd).status_offset as _), |
|
|
|
SWKBD_SHARED_MEM.add(swkbd.status_offset as _), |
|
|
|
std::mem::size_of::<SwkbdStatusData>(), |
|
|
|
std::mem::size_of::<SwkbdStatusData>(), |
|
|
|
) |
|
|
|
) |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).save_state_flags & (1 << 1) != 0 { |
|
|
|
if swkbd.save_state_flags & (1 << 1) != 0 { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
libc::memcpy( |
|
|
|
libc::memcpy( |
|
|
|
extra.learning_data.cast(), |
|
|
|
extra.learning_data.cast(), |
|
|
|
SWKBD_SHARED_MEM.add((*swkbd).learning_offset as _), |
|
|
|
SWKBD_SHARED_MEM.add(swkbd.learning_offset as _), |
|
|
|
std::mem::size_of::<SwkbdLearningData>(), |
|
|
|
std::mem::size_of::<SwkbdLearningData>(), |
|
|
|
) |
|
|
|
) |
|
|
|
}; |
|
|
|
}; |
|
|
@ -854,8 +854,8 @@ impl SoftwareKeyboard { |
|
|
|
msg: *mut libc::c_void, |
|
|
|
msg: *mut libc::c_void, |
|
|
|
msg_size: libc::size_t, |
|
|
|
msg_size: libc::size_t, |
|
|
|
) { |
|
|
|
) { |
|
|
|
let extra = user.cast::<SwkbdExtra>(); |
|
|
|
let extra = &mut *user.cast::<SwkbdExtra>(); |
|
|
|
let swkbd = msg.cast::<SwkbdState>(); |
|
|
|
let swkbd = &mut *msg.cast::<SwkbdState>(); |
|
|
|
|
|
|
|
|
|
|
|
if sender != ctru_sys::APPID_SOFTWARE_KEYBOARD |
|
|
|
if sender != ctru_sys::APPID_SOFTWARE_KEYBOARD |
|
|
|
|| msg_size != std::mem::size_of::<SwkbdState>() |
|
|
|
|| msg_size != std::mem::size_of::<SwkbdState>() |
|
|
@ -865,10 +865,8 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
let text16 = unsafe { |
|
|
|
let text16 = unsafe { |
|
|
|
widestring::Utf16Str::from_slice(std::slice::from_raw_parts( |
|
|
|
widestring::Utf16Str::from_slice(std::slice::from_raw_parts( |
|
|
|
SWKBD_SHARED_MEM |
|
|
|
SWKBD_SHARED_MEM.add(swkbd.text_offset as _).cast::<u16>(), |
|
|
|
.add((*swkbd).text_offset as _) |
|
|
|
swkbd.text_length as usize + 1, |
|
|
|
.cast::<u16>(), |
|
|
|
|
|
|
|
(*swkbd).text_length as usize + 1, |
|
|
|
|
|
|
|
)) |
|
|
|
)) |
|
|
|
.unwrap() |
|
|
|
.unwrap() |
|
|
|
}; |
|
|
|
}; |
|
|
@ -883,8 +881,8 @@ impl SoftwareKeyboard { |
|
|
|
|
|
|
|
|
|
|
|
let mut retmsg = std::ptr::null(); |
|
|
|
let mut retmsg = std::ptr::null(); |
|
|
|
|
|
|
|
|
|
|
|
(*swkbd).callback_result = (*extra).callback.unwrap()( |
|
|
|
swkbd.callback_result = extra.callback.unwrap()( |
|
|
|
(*extra).callback_user, |
|
|
|
extra.callback_user, |
|
|
|
&mut retmsg, |
|
|
|
&mut retmsg, |
|
|
|
text8.as_ptr(), |
|
|
|
text8.as_ptr(), |
|
|
|
text8.len(), |
|
|
|
text8.len(), |
|
|
@ -899,9 +897,9 @@ impl SoftwareKeyboard { |
|
|
|
"\0" |
|
|
|
"\0" |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let callback_msg = &mut (*swkbd).callback_msg; |
|
|
|
let callback_msg = &mut swkbd.callback_msg; |
|
|
|
|
|
|
|
|
|
|
|
if (*swkbd).callback_result > SWKBD_CALLBACK_OK as _ { |
|
|
|
if swkbd.callback_result > SWKBD_CALLBACK_OK as _ { |
|
|
|
for (idx, ch) in retmsg.encode_utf16().take(callback_msg.len()).enumerate() { |
|
|
|
for (idx, ch) in retmsg.encode_utf16().take(callback_msg.len()).enumerate() { |
|
|
|
callback_msg[idx] = ch; |
|
|
|
callback_msg[idx] = ch; |
|
|
|
} |
|
|
|
} |
|
|
@ -913,7 +911,7 @@ impl SoftwareKeyboard { |
|
|
|
envGetAptAppId(), |
|
|
|
envGetAptAppId(), |
|
|
|
sender, |
|
|
|
sender, |
|
|
|
APTCMD_MESSAGE, |
|
|
|
APTCMD_MESSAGE, |
|
|
|
swkbd.cast(), |
|
|
|
swkbd as *mut _ as *mut _, |
|
|
|
std::mem::size_of::<SwkbdState>() as _, |
|
|
|
std::mem::size_of::<SwkbdState>() as _, |
|
|
|
0, |
|
|
|
0, |
|
|
|
); |
|
|
|
); |
|
|
|