"Simple" is "Best"

開発時に詰まったところや 調べた結果日本語での情報が無かったり古かったりした場合に自分用のメモとして高校生(?)が更新していくブログ

マシュマロな「arrows SV F-03H」でSDカードを内部ストレージ化した話

事の発端

とある友人から「最近スマホの空き容量がなくて困っている」という相談を受けた

SDカードを買ってぶっ刺せば?と聞いたら

容量を食っているのはアプリの方だという

幸いAndroid Marshmallowだったので、SDカードを内部ストレージ化しちゃおう

という話になった

 

環境

友人が持っているスマホはタイトルの通り「arrows SV F-03H」

SDカードは以下のものを使用した

www.amazon.co.jp

問題発生

SDカードも無事手に入り、あとは刺してちょちょっとしたら解決、、、

と思っていたが現実はそうではなかった

どうやら製作元の富士通が色々細工をしているらしく

内部ストレージ化ができない模様

これでは困ったということで、なんとか方法を探してみると

以下のサイトを発見

inoccu.com機種は違えど、製作元は同じ富士通

もしかしたらと思い、上の記事に書いてあるとおりにやってみた

 

実際にやってみる

色々時間が無かったのと他人のスマホだったので、スクショの類は一切なし

まずADBで接続する

adb devices
adb shell

接続ができたらSDカードがしっかりと認識されているかを確認

sm list-disks 
disk:179,64

これでDISK-IDがわかる

今回の練習として、別端末の同手順で確認したら同じIDだった

恐らく初期値がそうなのであろう

では、内部ストレージ化をいたしましょう

>sm partition disk:179,64 private

 

これで、SDカード全てが内部ストレージとなる

もし、一部を内部ストレージ他を外部にするなら

>sm partition disk:179,64 mixed 40

こうする

これだと40%が外部、残り60%が内部となる

もし、内部ストレージとしての役を解き普通のSDカードにする場合は

>sm partition disk:179,64 public

これで晴れてSDカードとなる

内部ストレージ化しているSDカードは暗号化がされており

別端末(パソコン含む)では読み込むことができない

また、内部ストレージ化したSDカードにアプリをインストールし

何もせずにSDカードを抜くと当然アプリは起動しない

刺し直せば普通に起動するらしいが、そもそも内部ストレージ化したのだったら

抜かないのが一番

しかしアクシンデント

無事内部ストレージ化もでき、いざ移動してやろうとすると

「十分な空き容量がありません」

なんて言われる

ついさっきフォーマット(?)したわけなのだからそんなはずはない

10分ほど悩んだ挙句解決

そもそも、もとからあった内部ストレージがいっぱい過ぎた

最初からそうせいって感じだが、不要アプリをひたすらアンインストール

初期から入っているものがそのまんまなので、消せるものは全て消去or無効化

これで再度移動を試みると・・・

出来た

 

とりあえずということで、「B612」を移動させてみた

無事移動でき、起動もした

本人曰く、「前と何ら変わりない動作」だそうだ

SDカードにすることによって、実行速度が遅くなるのではないか

という心配があったのだが、それも解消

 

では、本命のデレステを移動させようとすると

なんとここでアクシデント

移動中にいきなり画面がもとに戻った

確認すると元の内部ストレージにあるので、再び移動

すると、何故かいきなり再起動をするスマホ

起動してすぐに

「システム」が反応しない

という旨の通知が

 

これは何やらまずい匂いがすると冷汗をかきながら確認

不思議なことに、ラブライブは元の内部ストレージに戻っていた

その後、テストプレイをしてもらったら楽曲データが吹っ飛んでいたらしいが

無事にプレイすることが出来た

ホッとしたのも束の間、「B612」が起動しない・・・

再起動後にアイコンが変わっており、見た瞬間に

「あ、これは死んだな」と察した

どうやらB612で撮った画像は残っていたらしいので一安心

 

今後どうするかは友人と相談する

もし、リベンジすることがあれば再び記事にしようと思う

あんまり深いところを弄るもんではないな(他人のならなおさら)

AndroidのThemeを無理矢理動的に変更したよっていう話

TwitterのアプリだとNight Modeっていう機能がついてる

暗いところでは目に優しくないから、色を落ち着かせようっていうもの

黒系が好きな私にとっては、是非とも自作アプリに組み込みたい

この場合、Themeを動的に切り替えるのが一番しっくり来るので実装してみると

つまずいてしまったのでメモ

 

こちらを参考にさせてもらった

stackoverflow.com

簡単にまとめると

Themeを変更した後にAvtivityを再描画させようぜ

と、いう話

 

1. styles.xmlを書き換える

今回は

「三種類のThemeをボタンをおすことによって切り替わる」

という感じで作っていく

てことで三種類のThemeを定義していく

res/valuse/styles.xml


    <resources>

    <!--First Theme-->
    <style name="FirstTheme" parent="Theme.AppCompat.Light.DarkActionBar"></style>

    <!--Second Theme-->
    <style name="SecondTheme" parent="Theme.AppCompat.DayNight.NoActionBar"></style>

    <!--Third Theme-->
    <style name="ThirdTheme" parent="Theme.AppCompat.DayNight.DarkActionBar"></style>

</resources>

色をわざわざ上書きするのも面倒くさいので、何も触らない

これならいちいち書く必要もないかもしれないが、名前がわかりやすくなるので

 

次がかなりの確率で忘れるのだが、しっかりAndroidManifest.xmlも変える

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kyoto.test.freeprojects.oldbigbuddha.changetheme">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/FirstTheme">  ←ここ
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 最初これを書き換えなかったためにビルドが通らなかった

 

2. レイアウトをちゃちゃっと書く

テストで作っているはずなのに無駄にレイアウトに凝ってしまうあるあるがあるので

そこら辺は程々に(と言いつつ長い)

とりあえずボタンが3つあればいい

layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="24dp"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:text="@string/app_name"
        android:textSize="32sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="16dp"/>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/bt_first"
            android:text="First Theme"
            android:textAllCaps="false"
            android:textSize="24sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"/>
        <Button
            android:id="@+id/bt_second"
            android:text="Second Theme"
            android:textAllCaps="false"
            android:textSize="24sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"/>
        <Button
            android:id="@+id/bt_third"
            android:text="Third Theme"
            android:textAllCaps="false"
            android:textSize="24sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"/>

    </LinearLayout>

    </LinearLayout>

特別なにかっていうものはない

今回の件とは関係ないが、

  1. IDはスネークケースで書く
  2. Padding・Marginは面倒臭がらずそれぞれ書く
  3. Left・Rightではなく、Start・Endで書く

というところを気をつけて書くと幸せになれるかもしれない

 

3. では、コードを書こう

今回重要になってくるのはsetTheme()

こいつにソースIDをぶち込んでやるとそのThemeを適用してくれる

ただ呼び出す場所が厄介で、setContentView()の前に書かないといけない

それでは動的に変更できないではないか

そんな気がするが、Activityを再描画させれば大丈夫

そのコードがこちら

finish();
startActivity( new Intent( this, MainActivity.class ));

最初このコードを見た時に動くのかと心配したが、普通に動いた

 

一回finish()を呼んでしまってるわけだから

シェアプリで一回選択したThemeを保存する

R.style.~~の形で取ってきているから、実態はint型のデータ

よって以下の形になる

mEditor = getSharedPreferences("themeData", MODE_PRIVATE).edit;
mEditor.putInt("theme", R.style.~~);
mEditor.commit();  // 注意

最初、mEditor.apply()と書いてうまくいかなかった

これはapply()が非同期で書き込んでいることが原因である

 

下にコードを載せるので見てほしいが

すぐ下にfinish()が書いてある

なので書き込んでしまう前に破棄されている模様

ちゃんとcommit()にする

 

あと紹介してないのは基本的なところだけなので

コードを貼って終了とする

MainActivity.java


package kyoto.test.freeprojects.oldbigbuddha.changetheme;

import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mBtFirst, mBtSecond, mBtThird;

    private SharedPreferences mPreferences;
    private SharedPreferences.Editor mEditor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreferences = getSharedPreferences("themeData", MODE_PRIVATE);
        setTheme( mPreferences.getInt("theme", R.style.FirstTheme) );
        setContentView(R.layout.activity_main);

        mBtFirst  = (Button)findViewById(R.id.bt_first);
        mBtSecond = (Button)findViewById(R.id.bt_second);
        mBtThird  = (Button)findViewById(R.id.bt_third);

        mBtFirst.setOnClickListener(this);
        mBtSecond.setOnClickListener(this);
        mBtThird.setOnClickListener(this);

        mEditor = mPreferences.edit();
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.bt_first: {
                mEditor.putInt("theme", R.style.FirstTheme);
                break;
            }
            case R.id.bt_second: {
                mEditor.putInt("theme", R.style.SecondTheme);
                break;
            }
            case R.id.bt_third: {
                mEditor.putInt("theme", R.style.ThirdTheme);
                break;
            }
        }
        mEditor.commit();
        finish();
        startActivity( new Intent( this, MainActivity.class ));
    }
}

Demo

f:id:bigbuddha:20170809193530g:plain

 

SecondとThirdの見分けが少々難しい

上にバーがあるかないかで判断して欲しい

以下にGithubリポジトリを貼っておく

github.com

Debian9(Stretch)を入れた後すぐにやったこと

今日(2017/08/05)、OSCに行ってきた

そこで「Debian Updates」という発表があり

そこで最後に、プレゼントとしてDebianのInstallDiscを頂いた

最近Debianに移行したのだが、無線系のドライバが上手く入ってなかったり

その他色々ミスがあったので、今回を気に入れ直した

最近様々なデストリビューションを入れて遊んでたときに

最初にやることが大体決まってきたのでメモ

Debianは既に起動している状態を前提とする

デスクトップ環境はGNONE、なるべく最小環境でInstallした

言語設定は英語にしてある

 

1.とりあえずZsh/Git/Vimを入れる

私の入れ方が悪いのか、Install時に設定したアカウントで最初からsudoが使えない

これは困るので、visudoで設定したいのだが

それを設定するために上記の3つを入れる

$ su -
# apt install vim zsh git
# chsh -s /bin/zsh

これがないと始まらない

まずは自分のリポからお手製のDotfilesを引っ張ってくる

ついでにログインシェルをzshにしておく

# exit
$ git clone ~自分のリポURL~
$ ln -s ./dotfiles/.zshrc .zshrc
$ ln -s ./dotfiles/.vimrc .vimrc
$ chsh -s /bin/zsh
$ exit

シンボリックリンクを使って引っ張ってくる

ターミナルを起動したあとに更新を忘れずに

$ source .zshrc

これで最低限の環境は揃った

やっぱり慣れた環境が一番落ち着く

f:id:bigbuddha:20170805212056p:plain

アカウント名はDeveloperで登録してある(今更感)

 

2.sudoを使えるようにする

なんかググると色々出てきて戸惑ったが

visudoでやった結果がしっかり使えるようになった

$ su -
# visudo

Vimが起動したのでちょちょっと以下のように編集する

f:id:bigbuddha:20170805213136p:plain

developer(自分のアカウント名)の部分を書き足す

これでsudoが使えるようになる

# apt update

これでパスワードを入れて動いたら成功

これでわざわざrootに入らずに色々入れることができる

 

3.日本語入力環境を整える

ただ開発するだけなら英数字記号を入れるだけでいいかもしれないが

ブログを書いたりSNSをしたりもするのでやはり日本語入力は外せない

私はfcitx-mozcをよく使うので今回も入れる

# sudo apt install fcitx-mozc

これで入る

検索欄でimと入れるとInput Methodというのが出てくるので

fcitxを選択

その後、Fcitx-Configurationを起動して、Mozcを追加する

f:id:bigbuddha:20170805214538p:plain

Mozcを一番上にすると起動時から日本語入力になって何かと不便

続いてMozc Setupを起動して自分好みにセットアップ

f:id:bigbuddha:20170805214741p:plain

ここまで来たら一度ログアウトをして、再ログイン

日本語入力ができたら成功

f:id:bigbuddha:20170805214911p:plain

ここまで来たらあとは煮るなり焼くなり好きにする

Tweek Toolを弄ると更に自分の環境が出来上がる

 

私はAndroid開発が主でなので

この後OpenJDKを入れてAndroidStudioを入れる

これはまた別途書後と思うので、今回はここまで

しばらく快適なDebianライフを過ごせそうだ

Fileを入出力するためのクラスを作ってみる

無事忌々しいテストも終わったもんだから

テスト期間中に組んだFileの入出力クラスをメモがてら紹介する

 

成り立ち

Javaから外部資源としてFileを読み書きするには

少々長ったらしい文を書かなくてはいけない

昔、Androidのクイズアプリを作った際に

CSVで問題データを保持させようということで

そのときに初めてファイルの入出力をいじった

非常に書きにくい

特に当時はリファレンスを見るという力も無かったため

色んな情報に左右されながら長ったらしいコードを書いていた

いま計画中のアプリでもCSVを使おうと思っているのでその前準備

 

何をするクラスか

大体Javaでファイルを扱うときは(ファイル管理ソフトでも作らない限りは)

新規作成・書き込み・読み込みこのぐらいができれば十分であろう

ついでにファイル削除もつけて、計4機能

こいつらを実装させていく

基本的にError処理は利用者任せにするため、全てthrow

 

使う機能

機能というと語弊があるかもしれないが気にせずに

今回のクラスはnioPathsを使ってファイルを操作する

ファイルの読みはBufferedReader、書きはPrintWriterを使う

 

とりあえずフィールド変数

今回使用する変数の方々

 


    
    /**
     * ファイルの生成、削除、名前変更を担当
     * */
    private Path path;
    /**
     * 文字コード設定のための定数
     * */
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private static final String BR = System.lineSeparator();
    private static final Pattern p = Pattern.compile(BR);

    /**
     * 読み込み用
     * */
    private BufferedReader reader;
    /**
     * 書き込み用
     * */
    private PrintWriter writer;
    private BufferedWriter bufferedWriter;

    /**
     * 読み込みの際に文字列連結高速化
     * */
    private StringBuilder content;

今回はちょっとJavaDocも書いてみた

ちょっと変わったところがこの二行

    private static final String BR = System.lineSeparator();
    private static final Pattern p = Pattern.compile(BR);

一行目は改行コードを取っているのだが

その改行コードがOSによって異なっているので

OSから改行コードをもらってきている

そのOS依存の改行コードを使ってパターンを作っているのが二行目

あとでこれを使ってゴニョゴニョする

今気づいたがあまりこれは意味がない・・・

 

続いてコンストラクタ


       /**
     * パスが文字列で与えられたときのコンストラクタ
     * @param pathName 操作したいファイルのフルパスを渡す
     * */
    public FileManager(String pathName) throws IOException {
        path = Paths.get(pathName);
        init(true);
    }

    /**
     * File型が与えられたときのコンストラクタ
     * @param file 操作したいファイルのFile型を渡す
     * */
    public FileManager(File file) throws IOException {
        path = file.toPath();
        init(true);
    }

    /**
     * Path型が与えられたときのコンストラクタ
     * @param path 操作したいファイルのPath型を渡す
     * */
    public FileManager(Path path) throws IOException {
        this.path = path;
        init(true);
}

3種類の型に対応できるようにした

今頃Fileという感じもするが

古いAPIだと返り値がFileということがあるらしい

init()の内容はその名の通り各フィールド変数の初期化


        private void init() throws IOException {
        bufferedWriter = Files.newBufferedWriter( path, UTF_8, StandardOpenOption.APPEND);
        writer = new PrintWriter(bufferedWriter, true);
        reader = Files.newBufferedReader( path, UTF_8 );
        content = new StringBuilder();
}

ここで注意しておきたいのが

bufferedWriter = Files.newBufferedWriter( path, UTF_8, StandardOpenOption.APPEND);

StandardOpenOption.APPENDをしっかりつけないと

実行時にファイルがまっさらになる

ほかは特に注意点なし

bufferedWriter = Files.newBufferedWriter( path, UTF_8, StandardOpenOption.APPEND);
reader = Files.newBufferedReader( path, UTF_8 );

こいつらは省エネな書き方

File file = new File(file_name);
BufferedWriter bw = new BufferedWriter(new FileWriter(file));

これが普通の書き方

最初に紹介したほうが個人的には好き

 

新規作成・削除

難しい処理は書くことなく、ほぼワンライン

無事に作成・削除できたかを知らせるboolean型の返り値を設定してある


    /**
     * ファイルを新規作成するためのメソッド
     * @return 作成に成功すればTrue, 既にファイルが存在する場合はFalse
     * @throws IOException 入出力エラーが発生した場合
     * */
    public boolean create() throws IOException {
        return path.toFile().createNewFile();
    }

    /**
     * ファイルを削除するためのメソッド
     * @return 削除に成功すればTrue, 失敗すればFalse
     * @throws IOException 入出力エラーが発生した場合
     * */
    public boolean delete() throws IOException {
        Files.delete(path);
        return !( exists() );
    }

説明はDocに書いてある通り

exists()っていうのは

ファイルが存在しているかどうかを調べるメソッド

以下の通りワンライン

public boolean exists() {
   return Files.exists(path);
}

外からでも有無を確認できるようにpublicにしてある

 

ここからが本番、読み込み

ここからがようやく本番といった感じ

いかにに無駄なく素早く処理するか

素人ながら色々工夫をして書いた


        /**
     * ファイルの中身を読み込むためのメソッド
     * @return ファイルの中身の文字列
     * @throws IOException 入出力エラーが発生した場合
     * @throws NullPointerException ファイルが空だった場合
     * */
    public String read() throws IOException, NullPointerException {
        if (exists() && Files.isReadable(path)) {
            String buffer;
            do {
                buffer = reader.readLine();
                content.append( buffer ).append( BR );
            } while (buffer != null);
            return content.toString();
        } else if ( !exists() ) {
            System.err.println("Couldn't find File");
        } else if ( !Files.isWritable(path) ) {
            System.err.println("Have no authority to read");
        }
        return null;
}

最初のif文で存在しているか&読み込み権限があるかを見ている

あとは定型文

これを何回も書きたくないからこのクラスを作ったようなもの

if文でboolen型を!をつけてFalseの場合に反転させているが

== falseで書いたほうが読みやすい気はする

 

仕上げの書き込み

最後の難関

    /**
     * ファイルに書き込むためのメソッド
     * @param text 書き込みたい内容
     * @throws IOException 入出力エラーが発生した場合
     * */
    public void write(String text) throws IOException {
        if (exists() && Files.isWritable(path)) {
            if (p.matcher(text).find()) {
                String[] buffer = text.split(BR, 0);
                for (String line : buffer) {
                    writer.println(line);
                }
            } else {
                writer.write(text);
            }
            writer.flush();
        } else if ( !exists() ) {
            System.err.println("Couldn't find File");
        } else if ( !Files.isWritable(path) ) {
            System.err.println("Have no authority to write");
        }
    }

ここで出てくるPattern

もし改行がある場合はそれを反映させ、ない場合はそのまま書き込む

この改行を楽にするためにPrintWriterを使用している

とは言えどもBufferedWriterにもnewLine()なんてのがあるので

素直にBufferedWriterを使えばよかった気もする

 

忘れられがちなClose

読み書きのメソッドを見て、close()がないことに気づかれただろう

忘れていたわけではなく、あえて書かなかったのだ

別にメソッドとして定義している

public void close_r() throws IOException {
  reader.close();
}

public void close_w() throws IOException {
   writer.close();
}

案の定のワンライン

なぜ読み書きの処理に埋め込まずに別途定義しているのか

それはそれぞれのメソッドがエラーを利用者に委ねているため

本来close()をいうのはfinallyの中に書かなくてはいけない

しかし、エラーを投げてしまっているため

finallyもクソもないのである

そのため、苦肉の策として別途定義することで

利用者側にfinallyでしっかり閉めてもらうことができる

私自身、かなり嫌々この方式を取った

もし何か良い策があったら連絡下さい

 

最後に

作ってから気づく実際に使えるのか感

実践で使ったことがないので何とも言えないが

あまり使える気がしない

今度使った後に感想でも書くこととしよう

 

このコードはGithubに上げてある

以下のリンクからすべてを見ることができる

github.com

Github上では、今回紹介した以外のメソッドも幾つか書いてあるので

気になる方はぜひご一読を

 

以上

次はCSVのパーサーでも自作したい

JAVAでコマンド版カウントダウンをしてみる

たまに、Youtubeなどで

コマンドプロンプト上で動くゲームを作る実況動画なるものがあるが

全てC系統で組んでいる

何故JAVAがないのかを考えてみると

System("cls")

がないことに気づく

素直にC系統を勉強して作ればいいだけかもしれないが

たまたまこのような記事を見つけたので

応用(と言うなの丸パクリ)してコマンドライン上で動く

カウントダウンアプリ(?)を作ってみる

 

使うもの

特筆して使うものは以下の2つ

  1. Thread.sleep()
  2. Process(ProcessBuilder)

 

大まかな仕組み

仕組みというほど大げさなものではないが

Whileループの中でSystem.out.printを使って一秒単位で画面上に秒数を表示する

画面の更新にはSE7から追加されたProcessを使う

1,2共にエラーをTry-catchしないといけないので

前回同様実装時には適切なエラー処理を

 

ソースコード

public class Main {
	public static void main ( String[] args ) {
		int c = 0;
		ProcessBuilder pb = new ProcessBuilder( "cmd", "/c", "cls" );
		while ( c < 10 ) {
			try {
				pb.inheritIO().start().waitFor();
				System.out.print( c );			//printlnではなくprint
				Thread.sleep( 1000 );
			} //以下エラー処理(省略)
			catch( InterruptedException iue ){} 
			catch( IOException ioe ){}
			c++;
		}
	}
}

これぞ5分クオリティ

 

解説(と言うかメモ)

見て一発でわかるプログラムなもんだから書くことなどなにもないのだが

ProcessBuilder pb = new ProcessBuilder( "cmd", "/c", "cls" );
pb.inheritIO().start().waitFor();

参考にしたサイトの方がよくわからないと仰っていたこの部分だけ調べたのでメモ

参考サイトの方では変数を使わず直接繋げてやっていられた

個人的にはこっちのほうが理解しやすかったのと

Whileの中でインスタンスを毎回生成すると言う無駄なことを防ぐためにこうした

 

一行目は普通のインスタンス作成

どうやら第一引数に起動したいプログラム名(?)

それ以降にそれぞれ分けてそのコマンドの引数

上記だと

コマンドプロンプト上でclsを実行する

というProcessBuilderインスタンスを作ることになる

次の行は1つずつ分解して考えてみる

 

inheritIO()

返り値はProcessであることに注意

リファレンスを見てみると

サブプロセスの標準入出力の入力元と出力先を、
現在の Java プロセスと同じものに設定します。

 とある

簡単に言えば

”結果をいま実行しているコマンドライン上に表示する”といった感じ(あくまでも感じ)

今回はclsなので動かしているコマンドライン上の画面がクリアされる

start()

これも返り値はProcess

名前の通り登録したプロセスを実行するメソッド

コヤツはいくつかエラーを吐くので

詳しくはこちらを確認

waitFor()

ラスト

返り値はint型、所謂終了コードを返してくれる

これは要求したプロセス(ここではcls)が終了するまで

JAVAの処理を中断するというもの

 

以上

これで二行目の文の説明(?)終了

 

もう少し実用的にするのであれば

最初に数値入力を促すウェザードを実装するか

引数で秒数を取得するなどして

時間の上限を動的にするといいかも

 

今後

最初に書いたように

コマンドライン上で動くゲームをJAVA作りたい

そんなこと考えながら

まず第一歩として画面の更新の方法をまとめてみた

そのうちに連載企画としてやってみたい

 

 

 

Win7でレジストリをいじってキー配列を変える

今の時期にWin7の話をするというのも時代遅れなきがするが

メモとして書いておく

 

最初に

当然の事ながら、レジストリをいじるので自己責任のもとで

バックアップは必須

これからすることによってパソコンがどうにかなったとしても

私は責任を取れない

 

今回は「Caps Lock」を「Alt」としてみる

参考サイトはこちら

How to Disable Caps Lock Key in Windows 7, 8, 10, or Vista

Windows/TIPS/レジストリを修正してCAPSLOCKの割り当て変更 - yanor.net/wiki

Windows Vista/XP/2000/NT4.0のキー配列の変更方法

主に二つ目を参考に話をすすめる

 

本題

レジストリ エディタを使って

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

 にScancode Mapという名でバイナリ値を作成

 そこに以下の内容を入力

00 00 00 00 00 00 00 00
02 00 00 00 38 00 3A 00
00 00 00 00

f:id:bigbuddha:20170104072000p:plain

勉強タイム

 勉強がてら、一つ一つを読み解いていく

まず、一行目の008つはヘッダのようなのでそのまま入力

続いて、二行目

これは2つに分けて02 00 00 0038 00 3A 00に分けられる

一つ目の02 00 00 00は変更するキーが2つですよということ

 

ここで一つ疑問

1(Caps Lock) + 1(Alt) = 2

確かにその通りであるが

ここで一つ疑問

なぜ02が一番最初に来ているのか

普通に考えて最後に来るのが普通ちゃうんかい┌(`Д´)ノ)゚∀゚)

って思っていたが、ふと「リトル・エンディアン」を思い出して

あぁ、なるほどね~

なんて思った

「リトル・エンディアン」がわからない方は

Wikipediaに聞くなり、ググっていただくと幸せになれるかもしれない

 

無事疑問は解決し・・・

では次

 38 003A 00

最初の値が変更後(出力)の役割、次に変更前(入力)の役割

リトル・エンディアンだから、383A

38がAltのキーコードで3AがCaps Lockのキーコードである

有名どころを抑えておく

名称入力値
Alt(Right) 38E0
Alt(Left) 3800
Caps Lock 3A00
Ctrl(Right) 1DE0
Ctrl(Left) 1D00
Esc 0100
NumLock 4500
ScrollLock 4600
Win(Right) 5CE0
Win(Left) 5BE0

他のキーのコードは参考サイト二つ目に書かれている

ここではあえて実際に入力する際の値を表しているので

キーコードと言うと語弊がある

そこは適時読み直していただけたらと(;・∀・)

 

そして最後にNULL埋め

これで完了

複数キーを変更するときの値が

いまいち理解しきれていない(末尾のNULLの数とか)ので

今は書かないでおく

今後わかれば書き足すなり、新たに記事を作るなりしよう

JavaでAPIが叩きたい

 

なんとなくJavaAPIが叩きたくなったのでその時のメモ

今回は素のJAVA(SE8)で組んでみたいと思う

 

使用するAPIはこちら↓

GitHub API v3 | GitHub Developer Guide

これで自分のGist一覧を取得するためのAPIを叩いてみる

叩くだけであってそれで得られたJSONの処理はしない

何故ならできないからだ(`・∀・´)エッヘン!!

 

まずはコード

import java.io.*;
import java.net.URL;

public class GithubApi {
private static final String API_URL = "https://api.github.com/users/[UserID]/gists"; //叩くAPI private static URL url = null; private static BufferedReader br = null; private static InputStreamReader isr = null; public static void main ( String[] args ) { try { System.out.println( conectGetJson() ); } catch ( Exception e ) { e.printStackTrace(); } }
/* 実際にAPIを叩いて得たJSONを文字列として返す
適当に組んでいるのでエラーは投げてます
当然のことながら実際に実装する際は各自で適切な処理を*/ public static String conectGetJson() throws Exception { url = new URL( API_URL ); String readLine = ""; String writeContent = "";
/* ここから読み込むための定型文 */ isr = new InputStreamReader( url.openStream() ); br = new BufferedReader( isr ); while ( ( readLine = br.readLine() ) != null ) writeContent = writeContent + readLine;//ここで読み込んだ内容を変数に保存している return writeContent; } }

こんな感じですね

相も変わらず読みにくいコード(汗)

コメントの通り、実装の際は適切なエラー処理をお願いしますm(__)m

 

組んでから気付いたのですが

普通にJavaでHTMLやら読み込むときとまったく同じですね

結局やってることは同じということでしょうか

あえて今回は「APIを叩く」ということに焦点を置きました

 

本当はJSONのパースまでできたらいいんですけどね

面倒くさそうなので現段階では手を付けていません

Androidだと標準APIでできるんですけどねぇ

楽そうなパースの方法がありましたらコメントしてもらえば嬉しいです