mirror of
https://github.com/mii443/rs-azookey-binding.git
synced 2025-08-22 16:15:35 +00:00
azookey ffi
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -5,3 +5,12 @@ version = 4
|
||||
[[package]]
|
||||
name = "azookey-binding"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
@ -3,3 +3,6 @@ name = "azookey-binding"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.172"
|
||||
|
||||
|
@ -9,7 +9,7 @@ let package = Package(
|
||||
// Products define the executables and libraries a package produces, making them visible to other packages.
|
||||
.library(
|
||||
name: "azookey-swift",
|
||||
type: .static,
|
||||
type: .dynamic,
|
||||
targets: ["azookey-swift"]),
|
||||
.library(
|
||||
name: "ffi",
|
||||
@ -17,7 +17,7 @@ let package = Package(
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/azookey/AzooKeyKanaKanjiConverter", branch: "66a341b7e656c2fff02c1399882e88ee067b3d31")
|
||||
.package(url: "https://github.com/azookey/AzooKeyKanaKanjiConverter", branch: "66a341b7e656c2fff02c1399882e88ee067b3d31", traits: ["Zenzai"])
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package, defining a module or a test suite.
|
||||
@ -26,9 +26,10 @@ let package = Package(
|
||||
.target(
|
||||
name: "azookey-swift",
|
||||
dependencies: [
|
||||
.product(name: "KanaKanjiConverterModule", package: "azookeykanakanjiconverter"),
|
||||
.product(name: "KanaKanjiConverterModuleWithDefaultDictionary", package: "AzooKeyKanaKanjiConverter"),
|
||||
"ffi"
|
||||
]
|
||||
],
|
||||
swiftSettings: [.interoperabilityMode(.Cxx)],
|
||||
),
|
||||
.testTarget(
|
||||
name: "azookey-swiftTests",
|
||||
|
@ -1,7 +1,124 @@
|
||||
// returns first candidate
|
||||
|
||||
import Foundation
|
||||
|
||||
import KanaKanjiConverterModuleWithDefaultDictionary
|
||||
|
||||
import ffi
|
||||
|
||||
@_silgen_name("HelloSwift")
|
||||
@MainActor public func hello_swift() {
|
||||
print("hello_swift")
|
||||
public class ComposingTextWrapper {
|
||||
var value: ComposingText
|
||||
|
||||
init(value: ComposingText) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
@_silgen_name("CreateKanaKanjiConverter")
|
||||
@MainActor public func create_kana_kanji_converter() -> UnsafeMutablePointer<KanaKanjiConverter> {
|
||||
let converter = KanaKanjiConverter()
|
||||
return Unmanaged.passRetained(converter).toOpaque().assumingMemoryBound(
|
||||
to: KanaKanjiConverter.self)
|
||||
}
|
||||
@_silgen_name("DestroyKanaKanjiConverter")
|
||||
@MainActor public func destroy_kana_kanji_converter(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>
|
||||
) {
|
||||
Unmanaged<KanaKanjiConverter>.fromOpaque(converter).release()
|
||||
}
|
||||
@_silgen_name("CreateComposingText")
|
||||
@MainActor public func create_composing_text() -> UnsafeMutablePointer<ComposingTextWrapper> {
|
||||
let c = ComposingTextWrapper(value: ComposingText())
|
||||
return Unmanaged.passRetained(c).toOpaque().assumingMemoryBound(to: ComposingTextWrapper.self)
|
||||
}
|
||||
@_silgen_name("DestroyComposingText")
|
||||
@MainActor public func destroy_composing_text(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>
|
||||
) {
|
||||
Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).release()
|
||||
}
|
||||
@_silgen_name("KanaKanjiConverter_RequestCandidates")
|
||||
@MainActor public func kana_kanji_converter_request_candidates(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>,
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ lengthPtr: UnsafeMutablePointer<Int>,
|
||||
_ context: UnsafePointer<CChar>
|
||||
) -> UnsafeMutablePointer<UnsafeMutablePointer<FFICandidate>> {
|
||||
let c = Unmanaged<KanaKanjiConverter>.fromOpaque(converter).takeUnretainedValue()
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
|
||||
let options = ConvertRequestOptions.withDefaultDictionary(
|
||||
requireJapanesePrediction: true,
|
||||
requireEnglishPrediction: false,
|
||||
keyboardLanguage: .ja_JP,
|
||||
learningType: .nothing,
|
||||
memoryDirectoryURL: URL(filePath: "./"),
|
||||
sharedContainerURL: URL(filePath: "./"),
|
||||
zenzaiMode: .on(
|
||||
weight: URL(filePath: "./ggml-model-Q5_K_M.gguf"), inferenceLimit: 1,
|
||||
requestRichCandidates: true, personalizationMode: nil,
|
||||
versionDependentMode: .v3(.init(profile: "", leftSideContext: String(cString: context)))
|
||||
),
|
||||
preloadDictionary: true,
|
||||
metadata: .init(versionString: "rs-azookey-binding")
|
||||
)
|
||||
|
||||
let candidates: ConversionResult = c.requestCandidates(ct.value, options: options)
|
||||
|
||||
var result: [FFICandidate] = []
|
||||
|
||||
for i in 0..<candidates.mainResults.count {
|
||||
let candidate = candidates.mainResults[i]
|
||||
|
||||
let text = candidate.text
|
||||
let correspondingCount = candidate.correspondingCount
|
||||
|
||||
result.append(
|
||||
FFICandidate(
|
||||
text: UnsafeMutablePointer(mutating: (text as NSString).utf8String!),
|
||||
correspondingCount: Int32(correspondingCount),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let pointer = UnsafeMutablePointer<UnsafeMutablePointer<FFICandidate>>.allocate(
|
||||
capacity: result.count)
|
||||
for i in 0..<result.count {
|
||||
pointer[i] = UnsafeMutablePointer<FFICandidate>.allocate(capacity: 1)
|
||||
pointer[i].pointee = result[i]
|
||||
}
|
||||
lengthPtr.pointee = result.count
|
||||
return pointer
|
||||
}
|
||||
@_silgen_name("KanaKanjiConverter_StopComposition")
|
||||
@MainActor public func kana_kanji_converter_stop_composition(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>,
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>
|
||||
) {
|
||||
let c = Unmanaged<KanaKanjiConverter>.fromOpaque(converter).takeUnretainedValue()
|
||||
c.stopComposition()
|
||||
}
|
||||
@_silgen_name("ComposingText_InsertAtCursorPosition")
|
||||
@MainActor public func composing_text_insert_at_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ text: UnsafePointer<CChar>,
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
let str = String(cString: text)
|
||||
ct.value.insertAtCursorPosition(str, inputStyle: .roman2kana)
|
||||
}
|
||||
@_silgen_name("ComposingText_DeleteForwardFromCursorPosition")
|
||||
@MainActor public func composing_text_delete_forward_from_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ count: Int32
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
ct.value.deleteForwardFromCursorPosition(count: Int(count))
|
||||
}
|
||||
@_silgen_name("ComposingText_DeleteBackwardFromCursorPosition")
|
||||
@MainActor public func composing_text_delete_backward_from_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ count: Int32
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
ct.value.deleteBackwardFromCursorPosition(count: Int(count))
|
||||
}
|
||||
|
@ -5,3 +5,7 @@
|
||||
|
||||
#endif
|
||||
|
||||
struct FFICandidate {
|
||||
char *text;
|
||||
int correspondingCount;
|
||||
};
|
BIN
azookey-swift/llama.lib
Normal file
BIN
azookey-swift/llama.lib
Normal file
Binary file not shown.
29
build.rs
29
build.rs
@ -1,5 +1,7 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let project_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let project_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
|
||||
// Build the Swift library
|
||||
let swift_build_command = format!(
|
||||
@ -18,16 +20,21 @@ fn main() {
|
||||
);
|
||||
}
|
||||
|
||||
// rename the output file to azookey-swift.lib from libazookey-swift.a
|
||||
let output_path = format!(
|
||||
"{}/azookey-swift/.build/release/libazookey-swift.a",
|
||||
// move azookey-swift.dll to the target directory
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
let profile = env::var("PROFILE").unwrap();
|
||||
let target_dir = format!("{}/target/{}", crate_dir, profile);
|
||||
let swift_lib_path = format!(
|
||||
"{}/azookey-swift/.build/release/azookey-swift.dll",
|
||||
project_dir
|
||||
);
|
||||
let new_output_path = format!(
|
||||
"{}/azookey-swift/.build/release/azookey-swift.lib",
|
||||
project_dir
|
||||
);
|
||||
std::fs::rename(&output_path, &new_output_path).expect("Failed to rename file");
|
||||
let target_lib_path = format!("{}/azookey-swift.dll", target_dir);
|
||||
std::fs::copy(&swift_lib_path, &target_lib_path).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to copy azookey-swift.dll to target directory: {}",
|
||||
target_lib_path
|
||||
)
|
||||
});
|
||||
} else {
|
||||
// non-windows
|
||||
let output = std::process::Command::new("sh")
|
||||
@ -50,7 +57,7 @@ fn main() {
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-search={}",
|
||||
std::env::var("SWIFT_LIB_DIR").unwrap()
|
||||
env::var("SWIFT_LIB_DIR").unwrap()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=azookey-swift");
|
||||
println!("cargo:rustc-link-lib=azookey-swift");
|
||||
}
|
||||
|
BIN
ggml-base.dll
Normal file
BIN
ggml-base.dll
Normal file
Binary file not shown.
BIN
ggml-cpu.dll
Normal file
BIN
ggml-cpu.dll
Normal file
Binary file not shown.
BIN
ggml-model-Q5_K_M.gguf
Normal file
BIN
ggml-model-Q5_K_M.gguf
Normal file
Binary file not shown.
BIN
ggml-vulkan.dll
Normal file
BIN
ggml-vulkan.dll
Normal file
Binary file not shown.
258
src/lib.rs
258
src/lib.rs
@ -1,3 +1,257 @@
|
||||
unsafe extern "C" {
|
||||
pub fn HelloSwift();
|
||||
use std::os::raw::c_void;
|
||||
|
||||
use libc::c_int;
|
||||
|
||||
/*
|
||||
@_silgen_name("CreateKanaKanjiConverter")
|
||||
@MainActor public func create_kana_kanji_converter() -> UnsafeMutablePointer<KanaKanjiConverter> {
|
||||
let converter = KanaKanjiConverter()
|
||||
return Unmanaged.passRetained(converter).toOpaque().assumingMemoryBound(
|
||||
to: KanaKanjiConverter.self)
|
||||
}
|
||||
@_silgen_name("DestroyKanaKanjiConverter")
|
||||
@MainActor public func destroy_kana_kanji_converter(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>
|
||||
) {
|
||||
Unmanaged<KanaKanjiConverter>.fromOpaque(converter).release()
|
||||
}
|
||||
@_silgen_name("CreateComposingText")
|
||||
@MainActor public func create_composing_text() -> UnsafeMutablePointer<ComposingTextWrapper> {
|
||||
let c = ComposingTextWrapper(value: ComposingText())
|
||||
return Unmanaged.passRetained(c).toOpaque().assumingMemoryBound(to: ComposingTextWrapper.self)
|
||||
}
|
||||
@_silgen_name("DestroyComposingText")
|
||||
@MainActor public func destroy_composing_text(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>
|
||||
) {
|
||||
Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).release()
|
||||
}
|
||||
@_silgen_name("KanaKanjiConverter_RequestCandidates")
|
||||
@MainActor public func kana_kanji_converter_request_candidates(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>,
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ context: UnsafePointer<CChar>
|
||||
) -> UnsafeMutablePointer<UnsafeMutablePointer<FFICandidate>> {
|
||||
let c = Unmanaged<KanaKanjiConverter>.fromOpaque(converter).takeUnretainedValue()
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
|
||||
let options = ConvertRequestOptions.withDefaultDictionary(
|
||||
requireJapanesePrediction: true,
|
||||
requireEnglishPrediction: false,
|
||||
keyboardLanguage: .ja_JP,
|
||||
learningType: .nothing,
|
||||
memoryDirectoryURL: URL(filePath: "./"),
|
||||
sharedContainerURL: URL(filePath: "./"),
|
||||
zenzaiMode: .on(
|
||||
weight: URL(filePath: "./ggml-model-Q5_K_M.gguf"), inferenceLimit: 1,
|
||||
requestRichCandidates: true, personalizationMode: nil,
|
||||
versionDependentMode: .v3(.init(profile: "", leftSideContext: String(cString: context)))
|
||||
),
|
||||
preloadDictionary: true,
|
||||
metadata: .init(versionString: "rs-azookey-binding")
|
||||
)
|
||||
|
||||
let candidates: ConversionResult = c.requestCandidates(ct.value, options: options)
|
||||
|
||||
var result: [FFICandidate] = []
|
||||
|
||||
for i in 0..<candidates.mainResults.count {
|
||||
let candidate = candidates.mainResults[i];
|
||||
let text = candidate.text
|
||||
let correspondingCount = candidate.correspondingCount
|
||||
|
||||
result.append(
|
||||
FFICandidate(
|
||||
text: UnsafeMutablePointer(mutating: (text as NSString).utf8String!),
|
||||
correspondingCount: Int32(correspondingCount),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let pointer = UnsafeMutablePointer<UnsafeMutablePointer<FFICandidate>>.allocate(capacity: result.count)
|
||||
for i in 0..<result.count {
|
||||
pointer[i] = UnsafeMutablePointer<FFICandidate>.allocate(capacity: 1)
|
||||
pointer[i].pointee = result[i]
|
||||
}
|
||||
return pointer
|
||||
}
|
||||
@_silgen_name("KanaKanjiConverter_StopComposition")
|
||||
@MainActor public func kana_kanji_converter_stop_composition(
|
||||
_ converter: UnsafeMutablePointer<KanaKanjiConverter>,
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>
|
||||
) {
|
||||
let c = Unmanaged<KanaKanjiConverter>.fromOpaque(converter).takeUnretainedValue()
|
||||
c.stopComposition()
|
||||
}
|
||||
@_silgen_name("ComposingText_InsertAtCursorPosition")
|
||||
@MainActor public func composing_text_insert_at_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ text: UnsafePointer<CChar>,
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
let str = String(cString: text)
|
||||
ct.value.insertAtCursorPosition(str, inputStyle: .roman2kana)
|
||||
}
|
||||
@_silgen_name("ComposingText_DeleteForwardFromCursorPosition")
|
||||
@MainActor public func composing_text_delete_forward_from_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ count: Int32
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
ct.value.deleteForwardFromCursorPosition(count: Int(count))
|
||||
}
|
||||
@_silgen_name("ComposingText_DeleteBackwardFromCursorPosition")
|
||||
@MainActor public func composing_text_delete_backward_from_cursor_position(
|
||||
_ composingText: UnsafeMutablePointer<ComposingTextWrapper>,
|
||||
_ count: Int32
|
||||
) {
|
||||
let ct = Unmanaged<ComposingTextWrapper>.fromOpaque(composingText).takeUnretainedValue()
|
||||
ct.value.deleteBackwardFromCursorPosition(count: Int(count))
|
||||
}
|
||||
|
||||
*/
|
||||
unsafe extern "C" {
|
||||
pub fn CreateKanaKanjiConverter() -> *mut c_void;
|
||||
pub fn DestroyKanaKanjiConverter(converter: *mut c_void);
|
||||
pub fn CreateComposingText() -> *mut c_void;
|
||||
pub fn DestroyComposingText(composingText: *mut c_void);
|
||||
pub fn KanaKanjiConverter_RequestCandidates(
|
||||
converter: *mut c_void,
|
||||
composingText: *mut c_void,
|
||||
lengthPtr: *mut c_int,
|
||||
context: *const libc::c_char,
|
||||
) -> *mut *mut FFICandidate;
|
||||
pub fn KanaKanjiConverter_StopComposition(converter: *mut c_void);
|
||||
pub fn ComposingText_InsertAtCursorPosition(
|
||||
composingText: *mut c_void,
|
||||
text: *const libc::c_char,
|
||||
);
|
||||
pub fn ComposingText_DeleteForwardFromCursorPosition(
|
||||
composingText: *mut c_void,
|
||||
count: libc::c_int,
|
||||
);
|
||||
pub fn ComposingText_DeleteBackwardFromCursorPosition(
|
||||
composingText: *mut c_void,
|
||||
count: libc::c_int,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
struct FFICandidate {
|
||||
text: *mut libc::c_char,
|
||||
corresponding_count: libc::c_int,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Candidate {
|
||||
pub text: String,
|
||||
pub corresponding_count: i32,
|
||||
}
|
||||
|
||||
pub struct KanaKanjiConverter {
|
||||
pub converter: *mut c_void,
|
||||
}
|
||||
|
||||
pub struct ComposingText {
|
||||
pub composing_text: *mut c_void,
|
||||
}
|
||||
|
||||
impl KanaKanjiConverter {
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
let converter = CreateKanaKanjiConverter();
|
||||
if converter.is_null() {
|
||||
panic!("Failed to create KanaKanjiConverter");
|
||||
}
|
||||
Self { converter }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_candidates(
|
||||
&self,
|
||||
composing_text: &ComposingText,
|
||||
context: &str,
|
||||
) -> Vec<Candidate> {
|
||||
unsafe {
|
||||
let c_str = std::ffi::CString::new(context).expect("CString::new failed");
|
||||
let mut length: c_int = 0;
|
||||
let candidates_ptr = KanaKanjiConverter_RequestCandidates(
|
||||
self.converter,
|
||||
composing_text.composing_text,
|
||||
&mut length,
|
||||
c_str.as_ptr(),
|
||||
);
|
||||
if candidates_ptr.is_null() {
|
||||
panic!("Failed to get candidates");
|
||||
}
|
||||
|
||||
let mut candidates = Vec::new();
|
||||
for i in 0..length {
|
||||
let candidate = *(*candidates_ptr.offset(i as isize));
|
||||
let text = std::ffi::CStr::from_ptr(candidate.text)
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let corresponding_count = candidate.corresponding_count;
|
||||
candidates.push(Candidate {
|
||||
text,
|
||||
corresponding_count,
|
||||
});
|
||||
}
|
||||
candidates
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop_composition(&self) {
|
||||
unsafe {
|
||||
KanaKanjiConverter_StopComposition(self.converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for KanaKanjiConverter {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DestroyKanaKanjiConverter(self.converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComposingText {
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
let composing_text = CreateComposingText();
|
||||
if composing_text.is_null() {
|
||||
panic!("Failed to create ComposingText");
|
||||
}
|
||||
Self { composing_text }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_at_cursor_position(&self, text: &str) {
|
||||
unsafe {
|
||||
let c_str = std::ffi::CString::new(text).expect("CString::new failed");
|
||||
ComposingText_InsertAtCursorPosition(self.composing_text, c_str.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_forward_from_cursor_position(&self, count: i32) {
|
||||
unsafe {
|
||||
ComposingText_DeleteForwardFromCursorPosition(self.composing_text, count);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_backward_from_cursor_position(&self, count: i32) {
|
||||
unsafe {
|
||||
ComposingText_DeleteBackwardFromCursorPosition(self.composing_text, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ComposingText {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DestroyComposingText(self.composing_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
src/main.rs
12
src/main.rs
@ -1,3 +1,13 @@
|
||||
use azookey_binding::{ComposingText, KanaKanjiConverter};
|
||||
|
||||
fn main() {
|
||||
unsafe { azookey_binding::HelloSwift() };
|
||||
let input = "seido";
|
||||
let kana_kanji_converter = KanaKanjiConverter::new();
|
||||
|
||||
let composing_text = ComposingText::new();
|
||||
composing_text.insert_at_cursor_position(input);
|
||||
|
||||
let result = kana_kanji_converter.request_candidates(&composing_text, "");
|
||||
|
||||
println!("{} -> {:?}", input, result);
|
||||
}
|
||||
|
Reference in New Issue
Block a user