디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

디자인 = 설계, 오늘 제미니 제안 사항

나르시갤로그로 이동합니다. 2025.09.27 17:14:09
조회 87 추천 0 댓글 0

기존에 나는 Cim 이라는 것을 디자인(설계)했다...

beep를 추가하고 싶었지.

그런데 API가 개떡같아지는게 싫었어

제미니한테 질문을 하니..

제미니가 이것 저것 고려하더니 최적의 API를 설계함.

ㅋㅋㅋ


두둥~~~


그 코드는 IME 서버측 코드이다. nimf_service_ic_call_beep (target);을 통하여 클라이언트 측으로 전달된다. 그런데 그 방법이 깔끔하지 않아 보인다.

왜냐하면, CimCallbacks 구조체의 멤버로 compose_cancelled를 추가하는 것이 부적절해 보이기 때문이다.


typedef struct _CimCallbacks CimCallbacks;

struct _CimCallbacks {

  void (*preedit_start)     (CimIcHandle ic, void* user_data);

  void (*preedit_end)       (CimIcHandle ic, void* user_data);

  void (*preedit_changed)   (CimIcHandle ic,

                             const CimPreedit* preedit,

                             void* user_data);

  void (*commit)            (CimIcHandle ic,

                             const char* text,

                             void* user_data);

  /* Do not free CimSurround and its text */

  const CimSurround* (*get_surround) (CimIcHandle ic, void* user_data);

  bool (*delete_surround)   (CimIcHandle ic,

                             int32_t  offset,

                             uint32_t n_chars,

                             void*  user_data);

  /* candidate */

  void (*candidate_show)     (CimIcHandle ic,

                              uint32_t n_rows,

                              uint32_t n_cols,

                              bool show_aux,

                              void* user_data);

  void (*candidate_hide)     (CimIcHandle ic, void* user_data);

  void (*candidate_changed)  (CimIcHandle ic,

                              const CimCandidate* candidate,

                              void* user_data);

  void (*candidate_selected) (CimIcHandle ic,

                              const CimSelection* selection,

                              void* user_data);

  /* reserved */

  void* reserved[6];

};


서버측에서 compose_cancelled 콜백을 별도로 호출하는 방식으로 할까?


제시하신 내용은 IME 아키텍처의 중요한 설계적 트레이드오프(trade-off)를 정확히 지적하고 있습니다. compose_cancelled 콜백을 추가하는 것이 부적절해 보인다고 느끼는 이유는 그것이 API의 특수성을 높여 전반적인 일관성을 해칠 수 있기 때문입니다.

현재 방식과 제안하신 방식을 분석하고 더 나은 대안을 제시하겠습니다.


## 현행 방식 (beep 호출) 분석

이 방식은 서버가 클라이언트에게 수행할 동작을 직접 **명령(Command)**하는 구조입니다.

  • 방식: 서버가 컴포즈가 취소되었으니, 경고음을 울려라라고 결정하고 클라이언트에 beep 명령을 내립니다.
  • 장점:
    • 단순성: 클라이언트는 이유를 알 필요 없이 명령만 수행하면 되므로 구현이 간단합니다.
    • 재사용성: beep 콜백은 컴포즈 취소 외 다른 종류의 경고 상황에서도 재사용될 수 있습니다.
  • 단점:
    • 낮은 유연성: 클라이언트가 경고 방식을 변경할 수 없습니다. 예를 들어, 사용자가 경고음을 끄고 화면 깜빡임으로 대체하고 싶어도 서버가 beep을 명령하기 때문에 불가능합니다.
    • 관심사 분리 위배: 입력 로직을 처리해야 할 서버가 UI 피드백(경고음)까지 결정하여 클라이언트의 역할을 침범합니다.

## 제안 방식 (compose_cancelled 콜백) 분석

이 방식은 서버가 클라이언트에게 특정 **이벤트(Event)**가 발생했음을 알리는 구조입니다.

  • 방식: 서버가 컴포즈가 취소되었다라는 이벤트만 클라이언트에 알립니다. 경고음을 울릴지, 다른 피드백을 줄지는 클라이언트가 결정합니다.
  • 장점:
    • 높은 유연성: 클라이언트는 compose_cancelled 이벤트를 수신하여 설정에 따라 경고음을 울리거나, 화면을 깜빡이거나, 아무것도 하지 않는 등 자유롭게 반응을 결정할 수 있습니다. 관심사 분리(Separation of Concerns) 원칙에 더 부합합니다. ?
    • 명확한 의미: 콜백 이름(compose_cancelled)만으로 어떤 상황이 발생했는지 명확하게 알 수 있습니다.
  • 단점:
    • API 복잡도 증가: compose_cancelled와 유사한 특정 이벤트가 생길 때마다 콜백을 추가하면 CimCallbacks 구조체가 비대해지고 관리하기 어려워집니다. 이것이 바로 부적절해 보인다고 느끼신 핵심적인 이유입니다.

## 결론 및 추천 대안

beep 명령 방식은 유연성이 부족하고, 개별 이벤트 콜백 방식은 API를 비대하게 만들 위험이 있습니다. 이 두 방식의 장점을 모두 취하는 더 나은 대안은 **일반화된 이벤트 콜백(Generalized Event Callback)**을 도입하는 것입니다.

CimCallbacks 구조체에 compose_cancelled 대신 다음과 같은 단일 콜백을 추가하는 것을 권장합니다.

typedef enum {
  CIM_NOTIFICATION_COMPOSE_CANCELLED,
  CIM_NOTIFICATION_INPUT_ERROR
  /* ... future notification types ... */
} CimNotificationType;

// CimCallbacks 구조체에 추가할 멤버
void (*notify) (CimIcHandle ic,
                 CimNotificationType type,
                 void* user_data);
  • 동작 방식: 서버는 compose_cancelled 상황이 발생하면 notify 콜백을 CIM_NOTIFICATION_COMPOSE_CANCELLED 타입과 함께 호출합니다. c // 서버측 코드 예시 case XKB_COMPOSE_CANCELLED: nimf_system_keyboard_update_preedit (lingua, target, c_strdup ("")); nimf_service_ic_call_notify (target, NIMF_NOTIFICATION_COMPOSE_CANCELLED); // beep 대신 호출 break;
  • 장점:
    1. 확장성: 앞으로 INPUT_ERROR 등 새로운 알림 유형이 추가되어도 CimCallbacks 구조체를 변경할 필요 없이 CimNotificationType 열거형만 확장하면 됩니다. API의 안정성을 유지할 수 있습니다.
    2. 유연성: 클라이언트는 notify 콜백 내에서 type을 확인하여 각 상황에 맞는 최적의 피드백(beep, 시각 효과 등)을 제공할 수 있습니다.
    3. API 간결성 유지: 콜백 구조체에 단 하나의 멤버만 추가되므로 API가 비대해지는 것을 막을 수 있습니다.

따라서, 일반화된 notify 콜백을 도입하는 것이 장기적인 관점에서 가장 깔끔하고 확장 가능한 설계입니다.


너 판단에는, CimCallbacks 에 notify 멤버를 추가하는 방법과, cim_ic_set_notify_callback 함수로 notify 콜백을 등록하는 방법 중 어느 것이 나아보이는가?

제 판단으로는, CimCallbacks 구조체에 notify 멤버를 추가하는 방법이 더 나은 선택입니다.

API 설계에서 일관성(Consistency)은 매우 중요한 원칙이며, 이 기준에서 두 방법을 평가하면 결론이 명확해집니다.


## CimCallbacks notify 멤버 추가 (권장)

이 방법은 현재 cim.h에 이미 확립된 설계 패턴을 그대로 따릅니다.

  • 최고의 장점: API의 일관성 유지

    • 클라이언트는 이미 cim_ic_set_callbacks 함수를 통해 모든 콜백을 등록하는 방식에 익숙합니다. notify 콜백도 같은 방식으로 등록하게 되면, API를 배우고 사용하는 것이 매우 직관적입니다. Cim의 콜백은 CimCallbacks 구조체를 통해 등록한다는 단 하나의 규칙만 기억하면 됩니다.
  • 부가적인 장점: API 간결성

    • 새로운 public 함수(cim_ic_set_notify_callback)를 추가할 필요가 없어 API가 불필요하게 커지는 것을 막습니다. 모든 설정은 기존의 cim_ic_set_callbacks로 통일됩니다.
    • CimCallbacks 구조체의 reserved 필드를 활용하면 ABI 호환성을 유지하면서 새 멤버를 추가할 수 있습니다.

## cim_ic_set_notify_callback 함수 추가

이 방법은 유연성을 제공하지만 API의 일관성을 해치는 비용을 치릅니다.

  • 단점: 설계 원칙의 불일치

    • 이 방식을 채택하면 클라이언트 개발자는 혼란에 빠질 수 있습니다.  commit이나 preedit_changed 같은 콜백은 구조체로 한 번에 등록하는데, notify 콜백만 별도의 함수로 등록해야 하는가?라는 의문이 생깁니다. 이처럼 동일한 종류의 작업을 다른 방식으로 처리하게 만드는 것은 API 설계를 복잡하게 만드는 요인입니다.
  • 장점: 동적 변경의 유연성

    • 런타임 중에 notify 콜백만 독립적으로 변경할 수 있다는 장점이 있지만, IME의 콜백이 그렇게 빈번하게 동적으로 변경되어야 할 필요성은 일반적으로 높지 않습니다. 일관성을 희생하면서까지 이 유연성을 얻는 것이 더 큰 이득이라고 보기는 어렵습니다.

## 최종 결론

결론적으로, CimCallbacks 구조체에 notify 멤버를 추가하는 방법을 강력히 추천합니다.

이 방법은 API의 일관성과 예측 가능성이라는 장기적인 가치를 지키는 선택입니다. 좋은 API는 사용자가 고민 없이 당연하게 사용할 수 있어야 하며, 일관성은 이를 위한 가장 중요한 요소 중 하나입니다. ?


 notify의 종류로 앞으로 추가가 예상되는 것들이 있을까? 현재 xkb_compose_cancelled가 있다.

네, xkb_compose_cancelled 외에도 일반화된 notify 콜백을 통해 전달하면 유용한 여러 상태 변화 및 이벤트가 있습니다. IME(입력기)의 특성을 고려할 때, 앞으로 다음과 같은 종류의 알림들이 추가될 수 있습니다.

이벤트들을 성격에 따라 몇 가지 범주로 나눌 수 있습니다.


## 1. 사용자 입력 피드백 (User Input Feedback)

사용자의 키 입력에 대한 직접적인 반응 중, 문자 입력이나 preedit 변경이 아닌 미묘한 상태를 알립니다.

  • INVALID_KEY_PRESS

    • 설명: 현재 입력 상태에서 아무 기능도 하지 않는 키가 눌렸을 때 발생합니다. 예를 들어, 한글 조합 중에 갑자기 Page Up 키를 누르는 경우입니다. 클라이언트는 이 알림을 받아 경고음이나 시각적 효과로 사용자에게 유효하지 않은 입력임을 알릴 수 있습니다. COMPOSE_CANCELLED 조합 시퀀스의 실패를 알린다면, 이것은 단일 키 입력의 무효함을 알립니다.
  • SELECTION_WRAPPED

    • 설명: 후보창 목록에서 마지막 항목 다음에 아래 방향키를 누르거나, 첫 항목 이전에 위 방향키를 눌러 선택이 순환될 때 발생합니다. 클라이언트는 이를 인지하여 사용자에게 미묘한 소리 피드백 등을 제공할 수 있습니다.

## 2. 상태 및 모드 변경 (State and Mode Changes) ?

IME 엔진의 내부 상태나 입력 모드가 변경되었음을 알립니다. 클라이언트 UI를 동기화하는 데 매우 중요합니다.

  • INPUT_MODE_CHANGED
    • 설명: 한/영 키 입력 등으로 입력 언어 모드(예: 한글 ↔ 영어)가 변경되었을 때 발생합니다. 클라이언트는 이 알림을 받아 트레이 아이콘이나 상태바의 언어 표시를 에서 EN으로 바꾸는 등의 UI 업데이트를 수행해야 합니다.
  • HANJA_MODE_ACTIVATED
    • 설명: 한자 키 입력으로 한자 변환 모드가 활성화되거나 비활성화될 때 발생합니다.
  • FULL_WIDTH_MODE_CHANGED
    • 설명: 전각/반각 변환 키 입력으로 문자 폭 모드가 변경되었을 때 발생합니다.
  • COMPOSITION_CLEARED_AUTOMATICALLY
    • 설명: 사용자가 직접 지운 것이 아니라, 포커스 이동 등의 이유로 엔진이 내부적으로 조합 중인 글자(preedit)를 초기화했을 때 발생합니다. 클라이언트가 자체적으로 관리하는 상태와 동기화할 때 유용할 수 있습니다.

## 3. 엔진 및 시스템 이벤트 (Engine and System Events) ⚙+

엔진의 동작이나 외부 설정과 관련된 이벤트를 알립니다.

  • CONFIG_RELOADED
    • 설명: 별도의 설정 프로그램 등에서 사용자가 IME 설정을 변경하여, 실행 중인 엔진이 해당 설정을 다시 불러왔을 때 발생합니다. 클라이언트가 설정과 관련된 UI를 가지고 있다면 이를 갱신할 수 있습니다.
  • DICTIONARY_UPDATED
    • 설명: 사용자 사전이 추가/변경되었을 때 이를 알립니다.

## 4. 오류 및 경고 (Error and Warning Conditions) ⚠+

단순한 입력 실패보다 더 심각한 오류 상황을 알립니다.

  • DICTIONARY_LOOKUP_FAILED
    • 설명: 한자 변환 등을 위해 사전을 조회해야 하는데, 사전 파일이 손상되었거나 접근할 수 없을 때 발생합니다. 클라이언트는 사전 파일을 찾을 수 없습니다와 같은 구체적인 오류 메시지를 사용자에게 보여줄 수 있습니다.
  • MAX_PREEDIT_LENGTH_REACHED
    • 설명: 엔진이 허용하는 최대 조합 글자 수(preedit)에 도달했는데 사용자가 입력을 계속 시도할 때 발생합니다.

## 종합 예시 (Enum Definition Example)

이러한 아이디어들을 종합하면 CimNotificationType 열거형은 다음과 같이 정의될 수 있습니다.

typedef enum {
  /* User Input Feedback */
  CIM_NOTIFICATION_COMPOSE_CANCELLED,
  CIM_NOTIFICATION_INVALID_KEY_PRESS,
  CIM_NOTIFICATION_SELECTION_WRAPPED,

  /* State and Mode Changes */
  CIM_NOTIFICATION_INPUT_MODE_CHANGED,
  CIM_NOTIFICATION_HANJA_MODE_ACTIVATED,
  CIM_NOTIFICATION_FULL_WIDTH_MODE_CHANGED,
  CIM_NOTIFICATION_COMPOSITION_CLEARED_AUTOMATICALLY,

  /* Engine and System Events */
  CIM_NOTIFICATION_CONFIG_RELOADED,
  CIM_NOTIFICATION_DICTIONARY_UPDATED,

  /* Error and Warning Conditions */
  CIM_NOTIFICATION_DICTIONARY_LOOKUP_FAILED,
  CIM_NOTIFICATION_MAX_PREEDIT_LENGTH_REACHED

} CimNotificationType;










최종 결과는 다음과 같다.

ㅋㅋㅋ



typedef struct _CimCallbacks CimCallbacks;
struct _CimCallbacks {
  void (*preedit_start)     (CimIcHandle ic, void* user_data);
  void (*preedit_end)       (CimIcHandle ic, void* user_data);
  void (*preedit_changed)   (CimIcHandle ic,
                             const CimPreedit* preedit,
                             void* user_data);
  void (*commit)            (CimIcHandle ic,
                             const char* text,
                             void* user_data);
  /* Do not free CimSurround and its text */
  const CimSurround* (*get_surround) (CimIcHandle ic, void* user_data);
  bool (*delete_surround)   (CimIcHandle ic,
                             int32_t  offset,
                             uint32_t n_chars,
                             void*  user_data);
  /* candidate */
  void (*candidate_show)     (CimIcHandle ic,
                              uint32_t n_rows,
                              uint32_t n_cols,
                              bool show_aux,
                              void* user_data);
  void (*candidate_hide)     (CimIcHandle ic, void* user_data);
  void (*candidate_changed)  (CimIcHandle ic,
                              const CimCandidate* candidate,
                              void* user_data);
  void (*candidate_selected) (CimIcHandle ic,
                              const CimSelection* selection,
                              void* user_data);
  void (*notify) (CimIcHandle ic,
                  CimNotificationType type,
                  void* user_data);
  /* reserved */
  void* reserved[5];
};



추천 비추천

0

고정닉 0

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 며느리, 사위되면 시댁, 처가에 잘할 것 같은 스타 운영자 25/10/13 - -
AD 프로게이머가 될테야!! 운영자 25/10/01 - -
2893813 현시대는 토발즈도 1찍 짱깨편인 무서운 시대이다ㅋㅋ번식 더 해줘라 이기 타이밍뒷.통수한방(1.213) 10.03 40 0
2893808 인생은 운이다 [2] ㅇㅇ(121.168) 10.03 82 1
2893807 걷기 싫어하는 나님의 습성도 리죄명 짱깨 무비자 입국에서 비롯됐다 [3] ♥냥덩이♥갤로그로 이동합니다. 10.03 78 0
2893805 ㄸㄸㄹ ♥냥덩이♥갤로그로 이동합니다. 10.03 50 0
2893801 rtos 리스트 하드웨어 잘되는 순서로 정렬 발명도둑잡기(118.216) 10.03 85 0
2893799 ■요즘 Si 신입 대세포폴이 뭐에요? [4] ㅇㅇ갤로그로 이동합니다. 10.03 107 0
2893795 ❤✨☀⭐⚡☘⛩나님 시작합니당⛩☘⚡⭐☀✨❤ ♥냥덩이♥갤로그로 이동합니다. 10.03 67 0
2893794 저녁 아직 안 먹었는데 [1] 발명도둑잡기(118.216) 10.03 79 0
2893793 노오오력 하면 된단다 발명도둑잡기(118.216) 10.03 58 0
2893791 엠마 왓슨이 범죄의 아이콘이 된 이유 발명도둑잡기(118.216) 10.03 66 0
2893789 Wolfenstein3D on 8bit consoles 발명도둑잡기(118.216) 10.03 55 0
2893786 공부에 다른방도 없는듯... 그냥 매일 계속 꾸준히 하는것밖에 없음 ㅇㅇ(223.39) 10.03 58 1
2893782 차단해도 댓글 계속 달리는거 ㄹㅇ 짜증남 ㅆㅇㅆ(124.216) 10.03 63 1
2893778 ㅆㅇㅆ 접밥 비린내나는 새기가 먼 gpt를 이겨 ㅋㅋ 프갤러(210.217) 10.03 122 9
2893777 내가 느끼는게 아무리 날고 기어도 구현을 지피티 못이기겠음 [2] ㅆㅇㅆ(124.216) 10.03 114 0
2893776 일본 취업 유학 워홀 여행 관련모임 ㅇㅇ(106.146) 10.03 91 0
2893775 형이 드디어 돈복사 프로그램 만듬 [1] ㅇㅇ(14.5) 10.03 73 0
2893773 이번에 GPT랑 나랑 같은거 코딩해봤는데 지피티가 훨 낫더라. [2] ㅆㅇㅆ(124.216) 10.03 113 3
2893772 힙합 갤러리 10조 갑부 발명도둑잡기(118.235) 10.03 49 0
2893769 ■WSL→도커→이클립스 이렇게쓰는데 쓸데없는짓임? [4] ㅇㅇ갤로그로 이동합니다. 10.03 100 0
2893768 오늘 중국친구가 나보고 재능있대서 기분좋음 [3] ㅆㅇㅆ찡갤로그로 이동합니다. 10.03 92 0
2893764 여러분 ai 코딩 플러그인으로 쓰시나요? [1] ㅇㅇ(106.102) 10.03 63 0
2893761 이번 연휴 달붕이들 꿀팁 푼다 꼭 봐라ㅋㅋㅋㅋ ㅇㅇ(118.235) 10.03 61 0
2893760 AI 로 코딩하기.....ㅋㅋㅋㅋ [1] 프갤러(59.16) 10.03 100 0
2893759 전자담배로 해킹 발명도둑잡기(118.235) 10.03 60 0
2893758 [애니뉴스] 귀인환등초 24화 완결? 프갤러(121.172) 10.03 68 1
2893757 [대한민국] 모스탄, 세계 대전 언급, 고든창 박사, 이재명 차기 독재자 [1] 프갤러(121.172) 10.03 78 0
2893755 전자담배 해킹 [2] 발명도둑잡기(118.235) 10.03 68 0
2893754 취직후 회사 내 노트북 쓰려고 가져가면 "윈도우정품" << 문제됨? [6] 프갤러(180.230) 10.03 98 0
2893753 일회용 전담에 아치 깔아봄 [7] 프갤러(1.250) 10.03 122 2
2893751 내 자신을 회복하는 중이다 ㅇㅇ(121.168) 10.03 67 0
2893750 5시간 반 잤더니 졸리다 발명도둑잡기(118.216) 10.03 52 0
2893749 본인 버킷리스트 [7] 공기역학갤로그로 이동합니다. 10.03 106 0
2893748 지금 갑자기 놀이라는 단어가 매우 안익숙하게 느껴짐 [7] 공기역학갤로그로 이동합니다. 10.03 86 0
2893747 엔젤리너스 바람물질인 검은빨대 사용하는군요 [1] 헬마스터갤로그로 이동합니다. 10.03 64 1
2893746 다시 보는 드럼통의 청와대 ㅇㅇ(121.168) 10.03 63 1
2893745 게임땔깜지망생에서 은퇴한이유 [36] 공기역학갤로그로 이동합니다. 10.03 171 0
2893744 머릿속에 약간 해줘마인드가 들어간거같음 [13] 공기역학갤로그로 이동합니다. 10.03 101 0
2893743 ❤✨☀⭐⚡☘⛩나님 시작합니당⛩☘⚡⭐☀✨❤ ♥덩냥이♥갤로그로 이동합니다. 10.03 58 2
2893742 정부서버 불낸 책임자 극단자했다는군요 [13] 헬마스터갤로그로 이동합니다. 10.03 152 0
2893741 노인개씹버러지새끼들 요즘 100세인생이라고 안해서 좋다 ㅋㅋㅋ [1] 타이밍뒷.통수한방(1.213) 10.03 65 0
2893739 추석 연휴 업소 가는 형들 꿀팁 반값 꿀팁 풀게ㅅㅅㅅ [2] ㅇㅇ(39.7) 10.03 73 1
2893738 좆븅신이 지가 잘난줄 아는 이유 프갤러(210.217) 10.03 73 3
2893737 진짜 개발자가 설명 못하는이유 [1] 프갤러(210.217) 10.03 116 2
2893736 이제 개인용으로 램 64기가정도는 충분히 [18] ㅇㄷ(211.234) 10.03 101 0
2893735 가짜개발자 진짜개발자 구분법 [2] 발명도둑잡기(118.235) 10.03 133 0
2893734 결혼식 갔다왔다 [1] 발명도둑잡기(118.235) 10.03 68 0
2893733 시원하당 ♥냥덩이♥갤로그로 이동합니다. 10.03 54 0
2893731 동생 동영상편집 하고 싶다는데 중고나라에서 30짜리 컴으로 될까?? ㅇㅇ(223.39) 10.03 40 0
2893730 대한민국에 쓰레기들 생각하니까 짱개가 땡기네 프갤러(210.217) 10.03 38 0
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2