<< NEW | main | OLD>>
Wheelpoolの開発が一段落したので
開発中のネタなんかをいくつか

<開発環境>
Win7(x64) / .NET3.5 / C#


■C#でのグローバルフック(低レベルフック・システムフック)

今回使用したのは低レベルマウスフックおよびキーボードフックです
これらは.NETで使用する場合はdll実装の必要がありません
参考になる実装例をいくつか紹介します

グローバルフック・ザ・キーボード
グローバルフック・ザ・マウス
覚書/C♯/グローバルフック

どちらもそのまま使えるレベルのサンプルです
最初の2つの方がC#らしいコードで私は好きですが
3つ目のサンプルはイベントがたくさん用意されているので
用途によってはこっちのが使い勝手がいいかもです
(3つ目のサンプルはマウスフックのクラス名とコンストラクタ名が
一致してないので注意してください…まあビルドの段階で気づくとは思いますが一応)

Visual Studioでグデバッグする際のコツとして
3つ目のサイトにもかいてありますが

①デバッグオプションでVisual Studio ホスティングプロセスを有効にするというオプションを無効にする
②GetModuleHandle(NULL)を呼び出す

といった方法があります
このどちらかを行わないとデバッガ上でフックを検知できません
最初①でやっていたのですが、Console.Writeline()が出力されなくなるという
よくわからない現象に見舞われたので結局②の方で落ち着きました
その場合#if DEBUGプリプロセッサを利用して切り替えられるようにしておくと捗ります


■DirectInputへの対応

先日、吉里吉里製のゲームをやっていたら
ホイールイベントがキャンセルできないケースがありました
どうやらDirectInputでマウス入力を処理してるようです

DirectInputはドライバに限りなく近いところで動作してるようで
低レベルフックでも握りつぶせないみたいです
http://d.hatena.ne.jp/LM-7/20090614/1244980470

これに勝つにはフィルタドライバしかないですが
Vista以降ドライバは署名関係が面倒くさくなったのと
私にドライバを実装する実力と気力がかなり不足しているため(←重要)
この件への対応は未定です…


■SendInputで注意すべきキー

WheelpoolのキーストロークはSendInputで行なっているんですが
いくつか送信できないものがありました

・Pauseキー →スキャンコードが割り当てられてない?
・Fnキー →windows仕様上送信できない?
・Ctrl+Alt+Del →Win7の場合SendSASというAPIがあるようだがサービスとして動作させないといけないらしい

単に私の調査不足で、何か方法があるかもしれません
情報をお持ちの方はご一報ください

またWinXPでAlt+Tabを送信する場合ですが、
最初にAltを押し下げたスレッドが終了してしまうと
画面中央に表示されている起動中ソフトの一覧が消えてしまうようです
これはWin7では発生しない現象でした

仕方ないのでフリップ表示中はAlt押し下げたスレッド(※1)をずっとループさせておいて
後からフックしたホイールイベントで※1にTabを送るよう通知するようにしました

それからKeys列挙体のカオスっぷりはココに書いたとおり


■マスターボリューム変更

XP向けにはmixerXXXってAPIを使います
解説&サンプルを幾つか

WindowsオーディオミキサーAPIを使う
窓プログラミング ミキサーその1(音量の調節)
ミキサー用の構造体とか関数を C# 用に定義し直す

APIの解説は一番上のサイトに大変わかりやすくまとまっています
2つ目はC++の例ですが見通しのいいサンプルで全体の実装イメージがつかめると思います
最後のがC#の実装で、特に構造体のマーシャリングは参考になりました
ミキサー関係の構造体はアホみたいに入れ子になってたりUnionだったりで
移植が面倒だったので、ちょっと悩んだところを解説します

まずMIXERLINECONTROLSやMIXERCONTROLDETAILSで入れ子になってる構造体は
IntPtrで定義しておいて、Marshal.AllocCoTaskMemで初期化するのがポイントです

// 入れ子にするMIXERCONTROL構造体のメモリを確保して初期化する
int mxc_size = Marshal.SizeOf(new MIXERCONTROL());
IntPtr pmxc = Marshal.AllocCoTaskMem(mxc_size);

// MIXERLINECONTROLSの作成
MIXERLINECONTROLS mxlc = new MIXERLINECONTROLS();
mxlc.cbStruct = Marshal.SizeOf(mxlc);
mxlc.dwLineID = mxl.dwLineID;
mxlc.dwControlType = MixerControlType.MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = mxc_size;
mxlc.pamxctrl = pmxc; // ここにMIXERCONTROLへのポインタを指定する

UnionはStructLayout属性でLayoutKind.Explicitを指定して
同じオフセットを割り当てるのが常套手段のようですが、
MIXERCONTROLみたいに構造体のメンバに文字列があったりすると
CharSetによってオフセットが変わってきてしまうので難しいところです

StructLayout属性でCharSetを固定してもいいですが
オフセットが重複しているメンバはどうせ今回は使用しないので
LayoutKind.Sequentialにしてダブリはバッサリ消してしまいました
どうしても共用体を表現したいならプロパティ使う手もあります

// 文字コードに依存しない定義(共用体は無視する)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct MIXERCONTROL
{
public int cbStruct;
public int dwControlID;
public int dwControlType;
public MixerControlFlag fdwControl;
public int cMultipleItems;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
public string szShortName; // CharSetによって以降のオフセットが変わってしまう
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
public string szName;
// union
public int Bounds_lMinimum;
public int Bounds_lMaximum;
//public int Bounds_dwMinimum; // 以下オフセット重複部(使わないので定義しない)
//public int Bounds_dwMaximum;
//public int Bounds_dwReserved1; // int[]で定義するとエラーになる
//public int Bounds_dwReserved2; // どうも値型と参照型が同じオフセットにあるとだめみたい
public int Bounds_dwReserved3;
public int Bounds_dwReserved4;
public int Bounds_dwReserved5;
public int Bounds_dwReserved6;
// union
public int Metrics_cSteps;
//public int Metrics_cbCustomData; // 以下オフセット重複部(使わないので定義しない)
//public int Metrics_dwReserved1;
public int Metrics_dwReserved2;
public int Metrics_dwReserved3;
public int Metrics_dwReserved4;
public int Metrics_dwReserved5;
public int Metrics_dwReserved6;
}
// どうしても同じフィールドを個別に定義したいならプロパティ使えばいい
// (めんどいので該当部分だけプロパティ化…)
[StructLayout(LayoutKind.Sequential)]
private struct MIXERCONTROLDETAILS
{
public int cbStruct;
public int dwControlID;
public int cChannels;
// union
public IntPtr hwndOwner;
//public int cMultipleItems; // フィールド変数はhwndOwnerだけ定義しておいて
public int cbDetails;
public IntPtr paDetails;
public int cMultipleItems // プロパティで同じフィールドにアクセスする
{
get { return (int)(((long)hwndOwner) & 0x00000000FFFFFFFF); }
set { hwndOwner = (IntPtr)value; }
}
}

ついでにもう一つ似たような問題として汎用ポインタ(IntPtr)も
32bit環境か64bit環境かでサイズが変わってきます
32bitではintと同じ=4byte, 64bitではlongと同じ=8byteです
構造体の途中にポインタがある場合もLayoutKind.Explicitで
オフセット指定すると崩壊してしまうので注意しましょう
(もしくはビルド構成で対象プラットフォームを固定してしまうとか)

ちなみにデフォルトのStructLayout.CharSetはCharSet.Ansiになります
取得するデバイス名が文字化けしてておかしいなあと思ったら
どこかのサイトに規定値Autoとか書いてあったのに騙されてましたよ…

今回見つけた超便利サイト
プラットフォーム呼び出しの定義で困ったらぜひ
http://pinvoke.net/index.aspx


さてXPの解説が長くなりましたが
Vista以降はサウンド関連のAPIが一新されたようで
マスターボリュームの調整にミキサー系のAPIは使えません

使えないとは言っても一応動作はするのですが、
マスターボリュームではなくアプリケーションごとの
ボリュームしか変更できませんでした

Vista以降でマスターボリュームを変更するには
ここのサンプルが大変参考になりました
Vista Core Audio API Master Volume Control


■モニター輝度変更

今回はWMIの機能を使ったんですが
SetMonitorBrightnessってAPIもあるみたいです
それぞれ操作できる機種が異なるという記事をどこかで読んだので
併用すれば対応機種が増えるかも……

なのですがウチのノートがWMIで輝度変更できちゃったので
今のところ実装予定はなしです
Windows/.NET comments(0) -


コメント


フォーム

ブログ内検索

自作ツールなど
■棒読みちゃんプラグイン
2ch専用ブラウザ読み上げ(改良版)

■IntelliPark設定ツール
WDIDLE3 for Windows

■マウスユーティリティ
Wheelpool

■ユーザー入力監視ソフト
iDLEM@STER

■さぽている攻略 [公開終了]
さぽつ~る(さぽつーる)
アイテムリスト成型
調合成功率計算
カテゴリー別

openclose

プロフィール

百合亞

Author:百合亞
敬虔な百合信仰者かつ崇拝者
将来の夢は女の子

管理人にメール

お名前:
メール:
件 名:

りんく
美少女万華鏡 -罪と罰の少女-

FLOWERS

2017年5月26日発売のNavel新作『月に寄りそう乙女の作法2.1エスパル』を応援しています!

「天結いキャッスルマイスター」応援中!

『想いを捧げる乙女のメロディー』2017年3月24日発売予定

オトメ*ドメイン

eye★phon(アイ・フォン)『つい・ゆり ~おかあさんにはナイショだよ~』

AXL新作第12弾「恋する乙女と守護の楯~薔薇の聖母~」 2016年1月29日発売予定!

お嬢様と秘密の乙女

カミツレ

【ハピメア】応援バナー

【白雪の騎士】応援バナー

ノブレスオブルージュ

シロガネオトメ

『ヒメゴト・マスカレイド』応援中!

屋上の百合霊さん

天使の羽根を踏まないでっ

「キミとボクとエデンの林檎」公式サイトへ

『るいは智を呼ぶファンディスク』を応援しています!

『処女はお姉さまに恋してる ~2人のエルダー~』絶賛発売中!!

りんく2
藤真拓哉オフィシャルブログ
CrystalDiskInfo - 水晶雫

マリかう

Powered by FC2 Blog    Templete by hacca*days.

PR