Hatena::ブログ(Diary)

hishidaのblog このページをアンテナに追加 RSSフィード

プロフィール

hishida

hishida

EB series support page 管理人 ブログ

2017-02-12

[]EBWin4,EBMacに「全ての項目の表示」を実装

EBWin4、EBMacに、「検索に一致した全ての項目の表示」機能を追加した。(EBPocket for iOS/Androidも順次対応予定)

これまではEBシリーズの本文の表示モードには、連続表示と項目毎表示しかなかった。

連続表示とは、見出し語の本文を表示する場合に、後続の本文のテキストを続けて表示するモードである。

通常の連続表示の例:検索語 detectiveの後続のテキストを続けて表示

f:id:hishida:20170212101225p:image

EPWINGはもともと「電子書籍」を目指しており、一冊の本、または巻物のように、最初から最後まで通読できるようになっている。このため、EPWINGの公式ビューアであるCDView(富士通)、Viewing(イースト)、こととい(岩波書店)では、基本的に連続表示を行うようになっていた。(今ではWindows10インストールできるかどうかも定かでない)

項目毎表示は、検索に一致した見出し語の本文だけを表示するモードである。ただしEPWINGには項目の区切りという概念がないので、ソフトウェアで何の識別子を項目の区切りにするかを決定しないといけない。これはたぶんUnix上のEPWING検索システムや、DDWinのようなサードパーティ製のEPWINGビューアで出てきた概念だと思う。

今回追加した「全ての項目の表示」とは、検索に一致した見出し語の本文だけを、すべて一覧で表示するものであり、項目毎表示の結果を連結したものと考えるといいと思う。

全ての項目の表示:検索に一致した語の本文を連結表示

f:id:hishida:20170212101244p:image

実はDDWinにはこの機能が昔からあり(項目表示→全て表示)、今でもこの機能のためにDDWinを利用しているというユーザもいらっしゃるらしい。

DDWinには一つ制約があり、串刺し検索で「全て表示」を行なった場合に、先頭の辞書しか外字が表示できなかった。EBWin4/EBMacでは全ての辞書の外字を表示するようになっている。これについては、EBWin3.xまではWin32 APIで描画していたため拡張が難しかったが、EBWin4では本文表示をWebブラウザコントロールで行っているため、実現がしやすくなった。

既知の問題点、および制約についても書いておくと、

  1. 「全ての項目の表示」では縦書き設定は解除される
  2. 「全ての項目の表示」を行なった後で、検索一致リストから項目を選択した時の挙動は、通常の連続表示/項目毎表示に戻る
  3. 串刺し検索の場合、リンクが働くのは先頭の辞書のみ

複合検索のモードレス化

もう一つ、EBWin4で改良を行なったのは、複合検索のダイアログがこれまでモーダルポップアップだったのを、モードレスポップアップに変更した。複合検索ダイアログを表示したままで、次々と絞り込み検索をするという使い方が可能になった。

モードレスにしようとすると、ダイアログ側から、メインスレッドの表示処理をコールバックする必要がある。C++だと関数ポインタ引数で渡すような実装方法になるが、C#にはdelegateという機能があり、もう少し美しく実装できる。

モーダルダイアログの場合。OKボタンを押すまで制御が帰ってこない。OKボタンを押すとダイアログが消え、メインスレッドで検索結果を表示する。

	ComplexSearchDialog cplx_dlg = new ComplexSearchDialog();
	cplx_dlg.Owner = this;
	// モーダルダイアログとして表示
	if (dlg.ShowDialog() == DialogResult.OK)
	{
		// 検索結果を表示
	}

モードレスダイアログの場合。ダイアログを表示したまま、検索結果をメインスレッドで表示する。

	private ComplexSearchDialog cplx_dlg = null

	if ( cplx_dlg == null || cplx_dlg.IsDisposed)   // 二重起動を防ぐ
	{
		cplx_dlg = new ComplexSearchDialog();
		cplx_dlg.RefreshEvent += delegate(object sender, EventArgs e)
		{
			// 検索結果を表示
		};
		cplx_dlg.Owner = this;

		// モードレスダイアログを表示する
		cplx_dlg.Show();
	}					

ダイアログ

public partial class ComplexSearchDialog : Form
{

	public delegate void RefreshEventHandler(object sender, EventArgs e);
	public event RefreshEventHandler RefreshEvent;

	// OKボタンが押された場合
        private void okButton_Click(object sender, EventArgs e)
        {
		//検索処理をする
		(略)
		//  検索結果をメインスレッドで表示する
		this.RefreshEvent(this, new EventArgs());
 }

2017-02-04

[][] EBPocket for iOS サスペンドからの復帰で異常終了する件が解決

「EBPocket for iOS が、サスペンドからの復帰時に異常終了する」という報告が以前から上がっており、なかなか原因が分からなくて頭を悩ませていたが、どうやら解決できたと思う。

iOSアプリプロセスのライフサイクルについて

まず前提として、iOSアプリには「終了させる」という概念がない。(実際、アプリに終了ボタンをつけると審査でリジェクトされる)

アプリを切り替えて(1)アクティブから(2)バックグラウンドになると、しばらくして(3)サスペンドに移行し、メモリが少なくなるとiOSから自動的に終了させられ、(4)停止状態になる。

iOSアプリの状態遷移とライフサイクル - Qiita

ホームボタンを押してアプリ選択した場合、(3)サスペンドから(1)アクティブに復帰する場合と、(4)停止状態から起動されて(1)アクティブになる場合がある。このうち、後者の(4)から(1)のときに異常終了していたらしい。

これを再現しようと思うと、他にメモリを占有するアプリを多数立ち上げて、メモリ不足の状況をつくらないといけない。

私は普段はAndroidを使っていてiOSは実機デバッグでしか使用しないので、なかなか気付かなかった。

ところが最近、あるきっかけでiOSを日常的に使うようになった。

キャンペーンでキクタアプリを買う

昨年末頃にAppStoreのセールで、次のキクタアプリが通常480円のところ全品120円になっており、紙の書籍より大幅に安いので、まとめ買いした。

iPhoneアプリ「キクタン」で、効率的に英単語学習!:アルク

それでiPod touchを毎日使うようになり、キクタンを同時に立ち上げてからEBPocketに戻ると、ユーザからの報告通りに異常終了することがわかった。

Xcodeでのクラッシュログの取得方法

再現さえすれば対処が可能になる。Xcodeデバッグモードで実行し、異常終了させてから、次の手順でクラッシュログが取得できる。

Menu→Windows→Devices

左側ペインの[DEVICES]から実機を選択し、[View Device Logs]を押すとクラッシュログが表示される。デバッグモジュールなので、異常終了したソースの箇所がわかる。

f:id:hishida:20170204105835p:image

その結果、NSString::drawAtPoint:forWidth:withFont:lineBreakMode:で落ちていることがわかった。このメソッドはiOS7からdeprecated(非推奨)になっているもので、

これをiOS7以後の推奨メソッドの NSString::drawAtPoint:withAttributes: に変えたら落ちなくなった。

iOSは毎年メジャーバージョンが上がり、その度に使用できていたAPIが使用できなくなったりするので、メンテナンスを続けていかないとiOSバージョンアップで使用できなくなることがある。

もしかすると二年ぐらい前から異常終了するようになっていた可能性がある。これで、失った信頼が回復できるといいのだが。

EBPocket FreeをEBPocket Basicに改称した経緯

今回提出にあたって一つトラブルがあった。Pro版はすぐに審査が通って公開されたが、EBPocet Freeの方が、アプリ名に"free"が入っていることが原因で、metadata rejectを食らった。

2. 3 PERFORMANCE: ACCURATE METADATA

Performance - 2.3.7

Your app's name to be displayed on the App Store includes references to your app’s price, which is not considered part of an app name.

Next Steps

Please remove any references to your app’s price from your app’s name, including any references to your app being free or discounted. If you would like to advertise changes to your app’s price, it would be appropriate to include this information in the app description. Changes to your app’s price can be made in the Pricing and Availability section of iTunes Connect.

アプリ名に価格を含んでいるといけないらしい。だがAppStore には free という名称を含むアプリがごまんとある。理不尽だが、Appleと戦っても勝てないので、あきらめてアプリ名を EBPocket Basic に変えて再提出したら、あっさり審査に通って公開された。

EBPocket FreeをアップデートしたらEBPocket Basicに変わってしまって驚かれるかもしれないが、これはAppleの審査のためで、内容は同じなのでご理解いただきたい。

P.S.

前述のキクタアプリはとてもよく出来ていて、音声も収録されているので、紙の書籍よりアプリの方がいいと思う。残念ながらiOSのみで、Android版は提供されていない。おかげで通勤時にキクタンを聞く習慣ができた。

2016-12-01

[][][]EBWin4 の高DPI化について

EBWin4の高DPI化を行ったので、忘備録として作業内容をまとめておこうと思う。

事の発端は、Macbook pro retina 13" Early2015を購入したこと(2016-11-19 - hishidaのblog)。retinaディスプレイではVMWare Fusion上のWindowsの文字が極端に小さくなり、文字サイズを拡大しないと使用できなくなった。

Macbook pro retina 13"の実解像度は2560x1600だが、Mac OS Xでは擬似解像度1280x800にスケーリングされて表示される。だがVMWare 上のWindowsではドットバイドットで表示されるので、2560x1600の実解像度のまま表示され、文字が小さくなってしまう。

「ディスプレイ設定」→「テキスト、アプリ、その他の項目のサイズを変更する:」で150%〜200%に拡大すると、DPIのスケーリングに従ってアプリも拡大されて表示される。だがEBWin4のように高DPIに対応していないアプリだと、下図のように文字がにじんで表示されてしまう。Surface Proなどの高解像度の端末では、以前から問題になっていたと思う。

図:高DPIに対応していない場合、文字サイズを拡大するとにじんで表示される:

f:id:hishida:20161202110628p:image

Windows Form アプリの高DPI化作業について

高DPI化全般については、下記のマイクロソフトの田中達彦氏のブログが詳しい。

アプリの高DPI(High DPI)対応について 第1回 ~ 高DPIとは ~ – 田中達彦のブログ

WPFで開発したソフトは自動的にdpiAwareになるが、昔ながらのWindows Formで開発したソフトは、デフォルトでは高DPIに非対応となる。

Windwos FormでアプリをdpiAwareにする方法は簡単で、前述のブログにあるように、app.manifestを追加してdpiAwareをtrueにすればいい。

app.manifestは、Visual Studio でプロジェクトで右クリック→追加(D)→新規項目(W)で簡単に追加できる。

ただしdpiAwareの雛型が作られるのはVisual Studio 2013以降なので(現行のVisual Studio Community 2015もOK)、Visual Studio 2010以前のバージョンを使用している場合は、記述を手動で追加する必要がある。

app.manifestに追加した記述:

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

基本的には、これだけでdpiAwareになり、文字サイズを拡大しても文字がにじまなくなる。

ただEBWin4の場合はEPWINGの外字をビットマップイメージで表示しており、文字サイズを変えても外字ビットマップは小さいままなので、表示のバランスが非常に悪くなる。

つまり現在のWindowsの文字サイズの倍率を取得して、ビットマップ画像も拡大しなければならない。

様々なサイトを参考にして、現在のDPIを取得するサポートクラスを追加した:(100%なら96dpiを返す)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;


namespace EBWin4
{
    public static class ScreenExtensions
    {
        public static void GetDpi(this System.Windows.Forms.Screen screen, DpiType dpiType, 
                   out uint dpiX, out uint dpiY)
        {
            try
            {
                var pnt = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
                var mon = MonitorFromPoint(pnt, 2/*MONITOR_DEFAULTTONEAREST*/);
                GetDpiForMonitor(mon, dpiType, out dpiX, out dpiY);
            }
            catch
            {
                dpiX = 96;
                dpiY = 96;
            }
        }

        //https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062(v=vs.85).aspx
        [DllImport("User32.dll")]
        private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);

        //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
        [DllImport("Shcore.dll")]
        private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);
    }

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx
    public enum DpiType
    {
        Effective = 0,
        Angular = 1,
        Raw = 2,
    }
}

上記クラスを使用して、現在の文字サイズのスケールを取得する関数

        /// <summary>
        /// ScreenのDPIスケールを得る
        /// </summary>
        /// <returns></returns>
        private double GetDPIScale()
        {
            double dpiScale = 1.0;
            try {
                //  現在フォームのあるスクリーンを得る
                System.Windows.Forms.Screen s =
                    System.Windows.Forms.Screen.FromControl(this);
                uint x, y;
                s.GetDpi(DpiType.Effective, out x, out y);
                dpiScale = ( x / 96.0);
            }
            catch {
            }
            return dpiScale;
        }

DPIスケールに合わせて画像を拡大する関数

      /// <summary>
        /// DPIに応じて拡大したImage画像を作成
        /// </summary>
        /// <param name="image"></param>
        /// <param name="dpiScale"></param>
        /// <returns></returns>
        private Image GetImageStretchedDPI(Image image, double dpiScale)
        {
            Size newSize = image.Size;
            newSize.Width = (int)(newSize.Width * dpiScale);
            newSize.Height = (int)(newSize.Height * dpiScale);

            Bitmap newBitmap = new Bitmap(image, newSize);

            image.Dispose();
            return newBitmap;

        }

これで高DPIで美しく文字が表示されるようになった。

図:高DPI化されたEBWin4

f:id:hishida:20161202110623p:image

高DPI時代のEPWINGビューアとして、もうしばらく延命できることとなった。

2016-11-04

[][][]EBPocket for iOS の中華フォント現象

「iOS10から、EBPocket for iOSの本文の日本語部分のフォントが中国語の繁体字になっている」というご指摘があった。iPad mini2で確認すると、英語フォントを指定した場合、確かに中国語の字形になっている。フォントの初期値をヒラギノではなく英語フォントのTimesNewRomanPSMTにしているのは、英和辞典などで文字のバランスがよいためだが、以前は日本語部分はヒラギノで表示されていた記憶がある。

調べてみると、最近のiOSでは中華フォント現象というのがあるらしい。

iOS で日本語文章に発生する中華フォント現象とは - Qiita

ただこのページで書いてある解決方法はSwiftの話で、EBPocketではObjective-CでUIWebViewを使用して本文を表示しているので、そのまま適用できない。

いろいろ試したところ、次のように、UIWebViewに表示するhtmlにlang="ja"をつければいいということがわかった。これでめでたく日本語部分がヒラギノで表示されるようになった。

<!DOCTYPE html>
<html lang='ja'>

言語の指定がないと標準で英語(lang='en')になり、iOSのフォントの優先順位で中国語が日本語より先にあるために、フォールバックで中国語フォントが選ばれるらしい。

とりあえず中華フォント現象のみ対応したバージョンをAppStoreに提出した。iOSのバージョンが上がってから初めての提出なので、審査が通るかどうかちょっと不安。

やっぱりiOSのバージョンが上がると必ず何かしら問題が起きるなぁ。

P.S.

AppStoreの審査は1日で通過し、本日リリースされた。最近は審査がスピードアップされているらしい。

2016-11-03

[][][]読書尚友・EBPocketをマテリアルデザインに対応

Androidアプリの読書尚友とEBPocketを、マテリアルデザインに対応してみた。

f:id:hishida:20161103094214p:image

f:id:hishida:20161103094210p:image

f:id:hishida:20161103094205p:image

マテリアルデザインはiOSなどのフラットデザインに似ているが、画面のパーツが現実世界の素材のメタファになっており、厚みや奥行き、重なり、質量を持つ。

GoogleはGoogle I/O 2014でマテリアルデザインのガイドラインを出したが、当初はGoogle謹製のアプリのようなUIを実現するには開発者が自前でコードを書く必要があった。2015年にDesign Support Libraryが公開されたことで、マテリアルデザインに沿ったアプリを作りやすくなった。

個人的なAndroidの開発環境をEclipseからAndroid Studioに移行したことで、これらのライブラリの導入が簡単になった。もうEclipseには戻れないと思う。

Android Studio では新しいプロジェクトを作るときのテンプレートでマテリアルデザインに沿ったアプリの雛形を生成できるので、自動生成されるレイアウトやリソースを流用したほうが作業が早い。

今回のマテリアルデザイン化の作業をまとめてみると:

  • styles.xmlでマテリアルテーマを使う。
	Theme.AppCompat.Light.DarkActionBar
	Theme.AppCompat.Light.Dialog
  • 配色はマテリアルデザインガイドにあるものを使用する
  • 従来のFragmentActivityやActionBarActivityのかわりにAppCompatActivityを使う
  • ActionaBarのかわりにToolBarをつかう。(ただしAppCompatActivityで従来のActionaBarも使える)
  • Design Support Libraryの部品を使う。今回使用したクラスは、
android.support.design.widget.CoordinatorLayout
android.support.design.widget.AppBarLayout
android.support.design.widget.NavigationView
android.support.v7.widget.Toolbar
  • サポートライブラリの定義をbuild.gradleに追加
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:design:23.4.0'
    compile 'com.android.support:support-v4:23.4.0'

EBPocketのほうはマテリアルデザインの導入を機にかなりUIを見直したので、操作性が向上したと思う。

  • ActionBarメニューは本文に関するメニュー(共有、ブックマーク登録、ページ内検索)だけ残し、他はナビゲーションドロアに移動。
  • グループ選択とグループの編集がナビゲーションドロアでできるようにした。グループ切り替えが迅速にできるようなった。
  • ブックマーク、最近の項目、履歴を共有で外部アプリに渡せるようにした。
  • オーバースクロールによる前画面移動をオプションでオフにできるように。
  • SearchViewの検索履歴ポップアップをデフォルトでオフにした。

EBPocketの今後の課題

  • PDIC,MDict,StarDictでブックマークを保存できるようにする
  • App Indexngに対応する。Google検索にアプリ検索を表示する機能。従来は端末内検索という機能があったが、Kitkat以降削除され、App Indexingが推奨されるようになった。

ただしApp IndexngはWebサービスも必要で、アプリだけ登録する場合は申請フォームから申請の必要があるらしい(まだ十分に調べていない)

  • 要望の上がっているところではAnki連携。ただ私がまずAnkiになれないといけない。
  • あとは単語帳とか、英語学習的な機能を充実できれば。

読書尚友の今後の課題

  • 本棚をRecycleViewにして、カード形式とグリッド形式を切り替えられるようにする。
  • ファイルブラウザの機能向上