none
ひらがなだけを入力する方法 RRS feed

  • 質問

  • テキストボックスに、リアルタイムで強制的にひらがなだけを入力するプログラムを作りたいと思っています。

    昔のMS-IMEの単語登録の読みを入力するボックスのようなものが作りたいです。

    検索しては見たのですが、やり方がわかりません。

    具体的には、IMEにひらがなが表示された瞬間に確定するという仕組みを考えましたが、そのようなメッセージがあるのかどうかわかりませんでした。

    言語はC#を予定していますが、VB.net、C++でも構いません。これらの言語も読めます。

    2011年12月13日 14:05

回答

  • まず、CallingConvertion を指定しなかった場合の挙動に関して確認する意味合いでリンクします。
    http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.dllimportattribute.callingconvention(v=VS.100).aspx

    省略時は WinApi で、実質的に StdCall と等価であるということになります。

    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetConversionStatus(IntPtr hIMC, ref int fdwConversion, ref int fdwSentence);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetOpenStatus(IntPtr hIMC);
    
    

    これらは使われていないので影響がないのでしょうけれども、StdCall であるべきです。
    Win32API は基本的に StdCall なので。

    [DllImport("Imm32.dll")]
    public static extern IntPtr ImmGetContext(IntPtr hWnd);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);
    

    これらは正しく StdCall なので問題ありません。

    [DllImport("Imm32.dll", CallingConvention = CallingConvention.ThisCall)]
    private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen);
    
    

    Win32API の場合、ThisCall は選択肢としてまずないです…。
    CallingConvertion のページ にも書いていますが、これは this ポインターを渡すための方法です。

    C++ などではクラスのメンバー関数を呼び出したとき、__thiscall という呼び出し規約が設定されています。
    コード上は this ポインターを渡さない関数呼び出しになりますが、コンパイラーが勝手に this ポインターを引数に渡すような関数とみなします。(私の解釈による勝手な説明なので、詳細な原理・動作は間違っている可能性があります)

    今回の ImmSetOpenStatus はクラスメンバー関数ではないので、これに当たりません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年12月16日 14:59
    モデレータ
  • ImmSetConversionStatusを使って、IMEを無変換にセットすれば良いのではないでしょうか? ただし、無変換なので英数字なども入力できてしまうと思いますので、その辺りのチェックは必要だと思います。

    (参考)
    [C#]IME関連
    http://d.hatena.ne.jp/HowHigh/20050328/p1

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月14日 7:38
    モデレータ

すべての返信

  • 質問からはどちらかわからなかったのですが、

    最終的にテキストボックスに表示されているのがひらがなだけになる
    というアプローチなら簡単そうに思ったのですが、
    どうしてもひらがなだけ一文字ずつ入力できないといけないのでしょうか。

    2011年12月14日 0:14
  • 最終的にひらがなだけかどうかを確認することならできると思います。

    そうではなくて、リアルタイムでひらがなだけに変換されるようにしたいです。

    目的は漢字変換の手間を省略したメモ帳を作る為です。

    2011年12月14日 4:03
  • 問題をもう少し簡単にして、ひらがな以外の文字の入力を許可しない、としたらどうですか?

    例えば、「読みを入力する」と入力したら、「みをする」だけを残すとか。

    2011年12月14日 7:14
  • ImmSetConversionStatusを使って、IMEを無変換にセットすれば良いのではないでしょうか? ただし、無変換なので英数字なども入力できてしまうと思いますので、その辺りのチェックは必要だと思います。

    (参考)
    [C#]IME関連
    http://d.hatena.ne.jp/HowHigh/20050328/p1

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月14日 7:38
    モデレータ
  • IMEを無効にして自前で変換しちゃったり

    Dictionary<string, string> dic1;
    Dictionary<string, string> dic2;
    Dictionary<string, string> dic3;
    
    private void CreateDictionary()
    {
        dic1 = new Dictionary<string, string>();
        dic1.Add("A", "あ");
        dic1.Add("I", "い");
        dic1.Add("U", "う");
        dic1.Add("E", "え");
        dic1.Add("O", "お");
        //略
    
         dic2 = new Dictionary<string, string>();
        dic2.Add("KA", "か");
        dic2.Add("KI", "き");
        dic2.Add("KU", "く");
        dic2.Add("KE", "け");
        dic2.Add("KO", "こ");
        dic2.Add("GA", "が");
        dic2.Add("GI", "ぎ");
        dic2.Add("GU", "ぐ");
        dic2.Add("GE", "げ");
        dic2.Add("GO", "ご");
        //略
    
        dic3 = new Dictionary<string, string>();
        dic3.Add("TYA", "ちゃ");
        dic3.Add("TYU", "ちゅ");
        dic3.Add("TYO", "ちょ");
        dic3.Add("KKA", "っか");
        dic3.Add("KKI", "っき");
        dic3.Add("KKU", "っく");
        dic3.Add("KKE", "っけ");
        dic3.Add("KKO", "っこ");
        //略
    }
    
    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (System.Windows.Forms.Control.ModifierKeys == Keys.None)
        {
            var txb = (TextBox)sender;
            char c = Char.ToUpper(e.KeyChar);
            switch (c)
            {
            case 'A':
            case 'I':
            case 'U':
            case 'E':
            case 'O':
                int start = txb.SelectionStart - 2;
                if (start < 0)
                {
                    start = 0;
                }
                string s = txb.Text.Substring(start, txb.SelectionStart - start) + c;
                s = s.ToUpper();
    
                bool isMatch = false;
                string match = string.Empty;
                if (s.Length == 3)
                {
                    isMatch = dic3.TryGetValue(s, out match);
                    if (!isMatch)
                    {
                        s = s.Substring(1);
                    }
                }
    
                if (!isMatch && s.Length == 2)
                {
                    isMatch = dic2.TryGetValue(s, out match);
                    if (!isMatch)
                    {
                        s = s.Substring(1);
                    }
                }
    
                if (!isMatch)
                {
                    isMatch = dic1.TryGetValue(s, out match);
                }
    
                if (isMatch)
                {
                    txb.SelectionStart = txb.SelectionStart - (s.Length - 1);
                    txb.SelectionLength = s.Length - 1;
                    txb.SelectedText = match;
                    txb.SelectionStart = txb.SelectionStart + match.Length;
                    e.Handled = true;
                }
                break;
            default:
                break;
            }
        }
    }
    



    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
    2011年12月14日 10:23
  • ありがとうございます。

    僕の作りたいプログラムでは、別にアルファベットなどが混ざっても構わないので、試してみます!

    2011年12月14日 11:19
  • それは僕も考えました。

    他の人の方法でできなかったら試してみます。

    2011年12月14日 11:19
  • すみません。困ったことになりました。

    書かれていた通りWin32APIを打ち込んで、アンセーフモードにしてコンパイルしたところ、VisualC#2010が、

    PInvokeStackImbalance が検出されました。
    Message: PInvoke 関数 'HiraganaEditor!HiraganaEditor.IMESetter::ImmSetOpenStatus' がスタックを不安定にしています。PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメーターがターゲットのアンマネージ シグネチャに一致していることを確認してください。

    なるエラーをはいて処理を打ち切ってしまいます。

    調べてみた結果、2010になって、Windows32APIを簡単に使えなくするために、MDSなる余計なプロテクトをかけるようになっているようです。

    環境変数でMDSを無効化してみようかとも思いましたが、どうすればいいのかわかりません…。

    2011年12月14日 15:22
  • MDS ってなんですか?Managed Debug Assistants(MDA) なら 2010 よりももっと前からありますが…。

    とりあえず、DllImport 属性と、それを付与した関数宣言(必要なら構造体なども)をさらしてください。
    構文に問題がある可能性も考えられるので。

    あと、Win32API 使うだけなら、アンセーフコードを許可する必要はありません。
    何か誤解していませんか?


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年12月14日 15:46
    モデレータ
  • スタックの破壊検出は .NET 1.1 からありました(デフォルトで無効でしたが)

    エラーメッセージにも書いてありますが、P/Invoke の書き方が間違っているという検出なので、P/Invoke の記述を正しくすれば問題ありません。
    (おそらく、参照された日記が間違っているところを、検証もなく丸写ししているのが問題なのではないかと思います)

    ぱっとみたかんじ、日記を書いた人は VB の 16bit 基準の命名をそのまま C# にコピーしていて、ビット幅が間違っているっぽいですね。unsafe の部分は out パラメータにすれば良いでしょう。

     

    2011年12月14日 23:52
  • というかスタック破壊を検出しなかった場合、戻り値が得られないだけでなく、return addressも不正にあり、関数が呼び出し元に返ってこず、暴走状態になります。

    「余計なプロテクト」なんて表現を見る限り、どれほど役に立っているか、何をしてるのか全く理解できていないようですね。

    2011年12月15日 0:17
  • 書かれていた通りWin32APIを打ち込んで、アンセーフモードにしてコンパイルしたところ、VisualC#2010が、

    PInvokeStackImbalance が検出されました。
    Message: PInvoke 関数 'HiraganaEditor!HiraganaEditor.IMESetter::ImmSetOpenStatus' がスタックを不安定にしています。PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメーターがターゲットのアンマネージ シグネチャに一致していることを確認してください。

    なるエラーをはいて処理を打ち切ってしまいます。

    すみません。私が掲載したリンク先の情報が古かったのかもしれませんね。代わりに以下をご紹介しておきます。

    アプリケーションのIME変換モードを取得、設定する方法
    http://social.msdn.microsoft.com/Forums/ja/vbgeneralja/thread/4a22e700-894c-48cd-a3cd-246f8be0a7ca

     VS2010のC#で動作確認しました。上記のページに掲載されているChangeImeModeメソッドを利用させていただき、以下を実行したところ、テキストボックス(textBox1)へ無変換状態でひらがなを入力することができました。正常に動作しているようです。

     ChangeImeMode(this.textBox1.Handle, ImeMode.Hiragana);

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月15日 5:31
    モデレータ
  • 偉そうなこと言って本当にすみません。

    右も左もわからない初心者なもので、Win32APIを使ったこと自体なくて…。

     

    C#だと同じ問題が発生しました。

    VBのほうがその問題の答えに見えましたので、VBでやってみます。

    2011年12月15日 10:50
  • どのような環境で、どのように作成されていますか? 繰り返しになりますが、私が上で紹介した、

    アプリケーションのIME変換モードを取得、設定する方法
    http://social.msdn.microsoft.com/Forums/ja/vbgeneralja/thread/4a22e700-894c-48cd-a3cd-246f8be0a7ca

    に掲載されているコードをそのまま貼り付けて、

    ChangeImeMode(this.textBox1.Handle, ImeMode.Hiragana);

    を実行するだけで、問題なく動作します。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月16日 0:49
    モデレータ
  • ChangeImeMode(this.textBox1.Handle, ImeMode.Hiragana);

    を実行するだけで、問題なく動作します。

    もしやと思って試したのですが、デバッグ実行すると、

    『PInvoke 関数 'test2010!test2010.ImmSetConversionStatusTest::ImmSetOpenStatus' がスタックを不安定にしています。PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメーターがターゲットのアンマネージ シグネチャに一致していることを確認してください。』

    と、同じエラーメッセージが表示されますね。調べてみると、以下のサイトに情報がありました。

    MeCab
    http://wiki.sh4e.net/?Tips%2FOther%2FMeCab

    ここに、以下の記述があります。

    「VisualStudio2010から、MDA(Managed Debugging Assistants)がデフォルトで有効になりました。」

    対策としては、CallingConventionを指定すれば良いとのこと。この辺り私はあまり詳しくないので、試行錯誤でうまく行く指定を見つけました。以下のように指定すればうまく動いています。
    誤りあればどなたかご指摘下さい。

    [DllImport("Imm32.dll")]
    public static extern IntPtr ImmGetContext(IntPtr hWnd);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetConversionStatus(IntPtr hIMC, ref int fdwConversion, ref int fdwSentence);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetOpenStatus(IntPtr hIMC);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.ThisCall)]
    private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);
    

    また、根本的にPInvokeStackImbalanceのチェック自体を無効にしてしまう方法もありました。以下が参考になります。

    タワーをWindows7(64ビット)とVisual C# Express 2010の環境で動かす際のエラーと対処法
    http://blog.livedoor.jp/art_of_deal/archives/cat_73977.html

    メニューのデバッグから例外を開き、Managed Debugging AssistantsにおけるInvokeStackImbalanceの「スローされるとき」のチェックを外します。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月16日 5:23
    モデレータ
  • まず、CallingConvertion を指定しなかった場合の挙動に関して確認する意味合いでリンクします。
    http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.dllimportattribute.callingconvention(v=VS.100).aspx

    省略時は WinApi で、実質的に StdCall と等価であるということになります。

    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetConversionStatus(IntPtr hIMC, ref int fdwConversion, ref int fdwSentence);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ImmGetOpenStatus(IntPtr hIMC);
    
    

    これらは使われていないので影響がないのでしょうけれども、StdCall であるべきです。
    Win32API は基本的に StdCall なので。

    [DllImport("Imm32.dll")]
    public static extern IntPtr ImmGetContext(IntPtr hWnd);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
    
    [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
    private static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);
    

    これらは正しく StdCall なので問題ありません。

    [DllImport("Imm32.dll", CallingConvention = CallingConvention.ThisCall)]
    private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen);
    
    

    Win32API の場合、ThisCall は選択肢としてまずないです…。
    CallingConvertion のページ にも書いていますが、これは this ポインターを渡すための方法です。

    C++ などではクラスのメンバー関数を呼び出したとき、__thiscall という呼び出し規約が設定されています。
    コード上は this ポインターを渡さない関数呼び出しになりますが、コンパイラーが勝手に this ポインターを引数に渡すような関数とみなします。(私の解釈による勝手な説明なので、詳細な原理・動作は間違っている可能性があります)

    今回の ImmSetOpenStatus はクラスメンバー関数ではないので、これに当たりません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年12月16日 14:59
    モデレータ
  • で、結局何が悪いのかというと、MSDN の function のシグネチャと比較していくとわかります。
    MDA が検出される、ImmSetOpenStatus の MSDN の説明をご覧ください。

    http://msdn.microsoft.com/en-us/library/windows/desktop/dd318586(v=VS.85).aspx

    これを見ると、第 2 引数は BOOL 型となっています。
    この型は 4 バイト整数型だが、TRUE or FALSE を表す型になります。
    C# で long を指定してしまうと 8 バイトの整数型となって、引数の型が一致しません。
    引数のサイズが異なるため、スタックのサイズ不一致が起こり、MDA として検出されていたことになります。

    正しい P/Invoke 文としては第 2 引数を bool にすることです。
    (bool 型のデフォルトは UnmanagedType.Bool、つまり BOOL 型と扱われます

    MDA はたいてい、P/Invoke の定義が悪いことが原因です。
    発生したときは小細工するのではなく、API の宣言と照らしたときに適切にマーシャリングされる型になっているかを確認することが必要です。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年12月16日 15:05
    モデレータ
  • できました!

    ありがとうございます!

     

    いつかWindowsAPIも本格的に勉強して、立派なプログラマーになりたいです。

    2011年12月18日 2:15
  • 遅くなりました。すみません。Azuleanさん、大変参考になりました。フォローありがとうございました。m(_ _)m

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年12月20日 0:47
    モデレータ
  • すみません一つ問題が起こりました。

    このコードを使うと、TextboxのImeModeをHiraganaにしても、最初は必ず英数字直接入力になってしまいます。

    何かいい解決法はないでしょうか。

    2012年1月3日 0:33
  • このコードを使うと、TextboxのImeModeをHiraganaにしても、最初は必ず英数字直接入力になってしまいます。

    まず、コードの意味を理解してください。
    どのタイミングで呼び出しているかは存じませんが、ImeMode プロパティで解決できる状態ではなくなっています。その認識を持たずに適当にコードを書くことは、「よくわからないコードを適当に使っている」状態に過ぎず、信頼が置けるコードとはとてもいえません。

    不具合が生じたときにも、こうやって人に聞くしかなくなるので、自分で解決できない状態が続くことになり、あなた一人ではコードも書けない状態になってしまいます。
    きちんと、どういったものをどう使っているからどうなるのかを調べるようにしましょう。わからないのならば勉強する、調べるといったプロセスを経てどうしてもわからなかったことを質問するなどして、理解する努力をしてください。
    そうして、コードを自分のものにしていってください。  

    ちなみに、手元で ChangeImeMode の Hiragana を Enter イベントで実行している限り、ひらがな固定になりました。
    手元の Win7(x64) + .NET4 + ATOK2011 の環境では。
    ImeMode プロパティは特に触っていません。
    # MS-IME は選択肢から消しているので動作確認していません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2012年1月3日 1:18
    モデレータ
  • 皆様の協力で作ることができた、以下のコードを使用しています。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;

     

    namespace HiraganaEditor {
        class IMESetter {
            //trapemiyaさんのコード
            [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
            private static extern bool ImmGetConversionStatus(IntPtr hIMC, ref int fdwConversion, ref int fdwSentence);

            [DllImport("Imm32.dll", CallingConvention = CallingConvention.Cdecl)]
            private static extern bool ImmGetOpenStatus(IntPtr hIMC);

            [DllImport("Imm32.dll")]
            public static extern IntPtr ImmGetContext(IntPtr hWnd);

            [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
            private static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);

            [DllImport("Imm32.dll", CallingConvention = CallingConvention.StdCall)]
            private static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);

            [DllImport("Imm32.dll", CallingConvention = CallingConvention.ThisCall)]
            private static extern bool ImmSetOpenStatus(IntPtr hIMC, long fOpen);

     

            // 入力モードを示す定数
            /// <summary>英数字入力モード</summary>
            private const int IME_CMODE_ALPHANUMERIC = 0x0;
            /// <summary>言語依存入力モード</summary>
            private const int IME_CMODE_NATIVE = 0x1;
            /// <summary>日本語入力モード</summary>
            private const int IME_CMODE_JAPANESE = IME_CMODE_NATIVE;
            /// <summary>カタカナ入力モード</summary>
            private const int IME_CMODE_KATAKANA = 0x2;
            /// <summary>言語入力モード</summary>
            private const int IME_CMODE_LANGUAGE = 0x3;
            /// <summary>全角入力モード</summary>
            private const int IME_CMODE_FULLSHAPE = 0x8;
            /// <summary>ローマ字入力モード</summary>
            private const int IME_CMODE_ROMAN = 0x10;

            // 変換モードを示す定数の宣言
            /// <summary>無変換モード</summary>
            private const int IME_SMODE_NONE = 0x0;
            /// <summary>複数文字変換モード</summary>
            private const int IME_SMODE_PLAURALCLAUSE = 0x1;
            /// <summary>単一文字変換モード</summary>
            private const int IME_SMODE_SINGLECONVERT = 0x2;
            /// <summary>自動変換モード</summary>
            private const int IME_SMODE_AUTOMATIC = 0x4;
            /// <summary>予測変換モード</summary>
            private const int IME_SMODE_PHRASEPREDICT = 0x8;


            /// <summary>
            /// IMEモードを切り替える
            /// </summary>
            /// <param name="handle">ウィンドウのハンドル</param>
            /// <param name="imeMode">IMEモード</param>
            public static void ChangeImeMode(IntPtr handle, ImeMode imeMode) {
                IntPtr lngInputContextHandle;
                int lngStatusIMEConversion = 0;
                bool lngWin32apiResultCode;

                // ウィンドウに関連付けされた入力コンテキストを取得
                lngInputContextHandle = ImmGetContext(handle);

                if (lngInputContextHandle != new IntPtr(0)) {
                    // IMEをオープン
                    lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 1);

                    // 初期入力モードを指定
                    switch (imeMode) {
                        case ImeMode.AlphaFull: // 全角英数字
                            lngStatusIMEConversion = IME_CMODE_FULLSHAPE;
                            break;
                        case ImeMode.Hiragana: // 全角ひらがな
                            lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE;
                            break;
                        case ImeMode.Katakana: // 全角カナ
                            lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA;
                            break;
                        case ImeMode.KatakanaHalf: // 半角カナ
                            lngStatusIMEConversion = IME_CMODE_NATIVE | IME_CMODE_KATAKANA;
                            break;
                        default:
                            // 半角英数字、その他
                            lngWin32apiResultCode = ImmSetOpenStatus(lngInputContextHandle, 0);
                            lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle);
                            return;
                    }

                    // IMEの初期方式を設定
                    lngWin32apiResultCode = ImmSetConversionStatus(lngInputContextHandle, lngStatusIMEConversion, IME_SMODE_NONE);

                    // 入力コンテキストを開放
                    lngWin32apiResultCode = ImmReleaseContext(handle, lngInputContextHandle);
                }
            }
        }
    }

    Form_Loadと、Text_Changedで、以下のコードで呼び出してみました。

    IMESetter.ChangeImeMode(this.Handle, ImeMode.Hiragana);

    すると、最初に全角半角キーを押すまで、IMEがオフのままになってしまいます。

    原因を自分で考えることもしてみましたが、ダメでした。

    初心者で済みません。

    2012年1月3日 5:33
  • Form_LoadとText_Changedで呼び出すのはどういう意味合いなのでしょうか?
    2012年1月3日 5:46
  • お返事ありがとうございます。

    FormのLoadイベントと、TextBoxのTextChangedイベントに以下のコードを打ち込みました。

    IMESetter.ChangeImeMode(this.Handle, ImeMode.Hiragana);

    そうしたら、一度IMEをオンにした後は正常に動くのですが、IMEがオフの状態で起動します。

    これをオンの状態で起動したいようにしたいのですが…。

    2012年1月3日 13:20
  • 質問に答えていますか?

    FormのLoadイベントと、TextBoxのTextChangedイベントに以下のコードを打ち込みました。

    なぜ、その 2 つのイベントを選んだのかという質問だったはずですよ。
    それらのイベントはどんな時に起きるものかを理解して、今処理したいのはどんな時かを考え直してください。

    # 「初心者」という言葉を盾に何でもかんでも他人にやらせるのはよくありません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2012年1月3日 15:07
    モデレータ
  • Loadイベントは起動したときにIMEモードをひらがな固定にする、TextChangedイベントは編集して文字が入力されたときにひらがな固定にするために入力しました。

    皆さんのおっしゃるようにEnterでもやっては見ましたが、普通に漢字変換できてしまい、意味がありませんでした。

    2012年1月3日 15:41
  • Loadイベントは起動したときにIMEモードをひらがな固定にする、TextChangedイベントは編集して文字が入力されたときにひらがな固定にするために入力しました。

    Load イベントはフォームが表示するために準備する段階で発生するイベントであり、入力可能な状態になったときではありませんね。
    TextChanged イベントも文字入力のたびに切り替えは、煩雑だと思っています。

    皆さんのおっしゃるようにEnterでもやっては見ましたが、普通に漢字変換できてしまい、意味がありませんでした。

    どのような環境で、どういった手順で、どういうことをしたら、どうなったかが読み取れません。
    あなたが書いたことで伝えたいことをきちんと伝えられるようにできていますか?
    (えらそうに書いていますが、私も言葉が足りないことがよくあります。ただ、今の状況は返事が足りない状況が続いています)

    情報が足りないのでいろいろと推測したものを並べていますが、あなたの言葉で現状の問題点と理想をきちんと説明し直してください。
    正直、何がどうなっているのか、よくわかりません。

    1. 言語バーから固定入力を解除すれば、漢字変換ができます。
      そういったことを言っているのですか?そんなことは読み取れません。
    2. そういった手順を踏まずとも効かないなら、再現環境も提示すべきだったでしょう。
    3. ATOK だと赤線で固定入力(変換はできない)というように、瞬時に確定されないが変換できないことを問題視している?

    ちなみに、どこまで求めているんですか?たとえば、IME 制御をどんだけ頑張っても、コピー&ペーストで余計な文字が入ることは防げません。
    よくわからないまま、完璧を求めるなら、たぶんコンポーネントを買った方が早いですよ。
    今回の目的にかなうかはわかりませんが、こういった製品もありますし。

    # そういえば、this.Handle を渡しているのは正しいのだろうか。
    # 個人的に感じたのは TextBox のハンドルな気がしたのだが、OS によるんかな。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2012年1月3日 16:46
    モデレータ
  • 頭大丈夫ですか? それとも日本語が不得手なのでしょうか。

    • どんな時に
    • どんな動作を

    してほしいのか、日本語で具体的に具体的に具体的に書いてみてください。書き込む前に30回ぐらい読み返してより具体的に表現できないか考え抜いてみてください。

    その上で、その動作を実現するようなコードを書けばいいのかアドバイスできます。

    2012年1月4日 0:27
  • 佐祐理さん、頭の心配までしていただいてありがとうございます。

    Azuleanさんへ。
    僕の質問は、ひらがな一文字を入力した時点で確定するソフトを作っていています。それが起動したときに、自動的にIMEが起動しないから起動したいというものです。

    Enterの一件は、LoadでもTextChangedでもなく、
    EnterイベントにIMESetter.ChangeImeMode(this.Handle, ImeMode.Hiragana);
    と入力したという意味です。

    ちなみに、ファイルを開いたときや、クリップボードから貼り付けた時などは、特に対策を講じる予定はありません。

    わかっていただけましたでしょうか?
    わかっていただけたら、質問に答えていただけませんか。
    僕の頭の心配までしていただく必要はありません。


    2012年1月4日 6:33
  • この質問ってステータスが既に解決済みになってますけど・・・

    当初の内容と違うのであれば、新たに立てて何がしたいのかを見直した方が良いですよ。

     

    正直現在どういう状況で何がしたいのか解らないですし、理解しようという気が・・・

    2012年1月4日 6:55
  • じっくり考えなおした結果、「(ソフトが)起動したとき」に「(IMEを)起動したい」ということでしたら、FormのLoadイベントのみに記述すれば十分です。

    それ以外のタイミングでなんらかの動作を望むのであれば、本当にじっくり考えなおしたのかどうか、やはり質問者さんの頭の心配をせざるを得ません。

    2012年1月4日 7:38
  • 僕の質問は、ひらがな一文字を入力した時点で確定するソフトを作っていています。

    IME を前提として実装する場合、利用している IME の挙動に依存しますので、環境に依存せずに実現することは不可能だと考えられます。
    MS-IME は希望通りの動作をしますが、ATOK は未確定状態での入力になります。
    その他の IME は知りません。

    環境に話がまったくでていないので、それが問題なのか、問題にならないのか、私にはわかりませんが。

    わかっていただけましたでしょうか?
    わかっていただけたら、質問に答えていただけませんか。

    わかりません。
    私の文章は長かったかもしれませんが、もう一度読み直していただけませんか。

    ただ、今の雰囲気からすると、必要なことをお答えいただいても、解決策を誰も提示できない可能性があります。 環境依存するとなると、正直対応が不可能か、困難です。
    そうなると、コミュニティでの質問で何とかするレベルではないと思います。
    (すべての環境で通じる方法をあなたのためだけに探すなんて、一種の業務依頼です)


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2012年1月4日 9:05
    モデレータ
  • IMEはMS-IME2010です。

    これ以上話をしても不毛そうなので、この辺で質問をたたむことにします。

    ありがとうございました。

    2012年1月5日 0:22
  • IMEはMS-IME2010です。

    Windows 7 (x64) + MS-IME 2010 + .NET 3.5 or 4 において、Enter イベントで特に問題なく動作しました。
    結局のところ、情報開示不足のままです。

    今回はあきらめられるそうですが、次回以降質問される前に以下のページを読んでみてください。
    http://www.hyuki.com/writing/techask.html


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2012年1月5日 13:45
    モデレータ