あまつぶ

12.31【ログイン時に起動する・書き込み編】

 12.18に書いた、イギリスからの買い物の請求書が届いた。1ポンドが182.261円の換算で、4274円。前に書いてからさらに円安が進んで、今日時点ではなんと190円をこえていたりするのを考えれば多少はよかったんだろうか。

 さて、前回、次はFinderのInformation Windowを開く方法と書いたが、予定変更。その上に書いた、「ログイン時に起動させる方法」がうまくいったのでそちらから書くことに(というか、Information Windowもまだうまくいってなかったりするのだけど)。
 ログイン時に起動の方法は、以前書いたとばかり思っていたのだが、 9.30に読み込みルーチンを書いて、「書き込みについては、次回」と書いたまま忘れていたのだった。ということで、今回はそのあたりの話。

 SetLoginPreferences(CoreFoundation/CoreFoundation.hをインクルード)

void SetLoginPreferences(Boolean newSetting)
{
  CFArrayRef     src_array; /* オリジナル */
  CFMutableArrayRef  dst_array; /* 変更を加えたもの */
  Boolean       currentSetting;
  CFIndex       index;
  
  currentSetting = ((index = GetLoginPreferences()) > 0);
  if (newSetting == currentSetting) return;
  
  /* まず、初期設定ファイル(loginwindow.plist)から情報を得る */
  src_array = CFPreferencesCopyValue(
      CFSTR("AutoLaunchedApplicationDictionary"),
      CFSTR("loginwindow"),
      kCFPreferencesCurrentUser,
      kCFPreferencesAnyHost);
  
  if (src_array)
  {
    Boolean    changed;
    
    /* 変更できるようにコピーする */
    dst_array = CFArrayCreateMutableCopy(NULL,0,src_array);
    
    if (dst_array) /* コピー成功 */
    {
      if (newSetting) /* add entry to preferences */
      {
        CFMutableDictionaryRef dict;
        CFStringRef       path;
        
        dict = CFDictionaryCreateMutable(
          kCFAllocatorDefault,0,
          &kCFTypeDictionaryKeyCallBacks,
          &kCFTypeDictionaryValueCallBacks);
        
        /* Hide : false */
        CFDictionarySetValue(dict,
          CFSTR("Hide"),kCFBooleanFalse);
        
        /* Path : */
        path = GetApplicationPath();
        CFDictionarySetValue(dict,CFSTR("Path"),path);
        CFRelease(path);
        
        /* add value to array */
        CFArrayAppendValue(dst_array,dict);
        CFRelease(dict);
      }
      else /* remove entry from preferences */
      {
        CFArrayRemoveValueAtIndex(dst_array,index);
      }
      
      /* save to preferences */
      CFPreferencesSetValue(
        CFSTR("AutoLaunchedApplicationDictionary"),
        dst_array,
        CFSTR("loginwindow"),
        kCFPreferencesCurrentUser,
        kCFPreferencesAnyHost);
      
      changed = CFPreferencesSynchronize(
        
CFSTR("loginwindow"),
        kCFPreferencesCurrentUser,
        kCFPreferencesAnyHost);
    }
    
    CFRelease(src_array);
    CFRelease(dst_array);
  }
}

 まずはソースから。最初に、前に紹介したGetLoginPreferences()を使って、すでに登録されているかどうかを調べる。それから、設定されようとしている状態と比較して、同じであれば何もせずに戻る。登録あるいは削除が必要な場合は処理を続ける。
 初期設定ファイル「loginwindow.plist」から情報を得るのだが、ここがまずふつうのアプリケーションの初期設定とやり方が異なる。自分自身の初期設定などの場合はCFPreferencesCopyAppValue()で設定を得ればよいが、ログインの設定の場合はCFPrefernecesCopyValue()を使うようだ。第1、第2パラメータはAppの場合と同じものを指定し、そのあとに、ユーザとホストを指定する。ログインの場合、ユーザごとに設定が異なるから、現在のユーザ(kCFPreferncesCurrentUser)を使う。また、ホストは、ホストごとに異なる設定が必要であればkCFPreferencesCurrentHostを指定、特にこだわらないのであればkCFPreferencesAnyHostを指定するようだ。
 さて、CFPreferencesCopyValue()で得たものは、変更できない(動かしてみるとそうでもないようだが、わざわざCFMutableArrayRef型が別に用意されていることを考えるとおそらくそういうことなのであろう)。そこで、CFArrayCreateMutableCopy()を使って変更可能なコピーを作成する(覚えにくい関数名だ)。そして、登録の場合はそこに新しいエントリを追加し、削除の場合は削除を行う。
 最後に、CFPreferencesSetValue()で設定を上書きし、CFPreferencesSynchronize()でファイルと同期させる。ここでCFPreferencesSetAppValue()などを使うと、設定が保存されない。ここがわからなくて、これまでうまくいかなかったのだった。できてしまえばあっけないが。

 これまで何度か書いてきた、Xでのキー配列変更について(前回は11.25)。半ば強引なやり方でようやく実現できたのでまずは報告。前回は、マウスとの組み合わせまではうまくいったが、キーとの組み合わせではうまくいっていなかった。
 キーとの組み合わせがだめなら、キーダウンイベントの時のflagsを変更してやったらどうだろう、と。あまりほめられたやり方ではないが、やってみる価値はあるのではないかと。キーダウンイベント(NX_KEYDOWN)が届いたとき、モディファイアキーの状態をチェックして、fnキー→ctrlキー、ctrlキー→optionキーに変更してやる。マウスとの組み合わせを考慮して、NX_FLAGSCHANGEDについてもそのままにしておく。
 結果は、今のところ良好。ただ、あまりきれいなやり方とは言えないし、副作用がある可能性もあるからソースやできたソフトについては公開しない。上の考えと前回の話を組み合わせれば同じ動きをするものができるわけだけど。
 9.2.2にアップデートしてからそのままにしてあった9.xのキー配列も変更を行い、なんとか無事両方の環境を(はりかえてしまったキートップにも)あわせることができた。 このまましばらく動かしてみて、特に問題が起こらないようであれば方法あるいはソフトウェアの公開を考えるつもり。

 年内の更新は今日が最後(大晦日だし、当然か)。来年もよろしくお願いします。よいお年を。


December 24, 2001 ↑ December index → January 1, 2002