mirror of
https://github.com/mii443/vrclipboard-ime-gui.git
synced 2025-08-22 16:15:32 +00:00
add tsf availability check
This commit is contained in:
BIN
public/windows_settings.png
Normal file
BIN
public/windows_settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
@ -11,6 +11,7 @@ mod transform_rule;
|
|||||||
mod tsf;
|
mod tsf;
|
||||||
mod tsf_conversion;
|
mod tsf_conversion;
|
||||||
mod tauri_emit_subscriber;
|
mod tauri_emit_subscriber;
|
||||||
|
mod tsf_availability;
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
@ -24,6 +25,8 @@ use config::Config;
|
|||||||
use handler::ConversionHandler;
|
use handler::ConversionHandler;
|
||||||
use tauri_emit_subscriber::TauriEmitSubscriber;
|
use tauri_emit_subscriber::TauriEmitSubscriber;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
use tsf_availability::check_tsf_availability;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Log {
|
struct Log {
|
||||||
@ -56,6 +59,27 @@ fn save_settings(config: Config, state: State<AppState>) -> Result<(), String> {
|
|||||||
config.save(state)
|
config.save(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn check_tsf_availability_command() -> Result<bool, String> {
|
||||||
|
debug!("Checking TSF availability");
|
||||||
|
match check_tsf_availability() {
|
||||||
|
Ok(result) => {
|
||||||
|
debug!("TSF availability check result: {}", result);
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
Err(e) => Err(format!("Failed to check TSF availability: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn open_ms_settings_regionlanguage_jpnime() -> Result<(), String> {
|
||||||
|
let _ = std::process::Command::new("cmd")
|
||||||
|
.args(&["/C", "start", "ms-settings:regionlanguage-jpnime"])
|
||||||
|
.output()
|
||||||
|
.map_err(|e| format!("Failed to open MS Settings: {}", e))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
@ -66,7 +90,7 @@ fn main() {
|
|||||||
Config::load().expect("Failed to load default config")
|
Config::load().expect("Failed to load default config")
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
.invoke_handler(tauri::generate_handler![load_settings, save_settings])
|
.invoke_handler(tauri::generate_handler![load_settings, save_settings, check_tsf_availability_command, open_ms_settings_regionlanguage_jpnime])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let _span = tracing::span!(tracing::Level::INFO, "main");
|
let _span = tracing::span!(tracing::Level::INFO, "main");
|
||||||
app.manage(STATE.lock().unwrap().clone());
|
app.manage(STATE.lock().unwrap().clone());
|
||||||
|
@ -52,6 +52,7 @@ where
|
|||||||
timestamp: format!("{}-{}-{} {}:{}:{}", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()),
|
timestamp: format!("{}-{}-{} {}:{}:{}", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("[{} {}] {} {}", event.timestamp, event.level, event.module_path, event.message);
|
||||||
if self
|
if self
|
||||||
.app_handle
|
.app_handle
|
||||||
.emit(
|
.emit(
|
||||||
|
24
src-tauri/src/tsf_availability.rs
Normal file
24
src-tauri/src/tsf_availability.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
use crate::tsf::{search_candidate_provider::SearchCandidateProvider, set_thread_local_input_settings};
|
||||||
|
|
||||||
|
pub fn check_tsf_availability() -> Result<bool> {
|
||||||
|
info!("Checking TSF availability");
|
||||||
|
|
||||||
|
if let Err(e) = set_thread_local_input_settings(true) {
|
||||||
|
error!("Failed to set thread local input settings: {:?}", e);
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
match SearchCandidateProvider::create() {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("TSF is available");
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to create SearchCandidateProvider: {:?}", e);
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/App.tsx
52
src/App.tsx
@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { List, Settings, Terminal, Bug, Info } from 'lucide-react';
|
import { List, Settings, Terminal, Bug, Info } from 'lucide-react';
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import TitleBar from "./TitleBar";
|
import TitleBar from "./TitleBar";
|
||||||
import SettingsComponent from "./SettingsComponent";
|
import SettingsComponent from "./SettingsComponent";
|
||||||
@ -8,6 +9,8 @@ import { ThemeProvider } from "./ThemeContext";
|
|||||||
import { LogProvider } from "./LogContext";
|
import { LogProvider } from "./LogContext";
|
||||||
import TerminalComponent from "./TerminalComponent";
|
import TerminalComponent from "./TerminalComponent";
|
||||||
import AboutComponent from "./AboutComponent";
|
import AboutComponent from "./AboutComponent";
|
||||||
|
import TsfSettingsModal from "./TsfSettingsModal";
|
||||||
|
import { Config } from "./SettingsComponent";
|
||||||
|
|
||||||
interface Log {
|
interface Log {
|
||||||
time: string;
|
time: string;
|
||||||
@ -18,6 +21,9 @@ interface Log {
|
|||||||
const AppContent = () => {
|
const AppContent = () => {
|
||||||
const [logs, setLogs] = useState<Log[]>([]);
|
const [logs, setLogs] = useState<Log[]>([]);
|
||||||
const [activeMenuItem, setActiveMenuItem] = useState('home');
|
const [activeMenuItem, setActiveMenuItem] = useState('home');
|
||||||
|
const [showTsfModal, setShowTsfModal] = useState(false);
|
||||||
|
const [currentSettings, setCurrentSettings] = useState<Config | null>(null);
|
||||||
|
const [isTsfAvailable, setIsTsfAvailable] = useState<boolean | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlisten = listen<Log>('addLog', (event) => {
|
const unlisten = listen<Log>('addLog', (event) => {
|
||||||
@ -29,6 +35,40 @@ const AppContent = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// TSF設定のチェック
|
||||||
|
useEffect(() => {
|
||||||
|
const checkTsfSettings = async () => {
|
||||||
|
try {
|
||||||
|
const settings: Config = await invoke('load_settings');
|
||||||
|
setCurrentSettings(settings);
|
||||||
|
|
||||||
|
if (settings.use_tsf_reconvert) {
|
||||||
|
// TSF設定が有効な場合、TSFが利用可能か確認
|
||||||
|
const available: boolean = await invoke('check_tsf_availability_command');
|
||||||
|
setIsTsfAvailable(available);
|
||||||
|
|
||||||
|
if (!available) {
|
||||||
|
setShowTsfModal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('TSF設定確認エラー:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkTsfSettings();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 設定保存関数
|
||||||
|
const saveSettings = async (config: Config) => {
|
||||||
|
try {
|
||||||
|
await invoke('save_settings', { config });
|
||||||
|
setCurrentSettings(config);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('設定保存エラー:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderLogEntry = (log: { time: string; original: string; converted: string }, index: number) => (
|
const renderLogEntry = (log: { time: string; original: string; converted: string }, index: number) => (
|
||||||
<div key={index} className="mb-2 p-2 bg-white/90 dark:bg-gray-800 rounded border border-gray-100 dark:border-gray-700 text-sm transition-colors">
|
<div key={index} className="mb-2 p-2 bg-white/90 dark:bg-gray-800 rounded border border-gray-100 dark:border-gray-700 text-sm transition-colors">
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">{log.time}</div>
|
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">{log.time}</div>
|
||||||
@ -79,7 +119,7 @@ const AppContent = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'settings':
|
case 'settings':
|
||||||
return <SettingsComponent />;
|
return <SettingsComponent setShowTsfModal={setShowTsfModal} />;
|
||||||
case 'terminal':
|
case 'terminal':
|
||||||
return <TerminalComponent />;
|
return <TerminalComponent />;
|
||||||
case 'about':
|
case 'about':
|
||||||
@ -111,6 +151,16 @@ const AppContent = () => {
|
|||||||
{renderContent()}
|
{renderContent()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* TSF設定モーダル */}
|
||||||
|
{currentSettings && (
|
||||||
|
<TsfSettingsModal
|
||||||
|
isOpen={showTsfModal}
|
||||||
|
onClose={() => setShowTsfModal(false)}
|
||||||
|
onSaveSettings={saveSettings}
|
||||||
|
currentSettings={currentSettings}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
|
|||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
import { ChevronDown, Settings, Save, AlertCircle, Check } from 'lucide-react';
|
import { ChevronDown, Settings, Save, AlertCircle, Check } from 'lucide-react';
|
||||||
|
|
||||||
interface Config {
|
export interface Config {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
split: string;
|
split: string;
|
||||||
command: string;
|
command: string;
|
||||||
@ -11,9 +11,10 @@ interface Config {
|
|||||||
skip_url: boolean;
|
skip_url: boolean;
|
||||||
use_tsf_reconvert: boolean;
|
use_tsf_reconvert: boolean;
|
||||||
skip_on_out_of_vrc: boolean;
|
skip_on_out_of_vrc: boolean;
|
||||||
|
tsf_announce?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OnCopyMode {
|
export enum OnCopyMode {
|
||||||
ReturnToClipboard = 'ReturnToClipboard',
|
ReturnToClipboard = 'ReturnToClipboard',
|
||||||
ReturnToChatbox = 'ReturnToChatbox',
|
ReturnToChatbox = 'ReturnToChatbox',
|
||||||
SendDirectly = 'SendDirectly'
|
SendDirectly = 'SendDirectly'
|
||||||
@ -57,9 +58,10 @@ interface CheckboxFieldProps {
|
|||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CheckboxField: React.FC<CheckboxFieldProps> = ({ id, name, label, checked, onChange }) => (
|
const CheckboxField: React.FC<CheckboxFieldProps> = ({ id, name, label, checked, onChange, disabled }) => (
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<div className="flex items-start">
|
<div className="flex items-start">
|
||||||
<div className="flex items-center h-4">
|
<div className="flex items-center h-4">
|
||||||
@ -69,11 +71,16 @@ const CheckboxField: React.FC<CheckboxFieldProps> = ({ id, name, label, checked,
|
|||||||
name={name}
|
name={name}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
className="h-3.5 w-3.5 text-indigo-500 dark:text-indigo-400 border-gray-300 dark:border-gray-600 rounded dark:bg-gray-700 transition-colors"
|
disabled={disabled}
|
||||||
|
className={`h-3.5 w-3.5 text-indigo-500 dark:text-indigo-400 border-gray-300 dark:border-gray-600 rounded dark:bg-gray-700 transition-colors ${
|
||||||
|
disabled ? 'opacity-50 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-2 text-xs">
|
<div className="ml-2 text-xs">
|
||||||
<label htmlFor={id} className="text-gray-700 dark:text-gray-300 transition-colors">
|
<label htmlFor={id} className={`text-gray-700 dark:text-gray-300 transition-colors ${
|
||||||
|
disabled ? 'opacity-50 cursor-not-allowed' : ''
|
||||||
|
}`}>
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -81,7 +88,11 @@ const CheckboxField: React.FC<CheckboxFieldProps> = ({ id, name, label, checked,
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const SettingsComponent: React.FC = () => {
|
interface SettingsComponentProps {
|
||||||
|
setShowTsfModal: (show: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsComponent: React.FC<SettingsComponentProps> = ({ setShowTsfModal }) => {
|
||||||
const [settings, setSettings] = useState<Config>({
|
const [settings, setSettings] = useState<Config>({
|
||||||
prefix: ';',
|
prefix: ';',
|
||||||
split: '/',
|
split: '/',
|
||||||
@ -136,6 +147,30 @@ const SettingsComponent: React.FC = () => {
|
|||||||
saveSettings(newSettings);
|
saveSettings(newSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTsfChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const isChecked = e.target.checked;
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
try {
|
||||||
|
const available: boolean = await invoke('check_tsf_availability_command');
|
||||||
|
if (!available && setShowTsfModal) {
|
||||||
|
setShowTsfModal(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, value, type } = e.target;
|
||||||
|
const newSettings = {
|
||||||
|
...settings,
|
||||||
|
[name]: type === 'checkbox' ? isChecked : value
|
||||||
|
};
|
||||||
|
setSettings(newSettings);
|
||||||
|
saveSettings(newSettings);
|
||||||
|
};
|
||||||
|
|
||||||
const handleSelectChange = (value: OnCopyMode) => {
|
const handleSelectChange = (value: OnCopyMode) => {
|
||||||
const newSettings = { ...settings, on_copy_mode: value };
|
const newSettings = { ...settings, on_copy_mode: value };
|
||||||
setSettings(newSettings);
|
setSettings(newSettings);
|
||||||
@ -193,6 +228,7 @@ const SettingsComponent: React.FC = () => {
|
|||||||
label="区切り文字"
|
label="区切り文字"
|
||||||
value={settings.split}
|
value={settings.split}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
disabled={settings.use_tsf_reconvert}
|
||||||
description="複数の変換モードを使いたい場合の区切り文字"
|
description="複数の変換モードを使いたい場合の区切り文字"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -201,6 +237,7 @@ const SettingsComponent: React.FC = () => {
|
|||||||
label="モード変更文字"
|
label="モード変更文字"
|
||||||
value={settings.command}
|
value={settings.command}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
disabled={settings.use_tsf_reconvert}
|
||||||
description="変換モードを変更するための文字"
|
description="変換モードを変更するための文字"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -210,6 +247,7 @@ const SettingsComponent: React.FC = () => {
|
|||||||
label="無条件で変換"
|
label="無条件で変換"
|
||||||
checked={settings.ignore_prefix}
|
checked={settings.ignore_prefix}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
disabled={settings.use_tsf_reconvert}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputField
|
<InputField
|
||||||
@ -217,7 +255,7 @@ const SettingsComponent: React.FC = () => {
|
|||||||
label="開始文字"
|
label="開始文字"
|
||||||
value={settings.prefix}
|
value={settings.prefix}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
disabled={settings.ignore_prefix}
|
disabled={settings.ignore_prefix || settings.use_tsf_reconvert}
|
||||||
description="変換を開始する文字(無条件で変換がオンの場合は無効)"
|
description="変換を開始する文字(無条件で変換がオンの場合は無効)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -282,7 +320,7 @@ const SettingsComponent: React.FC = () => {
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
checked={settings.use_tsf_reconvert}
|
checked={settings.use_tsf_reconvert}
|
||||||
onChange={handleChange}
|
onChange={handleTsfChange}
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5 ml-5 transition-colors">
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5 ml-5 transition-colors">
|
||||||
Windows10/11では「以前のバージョンの Microsoft IME を使う」を有効化する必要があります。有効にすると区切り、モード変更、開始文字が無効化されます。
|
Windows10/11では「以前のバージョンの Microsoft IME を使う」を有効化する必要があります。有効にすると区切り、モード変更、開始文字が無効化されます。
|
||||||
|
97
src/TsfSettingsModal.tsx
Normal file
97
src/TsfSettingsModal.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { open } from '@tauri-apps/plugin-shell';
|
||||||
|
import { AlertCircle, Settings, Check, X, ExternalLink } from 'lucide-react';
|
||||||
|
import { Config } from './SettingsComponent';
|
||||||
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
|
||||||
|
interface TsfSettingsModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSaveSettings: (config: Config) => Promise<void>;
|
||||||
|
currentSettings: Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TsfSettingsModal: React.FC<TsfSettingsModalProps> = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
onSaveSettings,
|
||||||
|
currentSettings
|
||||||
|
}) => {
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
const openWindowsSettings = async () => {
|
||||||
|
invoke('open_ms_settings_regionlanguage_jpnime');
|
||||||
|
};
|
||||||
|
|
||||||
|
const useLegacyConverter = async () => {
|
||||||
|
try {
|
||||||
|
const newSettings = { ...currentSettings, use_tsf_reconvert: false };
|
||||||
|
await onSaveSettings(newSettings);
|
||||||
|
onClose();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('設定保存に失敗しました:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 max-w-2xl w-full max-h-[90vh] overflow-y-auto transition-colors">
|
||||||
|
<div className="flex justify-between items-start mb-4">
|
||||||
|
<h2 className="text-lg font-medium text-gray-800 dark:text-gray-200 flex items-center">
|
||||||
|
<AlertCircle size={18} className="mr-2 text-yellow-500" />
|
||||||
|
Windowsの設定が必要です
|
||||||
|
</h2>
|
||||||
|
<button onClick={onClose} className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
||||||
|
<X size={20} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col sm:flex-row gap-3 justify-start mb-4">
|
||||||
|
<button
|
||||||
|
onClick={openWindowsSettings}
|
||||||
|
className="flex items-center justify-center bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded"
|
||||||
|
>
|
||||||
|
<Settings size={16} className="mr-2" />
|
||||||
|
Windows設定を開く
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-gray-700 dark:text-gray-300 mb-4">
|
||||||
|
<div className="bg-gray-50 dark:bg-gray-700 p-4 rounded mb-4">
|
||||||
|
<h3 className="text-sm font-medium mb-2 flex items-center">
|
||||||
|
<Settings size={14} className="mr-1.5" />
|
||||||
|
設定手順
|
||||||
|
</h3>
|
||||||
|
<ol className="list-decimal list-inside text-sm space-y-1.5 ml-1">
|
||||||
|
<li>上のボタンからWindows設定を開く</li>
|
||||||
|
<li>「全般」を開く</li>
|
||||||
|
<li>一番下の「以前のバージョンの Microsoft IME を使う」をオンにする</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg mb-6 overflow-hidden">
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-600 text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
Windows設定画面
|
||||||
|
</div>
|
||||||
|
<div className="p-4 flex justify-center">
|
||||||
|
<img src="./windows_settings.png"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col sm:flex-row gap-3 justify-end">
|
||||||
|
<button
|
||||||
|
onClick={useLegacyConverter}
|
||||||
|
className="flex items-center justify-center bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 px-4 py-2 rounded"
|
||||||
|
>
|
||||||
|
<Check size={16} className="mr-2" />
|
||||||
|
レガシー変換を使用
|
||||||
|
<span className="text-xs text-red-500 ml-1.5">(機能制限あり)</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TsfSettingsModal;
|
Reference in New Issue
Block a user