2009年5月30日土曜日

どうしても出来ないこともある

-
最近、C#を使って、コンソールのフォームアプリみたいなものを作っていました。
かなり完成に近づいてきて、後はイベントを発生させるだけだと思っていました。

しかし

最悪なバグを発見しました。

コンソール画面上にあるマウスのX座標が取得できません

以下のコードは、画面上にあるマウスの座標をひたすら出力し続けるプログラムです。
断言します。絶対にプログラミングミスではありません。
using System;
using System.Runtime.InteropServices;
using HANDLE = System.IntPtr;

class Sample{
[DllImport("kernel32.dll")]
static extern HANDLE GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")]
static extern bool ReadConsoleInput(HANDLE hConsoleInput,
[Out] INPUT_RECORD[] lpBuffer,
uint nLength,
out uint lpNumberOfEventsWritten);
[StructLayout(LayoutKind.Explicit)]
public struct INPUT_RECORD
{
[FieldOffset(0)]
public ushort EventType;
[FieldOffset(4)]
public KEY_EVENT_RECORD KeyEvent;
[FieldOffset(4)]
public MOUSE_EVENT_RECORD MouseEvent;
[FieldOffset(4)]
public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
[FieldOffset(4)]
public MENU_EVENT_RECORD MenuEvent;
[FieldOffset(4)]
public FOCUS_EVENT_RECORD FocusEvent;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct KEY_EVENT_RECORD
{
[FieldOffset(0), MarshalAs(UnmanagedType.Bool)]
public bool bKeyDown;
[FieldOffset(4), MarshalAs(UnmanagedType.U2)]
public ushort wRepeatCount;
[FieldOffset(6), MarshalAs(UnmanagedType.U2)]
public ushort wVirtualKeyCode;
[FieldOffset(8), MarshalAs(UnmanagedType.U2)]
public ushort wVirtualScanCode;
[FieldOffset(10)]
public char UnicodeChar;
[FieldOffset(12), MarshalAs(UnmanagedType.U4)]
public uint dwControlKeyState;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSE_EVENT_RECORD
{
public COORD dwMousePosition;
public uint dwButtonState;
public uint dwControlKeyState;
public uint dwEventFlags;
}
public struct WINDOW_BUFFER_SIZE_RECORD
{
public COORD dwSize;
public WINDOW_BUFFER_SIZE_RECORD(short x, short y)
{
dwSize = new COORD();
dwSize.X = x;
dwSize.Y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MENU_EVENT_RECORD
{
public uint dwCommandId;
}
[StructLayout(LayoutKind.Sequential)]
public struct FOCUS_EVENT_RECORD
{
public bool bSetFocus;
}
[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
public override string ToString()
{
return "(" + this.X + "," + this.Y + ")";
}
}

static void Main(){
HANDLE dh = GetStdHandle(-10);
INPUT_RECORD[] ir = new INPUT_RECORD[100];
uint n = 0;
while(true){
ReadConsoleInput(dh,ir,1,out n);
Console.Write(ir[0].MouseEvent.dwMousePosition);
}
}
}

何度考え直しても間違いはありませんでした。

それで、色々と調べたら、API取り込み部分を参照したぴんぼけ.NET様にdwMousePosition.X was always 0という文が……

「dwMousePosition.Xは常に0だった」

私の場合1ですが、とにかく原因不明で使えないことは明らかです。

最悪です……今までの苦労が水泡になりました。そんなに大変ってわけではありませんでしたがね。

とにかく、テキストエディタのコンソールバージョン「エフィア」はC#で作ることが不可能ということです。
C++かDかのどちらかになりますが、C#に似ているDを使ってみることにします。

で、D言語ではこうなります。
import std.c.windows.windows;
import std.stdio;

int main(char[][] args){
HANDLE dh = GetStdHandle(-10);
INPUT_RECORD ir;
uint n = 0;
while(true){
ReadConsoleInputW(dh,&ir,1,&n);
writeln("(",ir.MouseEvent.dwMousePosition.X,",",ir.MouseEvent.dwMousePosition.Y,")");
}
return 0;
}

ばっちり動きます。

Dでライブラリ作ってもユーザー少ないからあんまり意味ない気がするなぁ。

0 件のコメント:

コメントを投稿