えぇ、ぷれますって呼ぶのは、今回が初です。
正月ネタですが、無事に生きています。やる気のあるうちは。
今日は、自作ライブラリの整理を・・・
なんかごちゃごちゃしてきたので、すみわけしました。
ぷれますは、まだ関係ないけどね。
早速ですが、ダウンロードは以下から。
正式リリースは、Ver.1.00以降としていますので、今はまだテスト版です。
タイトルも変わるかもです。アプリ側では一切、ぷれますなんて呼んでいない(´・ω・`)
なので使い方もリリースノートもありません。
アイコンもなく、UIもいかにもテスト版って感じです。その辺を向上させるのは正式リリースが近づいたらでよくって、今は機能メインです。その方がやる気も続くはず。
ガワだけよくても、中身くそだったらダメじゃん?
中身よくて、ガワがくそでも、フリーソフトだし別にいいじゃん?(ぉぃ
前回、次に何をするつもりでいたのか、すっかり忘れてしまいましたが(ぉぃ)、ちょっとした改善をほどこしました。
1.複製ウィンドウで水平方向に数ピクセルずれて画像が表示されていた
正月はしょぼいシングルディスプレイ環境で開発していたので気づきませんでしたが、戻ってきて、マルチディスプレイ環境で確認したら、水平方向にずれていました。
原因を探って、無事解決に至りました。
private void CopyScreen2()
{
const int BITMAP_HEADER_OFFSET = 54; // 54byte = Bitmap Header Offset
// 描画先メモリの確保
if (replicatedBitmapMemory == null)
{
replicatedBitmapMemory = new MemoryStream*1
{
using (var bmpGraphics = System.Drawing.Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(0, 0, 0, 0, screenBmp.Size);
screenBmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY);
screenBmp.Save(replicatedBitmapMemory, System.Drawing.Imaging.ImageFormat.Bmp);
}
// メモリ参照イメージデータを生成
if (replicatedBitmap == null)
{
replicatedBitmap = new WriteableBitmap(screenBmp.Width, screenBmp.Height, 96, 96, PixelFormats.Bgr24, null);
}
var stride = ((int)SystemParameters.PrimaryScreenWidth * replicatedBitmap.Format.BitsPerPixel) / 8;
replicatedBitmap.WritePixels(new Int32Rect(0, 0, replicatedBitmap.PixelWidth, replicatedBitmap.PixelHeight),
replicatedBitmapMemory.GetBuffer(), stride, BITMAP_HEADER_OFFSET); // ビットマップヘッダー(54bytes)だけオフセット
}
}
いまだにメソッド名に2とかつけてるあたり、程度を察してしまいますが、そんなことはとりあえずどうでもいい(´・ω・`)
この前、さらしたソースコードとの違いは、上の赤いところです。
メモリ上に直接ビットマップデータを保存しているのですが、ビットマップデータの保存先の種類がHDDからメモリに変わっただけで、保存されるデータそのものは変わっていないんですね。
なので、ビットマップとして保存したときに、ビットマップ情報を示すヘッダーの分だけ余計なデータが入っているわけです。
画素データの前にゴミが入っていたので、その分だけずれてしまっていました。
ヘッダーサイズは、54byteらしいので、メモリ予約を54byte増やし、WriteableBitmapにピクセル値を書き出すときは、54byteだけオフセットします。
これで水平方向のずれがなくなりました。
2.ウィンドウを完全に「いないもの」にした
カーソルモード時に、引いたライン上にカーソルをあわせると、ラインの下に隠れているものをクリックできませんでした。
これでは面白くないので、カーソルモード中は、このアプリに関するすべての表示を「いないもの」扱いにしました。
見えるけど、さわれません。幽霊みたいな感じですかね。(え?
たとえば、画面を全部赤く塗りつぶしても、裏に隠れているボタンをクリックしたり、テキストを選択したりすることができます。
画像ではわかりづらいですが、とりあえずそんな感じです。
なので、線を引いた状態でプレゼンを続行するとき、いちいち線を気にせずに画面を操作できます。
やったこと
を参考に、レイヤーウィンドウも無視するようにしました。
public const int WS_EX_TRANSPARENT = 0x00000020;
public const int GWL_EXSTYLE = (-20);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
void SetWindowHitTest(bool isEnabled)
{
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(this).Handle;
// Change the extended window style to include WS_EX_TRANSPARENT
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if (isEnabled)
{
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT);
}
else
{
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
}
}
必要なusingは、各々設定してください。
あとは、カーソルモードのときは、SetWindowHitTest(false)にすると、ウィンドウの一切のヒットテストが無効になり、みえるけどさわれないウィンドウが完成します。
で、ここで気づく。
複製ディスプレイにマウスカーソルうつってないじゃん><
なので、マウスカーソル相当のものをうつせるようにします。
というか、見えやすいカーソル的な何かを、マウスカーソルにストーキングさせるようにします。
それから、ラインを引ける範囲を明示できるようにします。
今はアプリが起動したディスプレイの全画面が強制されるので。
しかも、複製ディスプレイには、アプリの画面とは関係なく、プライマリディスプレイを複製してしまううんこ仕様になっているので、これも明示した範囲だけ複製ディスプレイに表示するようにします。
そしたらVer.0.40aにしますね。
*1:int)SystemParameters.PrimaryScreenWidth
* (int)SystemParameters.PrimaryScreenHeight
* 3 // 24bit = 3byte [PixelFormat.Format24bppRgb]
+ BITMAP_HEADER_OFFSET);
}
else
{
replicatedBitmapMemory.Position = 0;
}
// デスクトップ画像でメモリを更新
using (var screenBmp = new System.Drawing.Bitmap(
(int)SystemParameters.PrimaryScreenWidth,
(int)SystemParameters.PrimaryScreenHeight,
System.Drawing.Imaging.PixelFormat.Format24bppRgb