C Programm aufteilen und schöner machen - aber wie?



  • Hallo,
    ich bin ein relativer C neuling und habe dieses Programm [1] (ist zu groß für das Forum) geschrieben.
    Leider ist es nicht sehr schön und ich wollte fragen wie man es schöner machen kann. Ich denke, dass es besser ist gleich am Anfang zu lernen wie man schön programmiert bevor sich zuviel festsetzt was man später nicht mehr wegbekommt.
    Ich habe gelesen, dass man externe Variablen wenn möglich nicht verwenden soll. Ich bekomme es leider ohnen nicht auf die Reihe. Beim unterteilen in kleinere Progrämmchen habe ich auch ein paar schwierigkeiten. Macht man möglichst viele kleinere oder dann doch nur ein paar? Unterteilt man die .h Dateien dann auch noch mal?

    Es ist zwar ein Linux Programm, aber es geht hauptsächlich um ANSI C, deswegen habe ich es hier gepostet. Bitte bedenkt dass es unter der GPL steht(verwendet Teile von GPL Programmen) und ihr damit einverstanden seit wenn ihr es verbessert. Natürlich kommt euer Name dazu!
    Falls es jemand ausprobieren will benötigt er Kernel 2.6 mit geladenen evdev uinput kbd und root Rechte.

    Vielen Dank schon mal!
    nice

    1 http://pastebin.ca/84050



  • diese 'number2key' funktion würd' ich irgendwie tabellengesteuert machen. dann wird sie viel kürzer...



  • Ich weiß, das hat nix mit deiner Frage zu tun, aber denk doch bitte an die dritte Person -s im 1. Satz deines Anfangskommentars... This program has no name at the moment 🙄



  • Danke für die schnellen Antworten
    net:
    Tabellengesteuert? Hast du ein Beispiel dafür wo man sieht was das ist?

    Niklas Cathor:
    Ich werde es verbessern Danke!



  • nice schrieb:

    net:
    Tabellengesteuert? Hast du ein Beispiel dafür wo man sieht was das ist?

    Mal ein kleiner Denkanstoss:

    int table[10][10];
    table['7'-'0']['9'-'0'] = KEY_A;
    

    Klickt's?



  • 😕 Heul, ich bin zu dumm.
    Wie frage ich das dann ab? Und wie soll ich das mit den Shift sachen machen?



  • Da wird dann praktisch gar nichts mehr abgefragt.

    key_press(table[key_1-'0'][key_2-'0']);
    key_release(table[key_1-'0'][key_2-'0']);
    

    Und die SHIFT-Dingers hab ich erstmal übersehen. Ist aber auch kein Problem´: Einfach eine Struktur definieren:

    struct myKey{
        int keycode; // da kommt der Keycode rein: z.B. KEY_1
        int isShift; // da kommt 1 rein wenn KEY_LEFTSHIFT benötigt wird
    }
    

    Jetzt selber weiterdenken 😉



  • aus:

    void number2key(char key_1,char key_2)
    {
        if ((key_1 == '7') && (key_2 == '9')) 
        {   
            key_press(KEY_A);
            key_release(KEY_A);
            check_special_keys();
        }
        else if ((key_1 == '9') && (key_2 == '7')) 
        {
            //generate _
            key_press(KEY_LEFTSHIFT);
            key_press(KEY_MINUS);
            key_release(KEY_MINUS);
            key_release(KEY_LEFTSHIFT);
            check_special_keys();
        }
        else if ((key_1 == '2') && (key_2 == '9')) 
        {
            key_press(KEY_B);
            key_release(KEY_B);
            check_special_keys();
        }
        ...
        ...
        ...
    

    mach:

    struct keytableentry
    {
       char key1;
       char key2;
       unsigned int presses;
       unsigned int constants[MAX_CONSTANTS];
    };
    
    struct keytableentry keytable[] =
    {
       {7, 5, 2, KEY_A, KEY_A},
       {9, 7, 4, KEY_LEFTSHIFT, KEY_MINUS, KEY_MINUS, KEY_LEFTSHIFT},
       {2, 9, 2, KEY_B, KEY_B},
       ...
       ...
       ...
    };
    
    void number2key (char key_1,char key_2)
    {
       unsigned int s;
       unsigned int l;
    
       for (s=0; s<sizeof(keytable)/sizeof(struct keytableentry); s++)
       {
          if (keytable[s].key1 == key_1 && keytable[s].key2 == key_2)
          {
             for (l=0; l<keytable[s].presses; l++)
                key_press (keytable[s].constants[l]);
             check_special_keys();
             return;
          }
       }   
    }
    

    edit: ein 'return' eingefügt



  • Neben den vorgeschlagenen Verbesserungen ist dein Problem auch die Länge des Quelltextes, oder? Da gibt es die Möglichkeit, diesen zu "Modularisieren", d.h. logisch zusammenhengende Teile in .h- und .c-files auszulagern. Dafür gibt's ein paar Regeln, an die man sich halten sollte, um nicht schiffbruch zu erleiden. Ich gebe hier mal ein Beispiel für eine Funktion:

    /* main.c */
    
    #include "modul1.h"
    
    int main()
    {
        function();  /* Ausgelagert in Modul1! */
        return 0;
    }
    
    /* modul1.h */
    
    #ifndef _MODUL1_H    /* Sog. "include-guard" */
      #define _MODUL1_H
    
      void function(void);  /* Prototyp */
    
    #endif
    
    /* modul1.c */
    
    #include "modul1.h"
    
    void function(void)  /* Definition */
    {
        23 + 42;
        return;
    }
    

    Somit ist "modul1.h" und "modul1.c" als eigenständiges Modul zu betrachten, das jetzt auch problemlos in andere Programme eingebunden werden kann. Die Frage, ob und wie man modularisiert, sollte erfahrungsgemäß davon abhängen, ob man sein Programm wirklich in logische Teile (-> Module) unterteilen kann. Es macht keinen Sinn, alles irgendwie zusammenzuwürfeln, das erschwert die Lesbarkeit um ein vielfaches und in diesem Fall wäre durch die Modularisierung auch nichts gewonnen.



  • Danke euch schon mal, ich werde die Dinge mal umsetzen und dann den neuen Source posten.

    Ist das mit den externen Variablen OK?



  • hallo,
    es ist schon ewig her, aber ich habe es nun geschafft und das Programm umgeändert. Jegliche Kritik ist gere Willkommen :). Es soll ja schließlich besser werden. Vorallem bei dem was alles in das Header File gehört und was nicht war ich mir nicht so sicher. Braucht jede Funktion einen Prototyp oder nur die, welche später von einem anderem Teil aufgerufen wird?

    Hier ist die neue Version:

    /* main.c
     * "Thumb to keys" lets you use the buttons of your PDA for fast writing.
     * First of all it translates the keypad direction into numbers
     * "up + left" is one, "up" is two, "up + right" is tree and so on. After that
     * it will allways look after combinations of two numbers to generate a key.
     * the definition of the keys is on thumbscript.com or you can read the keytable
     * struct.
     * 
     * It is able to switch the behaviour of the buttons. If you are pressing the 
     * combination "9 4" in thumscript mode (the default mode on startup) you will
     * get into the normal mode. You than can use your buttons as usual. If you 
     * want to get into the thumbscript mode you will need to press 
     * enter 5 times.
     *
     * Later there will be more possible keytables for your convenience.
     * 
     * Use gcc -o thumb2keys keyevents_2_uinput.c \
     * number_2_keyevents.c evdev_2_nubers.c main.c
     * to compile it.
     *
     * You need to have uinput and evdev loaded or compiled in your kernel!
     *
     * Have fun!
     *
     * Some parts of this program are based on esekeyd, uinput_mouse.c and kbdd 
     * which are all licenced under GPL.
     * 
     * This Code is licenced under GPL v2.
     *
     *
    */
    
    #include "thumbkeys.h"
    
    int main(){
        // set keytable to thumbscript table
        used_keytable=1;
        // initialization of evdev and uinput
        dev_event_init();
        dev_uinput_init();
        // start the translation
        beginn_translation();
        // close uinput and evdev
        close(fp_uinput);
        close(fp_event);
    }
    
    /* evdev_2_nubers.c
     * Evdev 2 numbers. This part of the programm will read out the evdev and
     * translate it to numbers (see main.c for explanation).
     *
     * At this state of the development you need to set the evdev path
     * yourself at thumbkeys.h. 
     *
     * This code is licenced under GPL v2.
     *
    */
    
    #include <fcntl.h>
    #include <stdio.h>
    
    #include "thumbkeys.h"
    
    struct input_event ev;
    struct keybuffer {
        char up;
        char down;
        char left;
        char right;
        char enter;
    }; 
    struct keybuffer kbuffer = { 0,0,0,0,0 };
    int numbers[2] = {0,0};
    int fp_event = 0;
    int count_enter = 0;
    
    int dev_event_init(void){
    	if (!(fp_event = open(EV_FILE, O_RDONLY))) {
    		perror("failed to open event device");
    		return -1;
    	}
        if ((ioctl(fp_event, EVIOCGRAB,1)) == -1) {
    		perror("failed to grab the device");
    		return -1;
    	}
    }
    
    void clear_kbuffer(void){
        kbuffer.up = 0;
        kbuffer.down = 0;
        kbuffer.left = 0;
        kbuffer.right = 0;
        kbuffer.enter = 0;
    }
    
    int key_to_number(struct input_event ev) {
        if (ev.value == 1) {
            switch (ev.code) {
                case KEY_UP:
                    kbuffer.up=1;
                    break;
                case KEY_DOWN:
                    kbuffer.down=1;
                    break;
                case KEY_LEFT:
                    kbuffer.left=1;
                    break;
                case KEY_RIGHT:
                    kbuffer.right=1;
                    break;
                case KEY_ENTER:
                    kbuffer.enter=1;
                    break;
            }
        }
        if (ev.value == 0) {
            if ( (kbuffer.up ==1) && (kbuffer.down ==0) && (kbuffer.left ==1) && (kbuffer.right ==0) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 1;
            }
            if ( (kbuffer.up ==1) && (kbuffer.down ==0) && (kbuffer.left ==0) && (kbuffer.right ==0) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 2;
            }
            if ( (kbuffer.up ==1) && (kbuffer.down ==0) && (kbuffer.left ==0) && (kbuffer.right ==1) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 3;
            }
            if ( (kbuffer.up ==0) && (kbuffer.down ==0) && (kbuffer.left ==1) && (kbuffer.right ==0) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 4;
            }
            if ( (kbuffer.up ==1) && (kbuffer.down ==1) && (kbuffer.left ==1) && (kbuffer.right ==1) || (kbuffer.enter ==1) ) {
                clear_kbuffer();
                return 5;
            }
            if ( (kbuffer.up ==0) && (kbuffer.down ==0) && (kbuffer.left ==0) && (kbuffer.right ==1) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 6;
            }
            if ( (kbuffer.up ==0) && (kbuffer.down ==1) && (kbuffer.left ==1) && (kbuffer.right ==0) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 7;
            }
            if ( (kbuffer.up ==0) && (kbuffer.down ==1) && (kbuffer.left ==0) && (kbuffer.right ==0) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 8;
            }
            if ( (kbuffer.up ==0) && (kbuffer.down ==1) && (kbuffer.left ==0) && (kbuffer.right ==1) && (kbuffer.enter ==0) ) {
                clear_kbuffer();
                return 9;
            }
        }
    
        return 0;
    }
    
    void check_enter(struct input_event ev){
        if ((ev.value == KEY_RELEASE) && (ev.code == KEY_ENTER)){
            if (count_enter++ >=5){
                used_keytable = 1;
                count_enter = 0;
            }
        }
        if ((ev.value == KEY_RELEASE) && (ev.code != KEY_ENTER))
            count_enter = 0;
    }
    
    void key_2_key(struct input_event ev){
        if (ev.value == KEY_PRESS)
            key_press(ev.code);
        if (ev.value == KEY_RELEASE)
            key_release(ev.code);
        if (ev.value == KEY_REPEAT)
            key_autorepeat(ev.code);
    }
    
    void beginn_translation(void) {
        int number = 0;
        int i = 0;
        while (read (fp_event,&ev, sizeof (struct input_event))) {
            if (ev.type == EV_KEY) {
                check_enter(ev);
                if (used_keytable == 0)
                    key_2_key(ev);
                else {
                    number = key_to_number(ev);
                    if (number != 0) {
                        switch (i) {
                            case 0:
                                numbers[i] = number;
                                i++;
                                break;
                                case 1:
                                numbers[i] = number;
                                i=0;
                                numbers_to_keyevents(numbers[0],numbers[1]);
                                break;                
                        }
                    }
                }
            }
        }   
    }
    
    /* number_2_keyevents.c
     * This is the number 2 keyevents part. 
     * You can easily extend it or change the key-combinations.
     * Moreover it is planned to provide more keytables.
     * The key-combinations are similar to the ones of thumbscript.com with some
     * changes.
     *
     * This Code is licenced under GPL v2.
     *
    */
    
    #include <linux/input.h>
    #include <stdio.h>
    
    #include "thumbkeys.h"
    
    int switch_table(int a){
        /*
        * This part is expandable. It is planed to offer more than
        * one key-definition table. For that purpose we will save the table-number
        * in the value of key_shifter.
        */
        switch (a) {
            case 0: used_keytable=0;
        }
    }
    
    int numbers_to_keyevents(int a, int b) {    
        static int combo_key_counter;
        static int combo_key_code[10];
    
        struct keycodes {
            int keycode;
            int key_shifter;
            int special;
        };
        struct keycodes keytable[9][9] =
        {   
            {{KEY_LEFTCTRL,0,1},{KEY_V,0,0},{KEY_W,0,0},{KEY_P,0,0},{KEY_1,0,0},{KEY_Q,0,0},{KEY_X,0,0},{KEY_Y,0,0},{KEY_U,0,0}},
            {{0,0,0},{KEY_LEFTSHIFT,0,1},{KEY_K,0,0},{KEY_J,0,0},{KEY_2,0,0},{KEY_L,0,0},{KEY_D,0,0},{KEY_I,0,0},{KEY_B,0,0}},
            {{KEY_APOSTROPHE,KEY_LEFTSHIFT,0},{KEY_APOSTROPHE,0,0},{KEY_BACKSPACE,0,0},{3,0,0},{KEY_3,0,0},{KEY_G,0,0},{KEY_E,0,0},{KEY_F,0,0},{KEY_C,0,0}},
            {{KEY_DOT,KEY_LEFTSHIFT,0},{KEY_EQUAL,0,0},{0,0,0},{KEY_TAB,0,0},{KEY_4,0,0},{KEY_O,0,0},{KEY_Z,0,0},{KEY_N,0,0},{KEY_H,0,0}},
            {{KEY_1,KEY_LEFTSHIFT,0},{KEY_2,KEY_LEFTSHIFT,0},{KEY_3,KEY_LEFTSHIFT,0},{KEY_4,KEY_LEFTSHIFT,0},{KEY_5,0,0},{KEY_6,KEY_LEFTSHIFT,0},{KEY_7,KEY_LEFTSHIFT,0},{KEY_8,KEY_LEFTSHIFT,0},{KEY_5,KEY_LEFTSHIFT,0}},
            {{KEY_ESC,0,0},{KEY_EQUAL,KEY_LEFTSHIFT,0},{KEY_COMMA,KEY_LEFTSHIFT,0},{KEY_0,0,0},{KEY_6,0,0},{KEY_ENTER,0,0},{0,0,0},{KEY_T,0,0},{KEY_S,0,0}},
            {{KEY_0,KEY_LEFTSHIFT,0},{KEY_SLASH,KEY_LEFTSHIFT,0},{KEY_SLASH,0,0},{KEY_SEMICOLON,0,0},{KEY_7,0,0},{0,0,0},{KEY_COMMA,0,0},{KEY_M,0,0},{KEY_A,0,0}},
            {{KEY_RIGHTBRACE,0,0},{KEY_BACKSLASH,KEY_LEFTSHIFT,0},{KEY_LEFTBRACE,0,0},{KEY_RIGHTBRACE,KEY_LEFTSHIFT,0},{KEY_8,0,0},{KEY_LEFTBRACE,KEY_LEFTSHIFT,0},{KEY_GRAVE,KEY_LEFTSHIFT,0},{KEY_SPACE,0,0},{KEY_R,0,0}},
            {{KEY_BACKSLASH,0,0},{0,0,0},{KEY_9,KEY_LEFTSHIFT,0},{99999,0,0},{KEY_9,0,0},{KEY_SEMICOLON,KEY_LEFTSHIFT,0},{KEY_MINUS,KEY_LEFTSHIFT,0},{KEY_MINUS,0,0},{KEY_DOT,0,0}}
        };
    
        /* We need to decrease the input values about one. This is because we get
         * numbers from 1 to 9. We will also check that we get only those values
        */
    
        if (((a >0) && (a<10)) && ((b >0) && (b<10))) {
            a--;  
            b--;
            if (keytable[a][b].keycode !=0) { //Get rid of not defined combinations   
            /*
             * If the keycode is 99999 we switch the keytable. I decided to use this 
             * because it is not defined. If I am wrong change it here and in the
             * struct to some not defined value in input.h.
            */
                if(keytable[a][b].keycode == 99999)
                    switch_table(keytable[a][b].key_shifter);
                else if (keytable[a][b].keycode !=0) {
                    if (combo_key_counter !=0) {
                        if (keytable[a][b].key_shifter !=0) {
                            key_press(keytable[a][b].keycode);
                            combo_key_counter++;
                            combo_key_code[combo_key_counter]=keytable[a][b].keycode;
                        }
                        else if (keytable[a][b].key_shifter ==0) {
                            key_press(keytable[a][b].key_shifter);
                            key_press(keytable[a][b].keycode);
                            combo_key_code[combo_key_counter]=keytable[a][b].keycode;
                            combo_key_counter++;
                            combo_key_code[combo_key_counter]=keytable[a][b].key_shifter;
                            combo_key_counter++;
                        }        
                        if (keytable[a][b].special!=1) {
                            combo_key_counter--;
                            while (combo_key_counter!=0) {
                                key_release(combo_key_code[combo_key_counter]);
                                combo_key_counter--;
                            }
                        }
                    }
                    else if (combo_key_counter==0) {
                        if (keytable[a][b].special==1) {
                            if (keytable[a][b].key_shifter !=0) {
                                key_press(keytable[a][b].key_shifter);
                                key_press(keytable[a][b].keycode);
                                combo_key_code[combo_key_counter]=keytable[a][b].keycode;
                                combo_key_counter++;
                                combo_key_code[combo_key_counter]=keytable[a][b].key_shifter;
                                combo_key_counter++;
                            }
                            else if (keytable[a][b].key_shifter ==0) {
                                key_press(keytable[a][b].keycode);
                                combo_key_code[combo_key_counter]=keytable[a][b].keycode;
                                combo_key_counter++;
                            }
                        }
                        else if (keytable[a][b].special==0){ 
                            if (keytable[a][b].key_shifter !=0) {
                                key_press(keytable[a][b].key_shifter);
                                key_press(keytable[a][b].keycode);
                                key_release(keytable[a][b].keycode);
                                key_release(keytable[a][b].key_shifter);
                            }
                            else if (keytable[a][b].key_shifter ==0){
                                key_press(keytable[a][b].keycode);
                                key_release(keytable[a][b].keycode);
                            }
                        }
                    }
                }
            }
        }
    }
    
    /* keyevents_2_uinput.c
     * Keyevents to uinput. This part creates a virtual keyboard for passing the
     * keycodes to the input device.
     *
     * This Code is licenced under GPL v2.
     *
     *
    */
    
    #include <linux/input.h>
    #include <linux/uinput.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    #include "thumbkeys.h"
    
    int dev_uinput_init(void) {
        struct uinput_user_dev dev;
        int aux;
    
    	fp_uinput = open("/dev/uinput", O_RDWR);
    	if (fp_uinput <= 0)
    		fp_uinput = open("/dev/misc/uinput", O_RDWR);
    	if (fp_uinput <= 0)
    		fp_uinput = open("/dev/devfs/misc/uinput", O_RDWR);
    	if (fp_uinput <= 0)
    		fp_uinput = open("/dev/input/uinput", O_RDWR);
    	if (fp_uinput <= 0) {
    		perror("failed to open the uinput device");
    		return -1;
    	}
    
    	memset(&dev, 0, sizeof(dev));
    	strncpy(dev.name, "Thumbscript", UINPUT_MAX_NAME_SIZE);
    
    	if (write(fp_uinput, &dev, sizeof(dev)) < 0) {
    		fprintf(stderr,"failed to write uinputdev");
    		close(fp_uinput);
    		return -1;
    	}
    
    	if (ioctl(fp_uinput, UI_SET_EVBIT, EV_KEY) != 0) {
    		close(fp_uinput);
    		return -1;
    	}
    	if (ioctl(fp_uinput, UI_SET_EVBIT, EV_REP) != 0) {
    		close(fp_uinput);
    		return -1;
    	}
    	for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++)
    		if (ioctl(fp_uinput, UI_SET_KEYBIT, aux) != 0) {
    			close(fp_uinput);
    			return -1;
    		}
    	if (ioctl(fp_uinput, UI_DEV_CREATE) != 0) {
    		close(fp_uinput);
    		return -1;
    	}
    }
    
    void key_press(int code){
        struct input_event event;
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = code;
        event.value = KEY_PRESS;
        write(fp_uinput, &event, sizeof(event));
    } 
    
    void key_release(int code){
        struct input_event event;
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = code;
        event.value = KEY_RELEASE;
        write(fp_uinput, &event, sizeof(event));
    } 
    
    void key_autorepeat(int code){
        struct input_event event;
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = code;
        event.value = KEY_REPEAT;
        write(fp_uinput, &event, sizeof(event));
    }
    
    /*
     * Header file
     *
     * This Code is licenced under GPL v2.
     *
    */
    #include <linux/input.h>
    #include <sys/types.h>
    
    int used_keytable;
    
    // Definitions for number_2_keyevents.c
    int switch_table(int a);
    int numbers_to_keyevents(int a, int b);
    static int combo_key_counter=0;
    static int combo_key_code[10] = {0,0,0,0,0,0,0,0,0,0};
    
    // Definitions for keyevents_2_uinput.c
    #define KEY_PRESS   1
    #define KEY_RELEASE 0
    #define KEY_REPEAT  2
    
    void key_press(int code);
    void key_release(int code);
    void key_autorepeat(int code);
    int dev_uinput_init(void);
    int dev_uinput_init(void);
    
    int fp_uinput;
    // Definitions for evdev_2_numbers
    
    #define EV_FILE  "/dev/input/event0"
    
    void clear_kbuffer(void);
    void beginn_translation(void);
    void check_enter(struct input_event ev);
    void key_2_key(struct input_event ev);
    int key_to_number(struct input_event ev);
    int dev_event_init(void);
    
    int fp_event;
    

    Vielen Dank für das Lesen.
    nice


Anmelden zum Antworten